4

I'd like to be able to use inline verbatim text with the following features:

  1. Line breaks, as provided for example by package spverbatim, command \spverb;
  2. Colored font, as provide by package color;
  3. Highlighting (text with colored background), like soul's package \hl command.

By "inline" I mean that the verbatim part is within the normal text (not an environment with its own paragraph), and by "verbatim" I mean that special symbols like \, _ etc are not be interpreted by LaTeX.

What I'd like to achieve looks like this (using blue as font color and grey as highlighting color), but it should allow a line break if the verbatim part requires one.

enter image description here

I have tried packages color, newverbs, spverbatim and soul, but I haven't been able to combine all the above features. The closest I've got is:

  • Tweaking spverbatim's definition of spverb to include colored font. That way I get features 1 and 2, but not 3:

    \gdef\myVerb{%
      \bgroup
      \color{fgColor}%
      \let\spverb@ve=\verb@egroup
      \def\verb@egroup{\spverb@ve\egroup}%
      \def\@xobeysp{\mbox{}\space}%
      \verb
    }
    

    Apparently \myVerb defined this way can't be chained with soul's package hl to use \hl{\myVerb{verbatim text}} (LaTeX complains LaTeX Error: \verb illegal in command argument.). Is there any way to combine them? For example, is there something analogous to \hl that can be added after \color{fgColor} in the code above to achieve highlighting?

  • Using the newverbs package to define

    \newverbcommand{\myVerb}
    {\color{fgColor}\begin{lrbox}{\verbbox}}
    {\end{lrbox}\colorbox{bgColor}{\usebox{\verbbox}}}
    

    This produces the font colored in fgColor and the highlighting with bgColor, so I get 2 and 3; but not 1: it doesn't allow line breaks. I guess that's because of lrbox or \colorbox, but I don't know how to modify this to allow line breaks. Is there any way to do it?

  • I can of course use

    \newcommand{\myVerb}[1]{{\ttfamily\color{fgcolor}{\hl{#1}}}}
    

    with hl as per soul package. With this I get 1, 2 and 3 but it's not verbatim, so I have to escape all special characters.

So, is there any way to achieve what I want? Either by solving what's missing in any of the above approaches, or by using a different approach? Perhaps there's a package that supports all the features I want off the shelf?

2 Answers 2

4

While not exactly what the OP asks, it may suffice. First, it uses \detokenize, not verbatim, which means 1) that braces {} must be balanced, 2) that the % symbol is still interpreted as a comment, 3) that a space is inserted after all detokenized macro names, and 4) Hash marks # are doubled in number.

Also, I just \allowbreak between words, using the \fboxsep of the colorbox to create the interword spaces.

EDITED to use \ttfamily for the \mytokens macro.

EDITED to fix line height, since the combination of a \strut and \fboxsep blew the allowed baselineskip budget.

Originally, I was not using interword space but allowed the \fboxsep to suffice. But this caused margin issues, as nothing could stretch. So, upon RE-EDIT, I insert a space of 0pt minus \fboxsep between words, which seems to allow enough compression to address the margin issues, while still leaving enough space between words (otherwise 2\fboxsep).

