我正在尝试自定义列表样式,以便自动突出显示我的代码,使其与 Eclipse/PyDev 安装完全相同(或足够接近)。我希望能够使用“class”和“:”作为分隔符集,这样“class”和“:”之间的任何内容都将以某种方式格式化。具体来说,我希望“class”具有“关键字”颜色,“class”和“:”之间的所有内容都是“classc”颜色或从其他定义继承其格式(“Base”应为“classc”颜色,“(object)”应为“code”颜色)。
我尝试通过实现一个宏来实现这一点,该宏重新格式化分隔符之间的文本,同时以不同的格式重新打印分隔符。
给出的输出的第一行几乎完全符合我的要求,只是出于某种原因,“:”出现在 Base 和 (object) 之间,而不是 (object) 之后。也就是说,颜色是正确的,但该行应该是“class Base(object):”。
第二行输出的缩进似乎导致了另一个问题。同样,这里的颜色基本正确,但我希望输出为“def new_function(self):”。从技术上讲,我也希望“self”具有“关键字”颜色,但我认为那是另一个问题。
\documentclass{article}
\usepackage{listings, color}
\definecolor{keyword}{RGB}{221,40,103}
\definecolor{classc}{RGB}{18,144,195}
\definecolor{code}{RGB}{217,232,247}
\definecolor{bg}{RGB}{35,35,35}
\definecolor{function}{RGB}{167,236,33}
\newcommand{\classHighlight}[1]{{\ttfamily\color{keyword}class\ }{\bfseries\color{classc}#1}{:}}
\newcommand{\functionHighlight}[1]{{\ttfamily\color{keyword}def\ }{\bfseries\color{function}#1}{:}}
\lstdefinestyle{myPython}{
language = Python,
basicstyle = \color{code}\ttfamily,
morekeywords=[1]{self,None,True,False,class,def},
moredelim={*[is][\classHighlight]{class\ }{:}},
moredelim={*[is][\functionHighlight]{def\ }{:}},
moredelim={*[s][\color{code}]{(}{)}},
backgroundcolor = \color{bg},
}
\lstset{style=myPython}
\begin{document}
\begin{lstlisting}
class Base(object):
def new_function(self):
function contents
\end{lstlisting}
\end{document}
当我删除“i”标签并运行以下几行时,我看到了令我更加困惑的输出:
moredelim={*[s][\classHighlight]{class\ }{:}},
moredelim={*[s][\functionHighlight]{def\ }{:}},
答案1
因此,问题在于 listings 认为 delimiter styler 命令不会打印除其参数之外的任何内容,因此它认为重复调用该命令来排版不同部分的代码是安全的。您已告知 styler 实际打印文本,因此如果多次调用该命令,文本将被打印多次。
准确地说,它被调用了两次或三次。考虑如下代码:
class Base(object):
\classHighlight
被调用三次。第一次调用时,它的参数是一个空格,它应该进行缩进(我不确定为什么需要在空格上调用它——在我看来,缩进的样式应该与行上的内容无关,因此这对我来说似乎是一个错误)。
第二次调用时,它会获取参数Base
,因此此时我们要使用适当的颜色打印class
和Base
。如果您正确设置了分隔符,\classHighlight
则会使用参数 第三次调用:
。
那么我们该如何处理这个问题呢?我们不能每次都让宏打印“class”,否则“class”会出现在三个地方。我们要做的就是测试我们是否传递了空格命令,是否传递了 ,或者只是其他:
东西。如果我们传递了一个空格或冒号,就按原样输出。如果我们传递了其他东西,就按需要着色。
唯一重要的细节是我们需要制作结束分隔符,):
而不是仅仅:
因为某种原因。还请注意,如果没有,这将彻底失败moredelim={*[s][\color{code}]{(}{)}}
。
完整代码如下:
\documentclass{article}
\usepackage{listings, color}
\makeatletter
% This macro makes the style commands
% #1 -- the name of the command,
% #2 -- the styling code
\def\makeHighlightCommand#1#2{%
\gdef#1##1{%
\testkern{##1}% Check if ##1 starts with \kern, if so just output it
{% else do this code
\edef\testa{\the\lst@token}% The actual thing to be typeset is in \lst@token
\def\testb{:}%
\ifx\testa\testb % Test whether lst@token is just :
:% if so print the colon
% we're done now but for some reason \lst@currstyle (which is what
% contains this function) doesn't go out of scope correctly.
\global\let\lst@currstyle\relax % So we explicitly set it to \relax
\else
#2% Use the styling code
\fi
}%
}%
}
% Tests if the first argument starts with \kern,
% if so, just outputs its first argument, otherwise just outputs its second argument
\def\testkern#1{\testkern@#1\relax\nil}
\def\testkern@#1#2\nil{\ifx#1\kern #1#2\expandafter\@gobble\fi}
% Uses listing's internal method to output a sequence of letters
% makes them super far apart like all the other letters
\def\lsttt#1{%
\bgroup
\let\lst@currstyle\relax
\lsttt@#1.
\egroup
}
\def\lsttt@#1{\ifx#1.\else\lst@length=1\lst@token{#1}\lst@Output\expandafter\lsttt@\fi}
\makeatother
\definecolor{keyword}{RGB}{221,40,103}
\definecolor{classc}{RGB}{18,144,195}
\definecolor{code}{RGB}{217,232,247}
\definecolor{bg}{RGB}{35,35,35}
\definecolor{function}{RGB}{167,236,33}
\makeHighlightCommand\classHighlight{{\ttfamily\color{keyword}\lsttt{class}}{\bfseries\color{classc}#1}}
\makeHighlightCommand\functionHighlight{{\ttfamily\color{keyword}\lsttt{def}}{\bfseries\color{function}#1}}
\lstdefinestyle{myPython}{
language = Python,
basicstyle = \color{code}\ttfamily,
morekeywords=[1]{self,None,True,False,class},
moredelim={*[is][\classHighlight]{class\ }{):}},
moredelim={*[is][\functionHighlight]{def\ }{):}},
moredelim={*[s][\color{code}]{(}{)}},
backgroundcolor = \color{bg},
}
\lstset{style=myPython}
\begin{document}
\begin{lstlisting}
class Base(object):
def new_function(self):
contents
\end{lstlisting}
\end{document}
输出如下:
如果这没有按照你想要的方式进行,请告诉我。
编辑:Kevin 抱怨关键字 def 和 class 的字母之间的间距与其他所有字母之间的间距不一样。为了解决这个问题,我添加了代码:
\def\lsttt#1{%
\bgroup
\let\lst@currstyle\relax
\lsttt@#1.
\egroup
}
\def\lsttt@#1{\ifx#1.\else\lst@length=1\lst@token{#1}\lst@Output\expandafter\lsttt@\fi}