展开列表内的宏并应用语法高亮

展开列表内的宏并应用语法高亮

我想知道是否有一种方法可以在lstlisting环境内扩展宏,并自动将语法突出显示应用于扩展的文本。

例如,

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}

\lstset{
    basicstyle=\ttfamily,
    keywordstyle=\color{blue},
    keywords={function},
    escapeinside={|}{|}
}
\def\fbar{function bar ();}

\begin{document}
\begin{lstlisting}[]
function foo ();
|\fbar|
\end{lstlisting}
\end{document}

应该产生这样的输出:

在此处输入图片描述

答案1

现在有啦! 我现在也讨厌列表:)

嗯,有点儿像。继续阅读你就会明白。

首先,escapechar=<char>令我们失望的是,该选项只是 的简写escapeinside=<char><char>。在我看来,它没什么用。文档和资料没有指出除此以外的任何内容。

我实现了一个cschar=<char>选项,它将使用<char>作为转义符(在 TeX 中,而不是listings' 的意思)。我从listings'中回收了一些代码escapeinside并让它开始一个\lst@scan@csname事情。这个扫描器尽可能多地抓取a-zA-Z\m@cr@s不允许)之间的字符并从中构建一个控制序列,或者它抓取一个非字母字符并构建一个控制字符。然后扩展构建的控制序列/字符(一次)并使用expl3's重新标记\tl_rescan:nn(我没有耐心复制它的定义)并重新插入到标记流中以listings执行其操作。如果扩展的控制序列恰好有另一个控制序列,则它稍后也会扩展,并以递归方式工作。

请注意,这是一个仿真TeX 构建控制序列的方式,因此它有一些不值得检查的错误\fbar hello功能。例如,将打印function bar(); hello,中间有一个空格,而 TeX 会扩展为function bar();hello。这使得您无法获得,例如function bar();hello因为\fbarhello将被解释为一个(未定义的)控制序列。您需要定义一个控制序列\def\hello{hello}并使用\fbar\hello

代码如下:

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{expl3}

\makeatletter
\gdef\lst@CSEscape#1{%
    \lst@CArgX #1\relax\lst@CDefX
        {}%
        {\lst@ifdropinput\else
         \lst@TrackNewLines\lst@OutputLostSpace \lst@XPrintToken
         \lst@InterruptModes
         \lst@EnterMode{\lst@TeXmode}{\lst@modetrue}%
         \let\do\@makeother\dospecials
         \let\lst@grabbed@csname\@empty
         \expandafter\lst@scan@csname%
         \fi}%
        {}}