I also rearranged the \grayspace and allowbreak, upon RE-EDIT, so that a linebreak would not occur before trailing punctuation.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\newcommand\mytokens[1]{\mytokenshelp#1 \relax\relax}
\def\mytokenshelp#1 #2\relax{\allowbreak\grayspace\tokenscolor{#1}\ifx\relax#2\else
 \mytokenshelp#2\relax\fi}
\newcommand\tokenscolor[1]{\colorbox{gray!20}{\textcolor{blue}{%
  \ttfamily\mystrut\smash{\detokenize{#1}}}}}
\def\mystrut{\rule[\dimexpr-\dp\strutbox+\fboxsep]{0pt}{%
 \dimexpr\normalbaselineskip-2\fboxsep}}
\def\grayspace{\hspace{0pt minus \fboxsep}}
\begin{document}
Here is my leading text
\mytokens{Fie Fi Fo Fum, I smell the $#@*& blood of an \Englishman.
I will continue this text to observe the margins. 
Fie Fi Fo Fum, I smell the \textbf{blood} of an Englishman.}
and my trailing text. And here is more text to find where the margin end
really should be.

Standard MATLAB formats are allowed, such as \mytokens{1.2}, \mytokens{-.2i},
\mytokens{1.}, \mytokens{-1.2e3}, \mytokens{+.2E-3j}.  \mytokens{i} and 
\mytokens{j} denote...
\end{document}

enter image description here

SUPPLEMENT

In response to a comment request, here is a version that takes the background color as an optional argument.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\newcommand\mytokens[2][gray!20]{\mytokenshelp{#1}#2 \relax\relax}
\def\mytokenshelp#1#2 #3\relax{\allowbreak\grayspace\tokenscolor[#1]{#2}\ifx\relax#3\else
 \mytokenshelp{#1}#3\relax\fi}
\newcommand\tokenscolor[2][gray!20]{\colorbox{#1}{\textcolor{blue}{%
  \ttfamily\mystrut\smash{\detokenize{#2}}}}}
\def\mystrut{\rule[\dimexpr-\dp\strutbox+\fboxsep]{0pt}{%
 \dimexpr\normalbaselineskip-2\fboxsep}}
\def\grayspace{\hspace{0pt minus \fboxsep}}
\begin{document}
Here is my leading text
\mytokens{Fie Fi Fo Fum, I smell the $#@*& blood of an \Englishman.
I will continue this text to observe the margins. 
Fie Fi Fo Fum, I smell the \textbf{blood} of an Englishman.}
and my trailing text. And here is more text to find where the margin end
really should be.

Standard MATLAB formats are allowed, such as \mytokens{1.2}, 
  \mytokens{-.2i}, \mytokens[red!40]{1.}, \mytokens{-1.2e3}, 
  \mytokens{+.2E-3j}.  \mytokens[cyan!30]{i} and 
  \mytokens[green!20]{j} denote...
\end{document}

enter image description here

9
  • Thanks! This seems to do what I need, except that my verbatim text may contain non-balanced {}. It may also contain \, which produce an extra space if I understood correctly; but that's less of an issue for me
    – Luis Mendo
    Oct 19, 2015 at 15:21
  • Hm, it looks like the # gets duplicated... Do you think my first approach could be modified to include something next to \color{fgColor} to realize the gray background in addition to the colored font?
    – Luis Mendo
    Oct 21, 2015 at 0:07
  • 1
    @LuisMendo I'm glad you found a workaround. If so inclined, you can always post your approach as an answer to your own question. Oct 24, 2015 at 1:09
  • 1
    @3isenHeim Please see the supplement to my answer. Feb 22, 2021 at 17:10
  • 1
    @steven-b-segletes thanks for the edit, I missed the parenthesis that made it work (\mytokenshelp{#1}#2) ! :)
    – 3isenHeim
    Feb 23, 2021 at 8:23
1

As I mentioned in comments to Steven's answer, I ended up writing a Matlab function to transform for example

\myVerb+abc$\+

into

\myVerb{abc\$\textbackslash }

that is, escape characters and use {} as delimiters. That way I can dispose of verbatim and use

\newcommand{\myVerb}[1]{{\ttfamily\color{fgcolor}{\hl{#1}}}}

i.e. the third "solution" in my question. It's not ideal but it works; I only need to run my Matlab function on the tex file to do the transformation before compiling with LaTeX.

This is the Matlab function I use.

function convert_myVerb(fileName)

% Converts \myVerb+...+ or \myVerb|...| into: \myVerb{...} with escaped characters

fid = fopen(fileName);
s = fread(fid);
fclose(fid);
s = char(s.');
ind = regexp(s, '(?<=\\myVerb).');
unique(s(ind)); % characters found after "\myVerb", as a check. I only used + and |
[ini, fin] = regexp(s, '\\myVerb([+|]).*?\1'); % all matching substrings
if isempty(ini)
    disp('Nothing needs to be converted. Converted file not written')
else
    disp([num2str(numel(fin)) ' substrings identified for conversion'])
    y = s(1:ini(1)-1); % output. Initiallize
    % \# \$ \% \& \textbackslash{} \textasciicircum {}\_ \{ \} \textasciitilde{}
    ini(end+1) = numel(s)+1;
    for n = 1:numel(fin)
        t = regexprep(s(ini(n)+6:fin(n)-1), '\\', '\\textbackslash '); % This has
        % to go first, so that it won't convert \ introduced to escape other
        % characters. No {} here, because they would get converted into \{\} later
        t = regexprep(t, '[#$%&_{}]', '\\$0');
        t = regexprep(t, '\^', '\\textasciicircum{}');
        t = regexprep(t, '~', '\\textasciitilde{}');
        t = ['\myVerb{' t '}'];
        y = [y t s(fin(n)+1:ini(n+1)-1)];
    end
    fid = fopen(fileName, 'w');
    count = fwrite(fid, y);
    fclose(fid);
    if count
        disp('Converted file successfully written')
    end
end

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .