5

Why doesn't upquote work with tabularx?

\documentclass{article}
\usepackage{upquote}
\usepackage{tabularx}

\begin{document}
This works:

\begin{tabular}{c}
  Inline \verb|`code`| \\   
\end{tabular}

This doesn't work:

\begin{tabularx}{\linewidth}{X}
  Inline \verb|`code`| \\   
\end{tabularx}
\end{document}

enter image description here

I have also the warning:

\verb may be unreliable inside tabularx

For my actual case, I solved using \textasciigrave from textcomp package. Is there a quicker method?

  • In the case of this example \verb does not include any special character, so you could just use \texttt instead which does not have this issue. – Henri Menke Aug 28 '18 at 4:18
  • @HenriMenke With \texttt{...} the backticks are not backticks... – CarLaTeX Aug 28 '18 at 4:38
  • Indeed, I was typesetting the file with LuaLaTeX where this problem doesn't occur at all (no need for upquote in the first place). One more reason to switch to LuaTeX :) – Henri Menke Aug 28 '18 at 5:15
3

As Henri Menke mentions in his answer, tabularx scans the whole body of the tabularx environment and thus fixes catcodes. \verb, on the other hand, relies on changeable catcodes to work properly. As a workaround tabularx provides a version of \verb that works in simple cases but has several flaws (see documentation for the full list), hence the warning you get.

The upquote package changes an internal \verb macro that makes ' and ` active and let them expand to their respective glyph representations. As mentioned, catcode changes are not available with tabularx, but we can still extend the \verb alternative it provides:

\documentclass{article}
\usepackage{upquote}
\usepackage{tabularx}

\makeatletter

\let\@upquote@quote=\textquotesingle
\let\@upquote@grave=\textasciigrave
\ifx\encodingdefault\upquote@OTone
  \ifx\ttdefault\upquote@cmtt
    \def\@upquote@quote{\char13 }
    \def\@upquote@grave{\char18 }
  \fi
\fi

\def\@upquote@repl#1{%
  \if\relax\detokenize{#1}\relax\else\@upquote@repl@#1\@end\fi
}
\def\@upquote@repl@#1#2\@end{%
  \if#1`\@upquote@grave\else
    \if#1'\@upquote@quote\else#1\fi
  \fi
  \if\relax\detokenize{#2}\relax\else\@upquote@repl@#2\@end\fi
}

\begingroup
\catcode`\*=\catcode`\#
\catcode`\#=12
\gdef\TX@vfirst{%
  \if\@tempa#%
    \def\@tempb{\TX@v@#}%
  \else
    \let\@tempb\TX@v@
    \if\@tempa\space~\else
      \expandafter\@upquote@repl\expandafter{\@tempa}%
    \fi
  \fi
  \@tempb
}

\gdef\TX@v@hash*1##*2{%
  \@upquote@repl{*1}%
  \ifx*2\relax\else#\expandafter\TX@v@hash\fi*2%
}
\endgroup

\makeatother

\begin{document}
This works:

\begin{tabular}{c}
  Inline \verb|`code`| \\
\end{tabular}

This works now, too:

\begin{tabularx}{\linewidth}{X}
  Inline \verb|`code`| \\
\end{tabularx}
\end{document}

First, we set up \@upquote@quote and \@upquote@grave to map to the upright glyphs of ' and `, respectively. Next comes the definition of a helper macro \@upquote@repl that replaces each occurence of ' and ` in its argument text by the corresponding glyphs.

Now we can adjust \verbs internal helper macros at the right places to apply \upquote@repl before the final output is printed. Turns out that we need to change \TX@vfirst, which has some special treatment for the first verbatim character, and \TX@v@hash, which processes the rest of the text. The result is as expected:

enter image description here

5

tabularx collects its body as an argument and therefore tokenizes the input. This breaks verbatim material, similar to why \section{\verb|`code`|} will not work. The only possibility to forward verbatim material into floating arguments is by saving it in a box first. In the case of tabularx you will also have to \copy rather than \box because of the multi-pass nature of the algorithm.

\documentclass{article}
\pagestyle{empty}
\usepackage{upquote}
\usepackage{tabularx}

\begin{document}
This works:

\begin{tabular}{c}
  Inline \verb|`code`| \\   
\end{tabular}

This doesn't work:

\setbox0=\hbox{\verb|`code`|}
\begin{tabularx}{\linewidth}{X}
  Inline \copy0 \\   
\end{tabularx}
\end{document}

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.