列表中的标题小写字母

列表中的标题小写字母

我正在尝试将 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}

相关内容