我必须在整个文档中显示大量自动生成的代码。
生成的代码表示具有显式块标签和goto
s 的循环。以下代码将函数f
应用于数组的每个元素,从而产生一个新数组(即ys = map f xs
):
\documentclass{article}
\usepackage{listings}
\begin{document}
\begin{lstlisting}
init_2:
i_1 = 0
arr_2 = newArray (length arr_1)
goto guard_2
guard_2:
guard i_1 < length arr_1 | done_2
goto body_2
body_2:
elt_1 = readArray arr_1 i_1
elt_2 = f_2 elt_1
writeArray arr_2 i_1
i_1 := i_1 + 1
goto guard_2
done_2:
return arr_2
\end{lstlisting}
\end{document}
到处都看到下划线和整数后缀,可读性很差。我更喜欢下面这样:
\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\begin{document}
\begin{lstlisting}[mathescape=true, basicstyle=\ttfamily]
$\color{red}{init_{ys}}$:
i$_{xs}$ = 0
arr$_{ys}$ = newArray (length arr$_{xs}$)
goto $\color{red}{guard_{ys}}$
\end{lstlisting}
\end{document}
但是,这需要对每个列表进行繁琐的格式化。我想知道是否有更自动化的解决方案?
我的问题是是否可以在列表中执行以下一项或多项操作:
自动为下划线后的符号部分添加下标(下面我有部分解决方案)
自动替换
_1
为_xs
和_2
_ys
自动标记匹配的字符串,例如制作标签
init_1
、guard_2
粗体
如果它能让我更轻松地排版代码,我不介意使用不同的列表包。
我已经在以下帮助下部分解决了问题 1这答案但它只适用于常规文本,而不是列表代码:
\documentclass{article}
\usepackage{listings}
\usepackage{fixltx2e}
%% Automatically make code after underscore subscripted
\def\SubscriptWord#1 {\check#1\relax\textsubscript{#1} }
% Check function parses world until space/newline
\def\check#1{%
\ifx\relax#1%
\else
\ifcat a#1%
\else
\typeout{illegal character #1}%
\fi
\expandafter\check
\fi}
\begin{document}
\catcode`\_=\active
\def_{\SubscriptWord}
normal_foo
\begin{lstlisting}
listing_bar
\end{lstlisting}
\end{document}
答案1
- 自动为下划线后的符号部分添加下标
但这可能会导致问题;特别是如果标识符包含下划线怎么办?
- 自动替换
_1
为_xs
和_2
_ys
我认为霍斯特绝对是正确的。虽然我不是它的忠实粉丝,但literate
在这里,这个关键点还是可以得到很好的利用的。
- 自动标记匹配的字符串,例如使标签 init_1、guard_2 变为粗体。
您的意思是“转到标签”?使用“转到标签”自动突出显示这些标签listings
是一个更难解决的问题。接下来的内容更像是一种美化的黑客行为,而不是真正的解决方案,但看看它是否适合您。
解决方案细分
程序包加载
除了你需要这个fixltx2e
包(因为它定义了\textsubscript
宏)之外,这里没有什么有趣的东西。
\usepackage{fixltx2e}
\usepackage{listings}
\usepackage{xcolor}
样式定义
\colorlet{gotolabel}{red}
\newcommand\lstsubstyle{\itshape\rmfamily}
\newcommand\gotolabelstyle{\itshape\rmfamily\color{gotolabel}}
列表设置
我们columns=flexible
在这里使用 而不是默认的columns=fixed
;否则,输出看起来会很丑陋。我们定义一个以 开头的单行分隔符goto␣
。最后,我们为下标、两个连续空格和冒号字符定义一些文字替换。
\lstset{
basicstyle=\ttfamily\upshape\color{black},
columns=fullflexible,
moredelim=**[il][\processgoto]{goto\ },
moredelim=**[il][\processpipe]{\ |\ },
literate={_1}{{\lstsub{xs}}}1
{_2}{{\lstsub{ys}}}1
{\ \ }{\processtwospaces}2
{:}{\processcolon}1,
}
转变
以下开关将用作状态变量,并告诉我们何时激活/停用某些样式。
\newif\ifgotolabel
EveryPar
钩
在每个“true”行的开头,我们应用 GoTo 标签的样式并将开关设置为 true。
\makeatletter
\lst@AddToHook{EveryPar}{%
\let\lst@thestyle\gotolabelstyle%
\global\gotolabeltrue%
}
辅助宏
moredelim
在这里,我们定义传递给和键的值所使用的宏literate
。
每次goto␣
遇到时,我们都会正常打印它,但我们会触发与 GoTo 标签相关的样式;无需设置开关(它已经在当前行的开头设置了)。
\newcommand\processgoto{%
\lst@CalcLostSpaceAndOutput%
{\lst@basicstyle goto\ }\gotolabelstyle%
}
每次出现的情况都是同样的想法␣|␣
:
\newcommand\processpipe{%
\lst@CalcLostSpaceAndOutput%
{\lst@basicstyle\ |\ }\gotolabelstyle%
}
以下宏以相应的样式排版下标,并且仅当设置了开关时才应用 GoTo 标签的颜色。
\newcommand\lstsub[1]{%
\textsubscript{%
\ifgotolabel%
\color{gotolabel}%
\fi
\lstsubstyle #1%
}%
}
以下宏保持“处理模式”中出现的两个连续空格不变,但重新激活基本样式并取消设置开关。具体来说,它会在缩进两个空格的每一行开头调用。
\newcommand\processtwospaces{%
\ifnum\lst@mode=\lst@Pmode%
\lst@basicstyle%
\global\gotolabelfalse%
\fi
\ \ %
}
这里的想法相同,但是针对的是冒号字符。
\newcommand\processcolon{%
\ifnum\lst@mode=\lst@Pmode%
\lst@basicstyle%
\global\gotolabelfalse%
\fi
:%
}
\makeatother
完整代码
\documentclass{article}
\usepackage{fixltx2e}
\usepackage{listings}
\usepackage{xcolor}
% Define styles for GoTo labels and subscripts
\colorlet{gotolabel}{red}
\newcommand\lstsubstyle{\itshape\rmfamily}
\newcommand\gotolabelstyle{\itshape\rmfamily\color{gotolabel}}
%
\lstset{
basicstyle=\ttfamily\upshape\color{black},
columns=fullflexible,
moredelim=**[il][\processgoto]{goto\ },
moredelim=**[il][\processpipe]{\ |\ },
literate={_1}{{\lstsub{xs}}}1
{_2}{{\lstsub{ys}}}1
{\ \ }{\processtwospaces}2
{:}{\processcolon}1,
}
\newif\ifgotolabel
\makeatletter
\lst@AddToHook{EveryPar}{%
\let\lst@thestyle\gotolabelstyle%
\global\gotolabeltrue%
}
\newcommand\processgoto{%
\lst@CalcLostSpaceAndOutput%
{\lst@basicstyle goto\ }\gotolabelstyle%
}
\newcommand\processpipe{%
\lst@CalcLostSpaceAndOutput%
{\lst@basicstyle\ |\ }\gotolabelstyle%
}
\newcommand\lstsub[1]{%
\textsubscript{%
\ifgotolabel%
\color{gotolabel}%
\fi
\lstsubstyle #1%
}%
}
\newcommand\processtwospaces{%
\ifnum\lst@mode=\lst@Pmode%
\lst@basicstyle%
\global\gotolabelfalse%
\fi
\ \ %
}
\newcommand\processcolon{%
\ifnum\lst@mode=\lst@Pmode%
\lst@basicstyle%
\global\gotolabelfalse%
\fi
:%
}
\makeatother
\begin{document}
\begin{lstlisting}
init_2:
i_1 = 0
arr_2 = newArray (length arr_1)
goto guard_2
guard_2:
guard i_1 < length arr_1 | done_2
goto body_2
body_2:
elt_1 = readArray arr_1 i_1
elt_2 = f_2 elt_1
writeArray arr_2 i_1
i_1 := i_1 + 1
goto guard_2
done_2:
return arr_2
\end{lstlisting}
\end{document}
答案2
如果您使用\lstset
,则可以选择用literate
latex 标记或替换下划线(应该回答问题 1 和问题 2)。并使用加粗关键字(如果我明白你的意思)。你可以尝试类似_1
_xs
keywordstyle
\lstset{%
keywordstyle=\bfseries
literate=*{_}{\_}1
{_1}{\_{xs}}2
{_2}{\_{ys}}2
}
文学编程非常注重正确的括号,所以我的例子可能行不通。请参阅 5.4 文学编程http://texdoc.net/texmf-dist/doc/latex/listings/listings.pdf并尝试找到正确的方法。这个论坛也有很多关于它的内容。(它有一个关于括号的错误,请参阅https://tex.stackexchange.com/a/149203)