\lst@Key{cschar}{}
    {\ifx\@empty#1\@empty
       \let\lst@CSChar\relax
     \else
       \def\lst@CSChar{\lst@CSEscape{#1}}%
     \fi}
\let\lst@explicit@space=\ %
\lst@AddToHook{SelectCharTable}{\lst@CSChar}
\def\lst@afterfi#1#2\fi{\fi#1}
\def\lst@scan@csname#1{%
  \if\relax\detokenize{#1}\relax
    \lst@afterfi{\lst@dispatch@csname{#1}}%
  \else
    \lst@afterfi{%
      \uppercase{\def\lst@tmpa{#1}}%
      \expandafter\lst@scan@csname@\expandafter
        {\number\expandafter`\lst@tmpa}{#1}}%
  \fi}
\def\lst@scan@csname@#1#2{%
  \ifnum %      vv If you want to \maketatletter :)
    % \ifnum0#1>63 \expandafter0\else\expandafter1\fi
      \ifnum0#1>64 \expandafter0\else\expandafter1\fi
      \ifnum0#1<91 \expandafter0\else\expandafter1\fi
        =0
    \edef\lst@grabbed@csname{\lst@grabbed@csname\string#2}%
    \expandafter\lst@scan@csname
  \else
    \lst@afterfi{\lst@dispatch@csname{#2}}%
  \fi}
\def\lst@dispatch@csname#1{%
  \ifx\lst@grabbed@csname\@empty
    \if\detokenize{#1}\lst@char@space
      \lst@afterfi{\lst@afterfi{\lst@return@from@csname@{}{#1}}}%
    \else
      \lst@afterfi{\lst@afterfi{\lst@dispatch@csname@{\string#1}}}%
    \fi
  \else
    \lst@afterfi{\expandafter\lst@dispatch@csname@\expandafter{\lst@grabbed@csname}{#1}}%
  \fi}
\def\lst@dispatch@csname@#1{%
  \@ifundefined{#1}%
    {\PackageError{Listings}{! Undefined control sequence \@backslashchar#1}}%
    {\expandafter\lst@return@from@csname\csname#1\endcsname}}
\def\lst@return@from@csname#1{%
  \ifx#1\lst@explicit@space
    \lst@afterfi{\lst@return@from@csname@{}{}}%
  \else
    \lst@afterfi{\expandafter\lst@return@from@csname@\expandafter{#1}}%
  \fi}
\def\lst@return@from@csname@#1#2{%
  \lst@escapeend \lst@LeaveAllModes\lst@ReenterModes
  \lst@newlines\z@ \lst@whitespacefalse
  \lst@csescape@output{#1}{#2}}
\def\if@single@item#1{%
  \if\relax\detokenize\expandafter{\@gobble#1}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondofone
  \fi}
\def\lst@active@space{\lst@ProcessSpace}
\begingroup
\catcode`\|=0
\catcode`\[=1
\catcode`\]=2
\let\do\@makeother\dospecials
[|global|let|lst@char@space= ]
|endgroup
\def\lst@csescape@output#1#2{%
  \if@single@item{#2}%
    {%
      \ifnum
        \ifx\lst@active@space#2\expandafter1\else\expandafter0\fi
        \ifx\lst@char@space#2\expandafter1\else\expandafter0\fi
        >0
        \def\lst@aftertokens{\safescantokens{#1}\lst@ProcessSpace}%
      \else
        \def\lst@aftertokens{\safescantokens{#1#2}}%
      \fi
    }{%
      \def\lst@aftertokens{\safescantokens{#1#2}}%
    }%
  \lst@aftertokens
}
\makeatother
\ExplSyntaxOn
\cs_new_protected:Npn \safescantokens #1 { \tl_rescan:nn {} {#1}}
\ExplSyntaxOff
\begin{document}
\lstset{
    basicstyle=\ttfamily,
    keywordstyle=\color{blue},
    keywords={function},
    cschar=\\,
}

\def\fbar{function bar ();}
\def\fuba{cat fuba ();}
\def\1{function first ();}

\begin{lstlisting}[]
function foo ();@12\ 3
\fbar\1{}@12\ 3
\fbar\fuba@12\ 3
\end{lstlisting}

\begin{lstlisting}[]
function foo (); @12\ 3
\fbar{} @12\ 3
\fbar @12\ 3
\fbar\ @12\ 3
\end{lstlisting}

\lstset{cschar=|}

\begin{lstlisting}[]
function foo ();@12\ 3
|fbar{}@12\ 3
|fbar@12\ 3
\end{lstlisting}

\begin{lstlisting}[]
function foo (); @12\ 3
|fbar{} @12\ 3
|fbar @12\ 3
|fbar\ @12\ 3
\end{lstlisting}

\end{document}

输出:

在此处输入图片描述

我会小心使用它。这种代码让人不太放心。

PS:如果您想让代码将更多字符识别为“字母”,则必须更改条件:

  \ifnum %      vv If you want to \maketatletter :)
    % \ifnum0#1>63 \expandafter0\else\expandafter1\fi
      \ifnum0#1>64 \expandafter0\else\expandafter1\fi
      \ifnum0#1<91 \expandafter0\else\expandafter1\fi
        =0

例如,将第一个改为6463使其@成为字母。

答案2

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}

\lstset{
    basicstyle=\ttfamily,
    keywordstyle=\color{blue},
    keywords={function},
    escapeinside={|}{|}
}
\def\fbar{function bar ();}

\begin{document}
\begin{lstlisting}[]
function foo ();
|\bgroup\endlinechar=-1 \scantokens\expandafter{\expandafter\egroup\expandafter|\fbar}
function baz ();
\end{lstlisting}
\end{document}

在此处输入图片描述


\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}

\lstset{
    basicstyle=\ttfamily,
    keywordstyle=\color{blue},
    keywords={function},
    escapeinside={|}{|}
}
\begingroup
\catcode`\^^M=12 %
\csname@firstofone\endcsname{%
  \endgroup%
  \def\fbar{%
    function bar ();
    function baz ();%
  }%
}%
%

\begin{document}
\begin{lstlisting}[]
function foo ();
|\bgroup\endlinechar=-1 \scantokens\expandafter{\expandafter\egroup\expandafter|\fbar} Something in the same line as baz;
function bat ();
\end{lstlisting}
\end{document}

在此处输入图片描述

相关内容