I'm trying to transform an uppercase KEYWORD into \textsc{Keyword} in Listings. I'd like something of the form
\lstdefinestyle{mystyle}
{
language = ML,
basicstyle = {\ttfamily},
keywordstyle = [2]{\scAfterTitlecase}, % magic macro desired here!
morekeywords = [2]{SOME,NONE,GREATER,EQUAL,LESS},
}
Ideally, if \scAfterTitlecase could be defined, the listing would "eat in" a code snippet SOME x and "spit out" a typeset result "as if" it were {\sc Some} x (for example).
Note: I realize that \sc will not preserve the \ttfamily basic style, and that is intentional. I am not trying to have small cap teletype letters.
Generalized Problem
Looking ahead, I realize I am going to be typesetting SNAKE_CASE_UPPERCASE_KEYWORDS, and I would love to figure out some way to similarly transform them to be typeset "small caps Pascal cased" (e.g., SNAKE_CASE_UPPER would be transformed into {\sc SnakeCaseUpper}).
Complete Example
I want to type in LaTeX something like this:
\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}
I want that lstlistings environment to be typeset as if I wrote:
signature \textsc{StretchGoal} = sig
val will_work : bool;
val issued : bool option;
end;
fun giveRaise (\textsc{Some} true) = true
| giveRaise _ = false;
I want a magic \scAfterTitlecase macro which would have the same effect as if I could somehow transform the morekeywords = [2]{Some, None, StretchGoal, ...}. The reason why I don't want to just change the keywords by hand is because I'm loading actual Standard ML code.
Edit 1 (Jan 13, 2022): As a first stab, I managed to write a macro which can take a SCREAMING_SNAKE_CASE argument and convert it to a PascalCase string:
\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
This works fine. Then I tried writing a "no argument" version of this macro (as discussed in the thread Change syntax of macro, to go inside braces). The complete, uh, "working" minimal example:
\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 is not happy, compaining:
! Extra \else.
\@makefirstuc ...i \@gls@domfirstuc \fi \fi \else
\glsmakefirstuc {#1}\fi \fi
l.44 signature STRETCH_GOAL
= sig
?
So, one step forward, albeit very small.
SOME xtransformed into the\textsc{Some} x, but I have added a complete example anyways. – Alex Nelson Jul 28 '21 at 02:10\scAfterTitlecaseneeds to 1) split a keyword into its component words by underscores_(if there are any), and then remove the underscores; 2) in each component words, capitalize the first letter while making all other letters lowercase; and 3) typeset the entire keyword in cap+small cap. Is my understanding correct? – Ruixi Zhang Jul 28 '21 at 03:25