我正在尝试将 Listings 中的大写字母转换KEYWORD
为\textsc{Keyword}
。我想要以下形式
\lstdefinestyle{mystyle}
{
language = ML,
basicstyle = {\ttfamily},
keywordstyle = [2]{\scAfterTitlecase}, % magic macro desired here!
morekeywords = [2]{SOME,NONE,GREATER,EQUAL,LESS},
}
理想情况下,如果\scAfterTitlecase
可以定义,列表将“吃掉”代码片段SOME x
并“吐出”排版结果,“就好像”它是{\sc Some} x
(例如)。
笔记:我知道这\sc
不会保留\ttfamily
基本风格,这是故意的。我不是尝试使用小写电传打字字母。
广义问题
展望未来,我意识到我将要排版SNAKE_CASE_UPPERCASE_KEYWORDS
,而且我很想找到某种方法以类似的方式将它们转换为“小型大写帕斯卡字母”排版(例如,SNAKE_CASE_UPPER
将转换为{\sc SnakeCaseUpper}
)。
完整示例
我想在 LaTeX 中输入如下内容:
\documentclass{article}
\usepackage{listings}
\lstset{
language=ML,
basicstyle = {\ttfamily},
keywordstyle = [2]{\scAfterTitlecase}, % magic macro desired here!
morekeywords = [2]{SOME,NONE,GREATER,EQUAL,LESS,STRETCH_GOAL},
}
\begin{document}
\begin{lstlisting}
signature STRETCH_GOAL = sig
val will_work : bool;
val issued : bool option;
end;
fun giveRaise (SOME true) = true
| giveRaise _ = false;
\end{lstlisting}
\end{document}
我希望该lstlistings
环境的排版方式就像我写的一样:
signature \textsc{StretchGoal} = sig
val will_work : bool;
val issued : bool option;
end;
fun giveRaise (\textsc{Some} true) = true
| giveRaise _ = false;
我想要一个神奇的\scAfterTitlecase
宏,它的效果与我能以某种方式转换的效果相同morekeywords = [2]{Some, None, StretchGoal, ...}
。我不想手动更改关键字的原因是因为我正在加载实际的标准 ML 代码。
编辑 1(2022 年 1 月 13 日):作为第一次尝试,我设法编写了一个宏,它可以接受 SCREAMING_SNAKE_CASE 参数并将其转换为 PascalCase 字符串:
\usepackage{mfirstuc}
\makeatletter
\def\@Screaming@Snake@To@Pascal@Case#1_#2\end@Screaming@Snake@To@Pascal@Case{%
\makefirstuc{\MakeLowercase{#1}}%
\ifx#2\@empty%
\else\ignorespaces\@Screaming@Snake@To@Pascal@Case#2%
\end@Screaming@Snake@To@Pascal@Case%
\fi}
\newcommand\ScreamingSnakeToPascalCase[1]{\ifx\@empty#1%
\else%
\@Screaming@Snake@To@Pascal@Case#1_\@empty\end@Screaming@Snake@To@Pascal@Case%
\fi}
\makeatother
这很好用。然后我尝试编写此宏的“无参数”版本(如线程中讨论的那样更改宏的语法,使其进入括号内)完整的、呃,“可行”的最小示例:
\documentclass{article}
\usepackage{mfirstuc}
\makeatletter
\def\@Screaming@Snake@To@Pascal@Case#1_#2\end@Screaming@Snake@To@Pascal@Case{%
\makefirstuc{\MakeLowercase{#1}}%
\ifx#2\@empty%
\else\ignorespaces\@Screaming@Snake@To@Pascal@Case#2%
\end@Screaming@Snake@To@Pascal@Case%
\fi}
\newcommand\ScreamingSnakeToPascalCase[1]{\ifx\@empty#1%
\else%
\@Screaming@Snake@To@Pascal@Case#1_\@empty\end@Screaming@Snake@To@Pascal@Case%
\fi}
\makeatother
\newcommand{\noarg}{%
% close the group
\egroup
% the first \expandafter removes \iftrue
% the second \expandafter removes \else
\expandafter\expandafter\expandafter
\ScreamingSnakeToPascalCase\iftrue\expandafter{\else}\fi
}
\lstset{
language=ML,
alsoletter={_},
basicstyle = {\ttfamily},
keywordstyle = {[2]\noarg},
morekeywords = [2]{SOME,NONE,GREATER,EQUAL,LESS,STRETCH_GOAL},
}
\begin{document}
{\noarg COUGH_DROP_MAY_NOT_WORK_GOOD} % This is typeset fine
% ...if I remove the lstlisting environment below
\textsc{\ScreamingSnakeToPascalCase{SPAM_EGGS_BUTTER}} % also works fine
% now, this lstlisting fails...
\begin{lstlisting}
signature STRETCH_GOAL = sig
val will_work : bool;
val issued : bool option;
end;
fun giveRaise (SOME true) = true
| giveRaise _ = false;
\end{lstlisting}
\end{document}
LaTeX 不太开心,抱怨道:
! Extra \else.
\@makefirstuc ...i \@gls@domfirstuc \fi \fi \else
\glsmakefirstuc {#1}\fi \fi
l.44 signature STRETCH_GOAL
= sig
?
因此,尽管很小,但还是向前迈了一步。
答案1
我提出了一个解决方案这个。唯一的微妙之处在于,每个执行的 TeX 宏都会导致列表中出现水平跳过,所以我需要一个\unskip
来撤消此操作。
但这将正确地转变SCREAMING_SNAKE_CASE
为\textsc{ScreamingSnakeCase}
Listings 环境中的情形。
\documentclass{article}
\usepackage{mfirstuc}
\makeatletter
% I need to do something like
% https://tex.stackexchange.com/a/448770/14751
% to transform the "\lst@um_" back to "_"
\def\@Screaming@Snake@To@Pascal@Case#1\_#2\end@Screaming@Snake@To@Pascal@Case{%
\makefirstuc{\MakeLowercase{#1}}%
\ifx#2\@empty\else\ignorespaces\@Screaming@Snake@To@Pascal@Case#2\end@Screaming@Snake@To@Pascal@Case\fi}
\newcommand\ScreamingSnakeToPascalCase[1]{%
\ifx\@empty#1\else{\normalfont\scshape\@Screaming@Snake@To@Pascal@Case#1\_\@empty\end@Screaming@Snake@To@Pascal@Case}\fi}
% https://tex.stackexchange.com/questions/439396/listings-highlight-a-prefixed-keyword-starting-with-a-single-quote
\makeatother
\usepackage{listings}
\makeatletter
\def\@setlststyle{%
\unskip\edef\lt@temp{\unskip\noexpand\ScreamingSnakeToPascalCase{\expandafter\the\lst@token\unskip\relax\unskip}}%
\unskip\global\lst@token=\expandafter{\lt@temp}%
\unskip\the\lst@token
}
\begingroup
\catcode`\_=11
\gdef\scsty#1{
\unskip\edef\lsttokens{\the\lst@token}
\unskip\global\lst@token={}
\unskip\expandafter\replaceUM\lsttokens\noexpand\lst@um_\relax\@end
\unskip\unskip\@setlststyle
}
\gdef\appendall#1\@endAppend{\unskip
\global\lst@token=\expandafter{\the\lst@token#1}
}
\gdef\replaceUM#1\lst@um_#2\@end{\unskip
\if\relax\detokenize{#1}\relax
\else
\ifx\relax#2
\appendall#1\@endAppend
\else
\appendall#1\_\@endAppend
\replaceUM#2\@end
\fi
\fi
}
\endgroup
\makeatother
\lstset{
% language=ML,
% columns = fixed,
columns=flexible,
% columns=fullflexible,
alsoletter={_},
basicstyle = {\ttfamily},
keywordstyle = [2]\scsty,
morekeywords = [2]{SOME,NONE,GREATER,EQUAL,LESS,STRETCH_GOAL},
keywordstyle = {\bf},
morekeywords={abstype,and,andalso,as,case,do,datatype,else,end,%
eqtype,exception,fn,fun,functor,handle,if,in,include,infix,%
infixr,let,local,nonfix,of,op,open,orelse,raise,rec,sharing,sig,%
signature,struct,structure,then,type,val,with,withtype,while},%
sensitive,%
morecomment=[n]{(*}{*)},%
morestring=[d]"%
}
\begin{document}
\begin{lstlisting}
signature STRETCH_GOAL = sig
val will_work : bool;
val issued : bool option;
end;
fun giveRaise (SOME true) = true
| giveRaise _ = false;
\end{lstlisting}
\end{document}