2

I have argument #1 which contains some text X representing some label. I would like to use \str_if_eq to compare X and name of paragraph referenced by this string. What I want to achieve is that if \label{X} is under some \paragraph[shortname_different_from_X]{Long description}, I want to include \nameref{X}, so that reader would see shortname_different_from_X, so that it would be possible to find what I'm talking about also in printed version. (Assume knowing shortname_different_from_X is enough to find correct paragraph in printed version.)

Here is my code:

\cs_new_protected:Nn \mynode_print:N
 {
  \texttt
   {
    \tl_if_empty:NTF #1
      { - }
      { \hyperref[\tl_to_str:N #1] { \tl_to_str:N #1} % this is here only to show name of label and make it so that reader can click on it and go to label
      \str_if_eq:nnTF{\tl_to_str:N #1}{ \nameref{\tl_to_str:N #1} }{}{ ~(see~\nameref{\tl_to_str:N #1}) } } % second argument should be changed so that it contains name of referenced paragraph
   };~
 }

In provided code, comparison returns always false, because using \nameref{\tl_to_str:N #1} in second argument of str_if_eq is wrong, it's not a string.

For completeness, here is usage example, I don't want see n_1, see n_2, see n_3 visible, only see missing_nodes should be visible:

\documentclass[12pt, oneside]{book}
\usepackage[a4paper,top=2.5cm,bottom=2.5cm,left=3.5cm,right=2cm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage[IL2]{fontenc}
\usepackage{graphicx}
\usepackage{url}
\DeclareUrlCommand\url{\def\UrlLeft{<}\def\UrlRight{>} \urlstyle{tt}}
\usepackage[hidelinks,breaklinks]{hyperref}
\usepackage[slovak]{babel}
\usepackage{blindtext}
\usepackage{xcolor}
\usepackage{fancyvrb}
\usepackage{listings}
\usepackage{subcaption}
\usepackage{tikz}
\usepackage{dot2texi}
\usepackage{nameref}
\usepackage{xparse}
\usepackage{xstring}
\usepackage{ifthen}
\usetikzlibrary{snakes,arrows,shapes}
\linespread{1.25}
\setlength{\emergencystretch}{30pt}

\ExplSyntaxOn
\NewDocumentCommand\mynode{mmmm}
 {
  \mynode_main:nnnn { #1 } { #2 } { #3 } { #4 }
 }

\seq_new:N \l_mynode_input_seq
\seq_new:N \l_mynode_output_seq
\tl_new:N \l_mynode_node_tl
\tl_new:N \l_mynode_text_tl

\cs_new_protected:Nn \mynode_main:nnnn
 {
  \seq_set_split:Nnn \l_mynode_input_seq { ; } { #3 }
  \seq_set_split:Nnn \l_mynode_output_seq { ; } { #4 }
  \tl_set:Nn \l_mynode_node_tl { #1 }
  \mynode_replace:N \l_mynode_node_tl
  \tl_set:Nn \l_mynode_text_tl { #2 }
  \mynode_replace:N \l_mynode_text_tl

  \mynode_paragraph:VV \l_mynode_node_tl \l_mynode_text_tl
  \label{ \tl_to_str:n { #1 } }

  \begin{itemize}
    \item in:~
    \seq_map_variable:NNn \l_mynode_input_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
    \item out:~
    \seq_map_variable:NNn \l_mynode_output_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
  \end{itemize}
 }

\cs_new_protected:Nn \mynode_paragraph:nn
 {
  \paragraph[#1]{#2~(\texttt{#1}):}
 }
\cs_generate_variant:Nn \mynode_paragraph:nn { VV }

\cs_new_protected:Nn \mynode_print:N
 {
  \texttt
   {
    \tl_if_empty:NTF #1
      { - }
      { \hyperref[\tl_to_str:N #1] { \tl_to_str:N #1}
      \str_if_eq:nnTF{\tl_to_str:N #1}{ \nameref{\tl_to_str:N #1} }{}{ ~(see~\nameref{\tl_to_str:N #1}) } }
   };~
 }

\cs_new_protected:Nn \mynode_replace:N
 {
  \regex_replace_all:nnN { \_ } { \c{_} } #1
  \regex_replace_all:nnN { \< } { \c{textless} } #1
  \regex_replace_all:nnN { \> } { \c{textgreater} } #1
 }

\NewDocumentCommand{\change}{m}
 {
  \tl_set:Nn \l_mynode_text_tl { #1 }
  \mynode_replace:N \l_mynode_text_tl
  \tl_use:N \l_mynode_text_tl
\tl_show_analysis:N #1
 }
\ExplSyntaxOff


\begin{document}     
\mynode{n_1}{node 1}{}{n_2;n_3}
\mynode{n_2}{node 2}{n_1}{n_4}
\mynode{n_3}{node 3}{n_1}{}
\paragraph[missing\_nodes]{Nodes that are not present}
Some text describing why nodes are missing.
\label{n_4}
\label{n_5}
% ...

\end{document}
  • 1
    Can you please make your code compilable with an example usage? – Phelype Oleinik Apr 23 at 16:31
  • I added example code. There may be some unused \usepackage commands, I took it from long document. I can try to shorten it more if it's needed. – user224348 Apr 23 at 18:45
2

There you go!

The first problem was that you were using \str_if_eq:nn instead of \str_if_eq:ee. The former, when you pass an argument like \tl_to_str:N #1 will compare the literal text “\tl_to_str:N#1” (with the proper replacement of #1 by the actual argument), and will not expand \tl_to_str:N. But once you change that, then \nameref will explode because it's not expandable. I loaded the refcount package and used \getrefbykeydefault, which is expandable. And the final problem was that you were doing the substitution of _ by \_ too early, and then the label would be saved as n\_1 but would compare against n_1. I moved the \mynode_replace:N before the actual typesetting, which is where you will need the replacement.

I removed the unused packages for the example. Note that hyperref should be the very last package to be loaded, except for very few exceptions (lovely sentence, this one :).

On June 2018 the \str_if_eq_x:nn function was renamed to \str_if_eq:eeTF, so if you have an older expl3 it won't work. I added a check for that so that the code will use which one is available.

Here's the output:

enter image description here

and the code:

\documentclass[12pt, oneside]{book}
\usepackage{xparse}
\usepackage{refcount}
\usepackage[hidelinks,breaklinks]{hyperref}

\ExplSyntaxOn
\NewDocumentCommand\mynode{mmmm}
 {
   \mynode_main:nnnn { #1 } { #2 } { #3 } { #4 }
 }

\seq_new:N \l_mynode_input_seq
\seq_new:N \l_mynode_output_seq
\tl_new:N \l_mynode_node_tl
\tl_new:N \l_mynode_text_tl

\cs_new_protected:Nn \mynode_main:nnnn
 {
  \seq_set_split:Nnn \l_mynode_input_seq { ; } { #3 }
  \seq_set_split:Nnn \l_mynode_output_seq { ; } { #4 }
  \tl_set:Nn \l_mynode_node_tl { #1 }
  \tl_set:Nn \l_mynode_text_tl { #2 }

  \mynode_paragraph:VV \l_mynode_node_tl \l_mynode_text_tl
  \label{ \tl_to_str:n { #1 } }

  \begin{itemize}
    \item in:~
    \seq_map_variable:NNn \l_mynode_input_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
    \item out:~
    \seq_map_variable:NNn \l_mynode_output_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
  \end{itemize}
 }

\cs_new_protected:Nn \mynode_paragraph:nn
 {
   \tl_set:Nn \l_tmpa_tl {#1}
   \mynode_replace:N \l_tmpa_tl
   \paragraph[#1]{#2~(\texttt{\l_tmpa_tl}):}
 }
\cs_generate_variant:Nn \mynode_paragraph:nn { VV }

\cs_new_protected:Nn \mynode_print:N
 {
  \texttt
   {
    \tl_if_empty:NTF #1
      { - }
      {
        \tl_set:Nx #1 { \tl_to_str:N #1 } % To avoid repetition
        \hyperref [#1] {#1}
        \cs_if_exist_use:NF \str_if_eq:eeTF \str_if_eq_x:nnTF
        % \str_if_eq:eeTF
            {#1}
            { \getrefbykeydefault {#1} { name } { squirdshlicker~:) } }
          {}
          { ~(see~\nameref{#1}) }
      }
   };~
 }

\cs_new_protected:Nn \mynode_replace:N
 {
  \regex_replace_all:nnN { \_ } { \c{_} } #1
  \regex_replace_all:nnN { \< } { \c{textless} } #1
  \regex_replace_all:nnN { \> } { \c{textgreater} } #1
 }

\NewDocumentCommand{\change}{m}
 {
  \tl_set:Nn \l_mynode_text_tl { #1 }
  \mynode_replace:N \l_mynode_text_tl
  \tl_use:N \l_mynode_text_tl
\tl_show_analysis:N #1
 }
\ExplSyntaxOff

\begin{document}
\mynode{n_1}{node 1}{}{n_2;n_3}
\mynode{n_2}{node 2}{n_1}{n_4}
\mynode{n_3}{node 3}{n_1}{}
\paragraph[missing\_nodes]{Nodes that are not present}
Some text describing why nodes are missing.
\label{n_4}
\label{n_5}

\end{document}

On your second request. Yes, it is possible, but not recommended. I made a macro to do that, but please notice that the :D argument specification means “Do not use”!

There is one major issue that makes this a weird thing: the material in the optional argument of \paragraph (or any other sectioning command, for that matter) is supposed to be typesettable material, so you should escape the _.

I used the least awkward approach to do this: I make a copy of the label into a temporary macro, then I apply \mynode_replace:N to said label, and then call \nameref to do its thing with the now escaped label. Finally I restore the label to its original value.

Full code (the output is the same):

\documentclass[12pt, oneside]{book}
\usepackage{xparse}
\usepackage{refcount}
\usepackage[hidelinks,breaklinks]{hyperref}

\ExplSyntaxOn
\NewDocumentCommand\mynode{mmmm}
 {
   \mynode_main:nnnn { #1 } { #2 } { #3 } { #4 }
 }

\seq_new:N \l_mynode_input_seq
\seq_new:N \l_mynode_output_seq
\tl_new:N \l_mynode_node_tl
\tl_new:N \l_mynode_text_tl

\cs_new_protected:Nn \mynode_main:nnnn
 {
  \seq_set_split:Nnn \l_mynode_input_seq { ; } { #3 }
  \seq_set_split:Nnn \l_mynode_output_seq { ; } { #4 }
  \tl_set:Nn \l_mynode_node_tl { #1 }
  \tl_set:Nn \l_mynode_text_tl { #2 }

  \mynode_paragraph:VV \l_mynode_node_tl \l_mynode_text_tl
  \label{ \tl_to_str:n { #1 } }

  \begin{itemize}
    \item in:~
    \seq_map_variable:NNn \l_mynode_input_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
    \item out:~
    \seq_map_variable:NNn \l_mynode_output_seq \l_mynode_node_tl
     {
      \mynode_print:N \l_mynode_node_tl
     }
  \end{itemize}
 }

\cs_new_protected:Nn \mynode_paragraph:nn
 {
   \tl_set:Nn \l_tmpa_tl {#1}
   \mynode_replace:N \l_tmpa_tl
   \paragraph[#1]{#2~(\texttt{\l_tmpa_tl}):}
 }
\cs_generate_variant:Nn \mynode_paragraph:nn { VV }

\cs_new_protected:Nn \mynode_print:N
 {
  \texttt
   {
    \tl_if_empty:NTF #1
      { - }
      {
        \tl_set:Nx #1 { \tl_to_str:N #1 } % To avoid repetition
        \hyperref [#1] {#1}
        \cs_if_exist_use:NF \str_if_eq:eeTF \str_if_eq_x:nnTF
        % \str_if_eq:eeTF
            {#1}
            { \getrefbykeydefault {#1} { name } { squirdshlicker~:) } }
          {}
          {
            \exp_args:NV
            \__mynode_label_bodge:D #1 { ~(see~\nameref{#1}) }
          }
      }
   };~
 }

\cs_new_protected:Npn \__mynode_label_bodge:D #1 #2
  {
    \cs_set_eq:Nc \__mynode_tmpa: { r@#1 }
    \exp_args:Nc
    \mynode_replace:N { r@#1 }
    #2
    \cs_set_eq:cN { r@#1 } \__mynode_tmpa:
  }

\cs_new_protected:Nn \mynode_replace:N
 {
  \regex_replace_all:nnN { \_ } { \c{_} } #1
  \regex_replace_all:nnN { \< } { \c{textless} } #1
  \regex_replace_all:nnN { \> } { \c{textgreater} } #1
 }

\NewDocumentCommand{\change}{m}
 {
  \tl_set:Nn \l_mynode_text_tl { #1 }
  \mynode_replace:N \l_mynode_text_tl
  \tl_use:N \l_mynode_text_tl
\tl_show_analysis:N #1
 }
\ExplSyntaxOff

\begin{document}
\mynode{n_1}{node 1}{}{n_2;n_3}
\mynode{n_2}{node 2}{n_1}{n_4}
\mynode{n_3}{node 3}{n_1}{}
\paragraph[missing_nodes]{Nodes that are not present}
Some text describing why nodes are missing.
\label{n_4}
\label{n_5}

\end{document}
  • @user224348 It looks like you have an older expl3 which doesn't have \str_if_eq:eeTF (added on June 2018) and you are probably getting a bunch of compilation errors. I added a version which should work with your version of expl3. – Phelype Oleinik Apr 23 at 23:26
  • Can I have one more question to this code? In \mynode_paragraph:nn I used that trick with temp variable also on #2 so that it would be escaped too. Can I use something similar if I didn't escape missing\_nodes? I have realized that it would maybe make more sense to not escape it if everything else is not escaped (for example I could use mynode and paragraph interchangeably). – user224348 Apr 24 at 18:08
  • @user224348 I added a variant. However I think you should escape the underscore there because it is supposed to be typesettable material. If you want you can create a dedicated macro which handles that in a less awkward way :-) – Phelype Oleinik Apr 25 at 1:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.