
eu tenho usadoesta soluçãoencontrado aqui no LaTeX Stack Exchange para colorir números em meus trechos de código:
\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\makeatletter
%%% Copied from https://tex.stackexchange.com/a/500690/23765
% Some conditional tests
\def\@genericif#1{#1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
\def\@ifdigit#1{\@genericif{\ifnum1<1\noexpand#1\relax}}
\def\@ifempty#1{\@genericif{\if\relax\detokenize{#1}\relax}}
% The main parsing macros
\def\parse@num#1{%
\@ifempty{#1}%
{\parse@num@false}%
{\@genericif{\parsesign}%
{\parse@num@sign#1{}\@end}%
{\parse@num@dig#1{}\@end}%
}%
}
% Parse sign
\def\parse@num@sign#1#2\@end{%
\@genericif{\ifx\parse@num@minus#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@dig#2\@end}}%
{\@genericif{\ifx\parse@num@plus#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@dig#2\@end}}%
{\parse@num@dig#1#2\@end}%
}%
}
% Parse first digit
\def\parse@num@dig#1#2\@end{%
\@ifdigit{#1}%
{\@ifempty{#2}{\parse@num@true}{\parse@num@digs#2\@end}}%
{\parse@num@false}%
}
% Parse optional following digits
\def\parse@num@digs#1#2\@end{%
\@ifdigit{#1}{%
\@ifempty{#2}%
{\parse@num@true}%
{\parse@num@digs#2\@end}%
}{%
\@genericif{\parsefloat}{%
\@genericif{\ifx\parse@num@point#1}%
{\@ifempty{#2}{\parse@num@false}{\parse@num@decs#2\@end}}%
{\parse@num@false}%
}{\parse@num@false}%
}%
}
% Parse decimal places
\def\parse@num@decs#1#2\@end{%
\@ifdigit{#1}{%
\@ifempty{#2}%
{\parse@num@true}%
{\parse@num@decs#2\@end}%
}{\parse@num@false}%
}
% User interface
\newcommand\ifnumber[4][]{%
\begingroup
\let\parsesign=\iftrue
\let\parsefloat=\iftrue
\let\parse@num@minus=-%
\let\parse@num@plus=+%
\let\parse@num@point=.%
#1%
\def\parse@num@true{\endgroup#3}%
\def\parse@num@false{\endgroup#4}%
\parse@num{#2}%
}
%%% Additions to the listings package
\lst@Key{numbersstyle}{}{\def\lst@numbersstyle{#1}}
\lst@Key{parsenumbers}{false}[t]{\lstKV@SetIf{#1}\lst@ifparsenumbers}
\lst@AddToHook{OutputOther}{%
\lst@ifparsenumbers
% Only if mode changes are not prohibited
\lst@ifmode\else
\expandafter\@hook@ifnumber\the\lst@token\@end
{\let\lst@thestyle=\lst@numbersstyle}%
{}%
\fi
\fi
}
\def\@hook@ifnumber#1#2\@end{%
\@genericif{\ifx\lst@nolig#1}%
{\@hook@ifnumber@{#2}}%
{\@hook@ifnumber@{#1#2}}%
}
\def\@hook@ifnumber@{%
\ifnumber[\expandafter\let\expandafter\parse@num@minus\csname lst@um-\endcsname]%
}
\makeatother
%%% Example document
\lstset{
basicstyle = \ttfamily,
identifierstyle = \color{blue},
keywordstyle = \color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
% Apply new number coloring routine
parsenumbers = true,
numbersstyle = {\color{magenta}}
}
Funciona bastante bem, mas infelizmente também apresenta alguns problemas. Anexando isso acima ao meu exemplo mínimo abaixo...:
\begin{document}
\section{Python}
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\section{Processing}
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}
...resulta em:
Os resultados não são ruins, e é particularmente bom que essa solução lide com números em nomes de variáveis, independentemente de serem seguidos por um sublinhado ou não (por exemplo, var_2
e var3
). Mas o exemplo acima também mostra alguns problemas que não consegui resolver:
- É possível ver que os números precedidos por a
(
ou imediatamente seguidos por)
não são coloridos, por exemplorange(3)
,size(300, 300)
- os números que tocam sinais como vírgulas, dois pontos ou ponto e vírgula também não são coloridos; por exemplo, o número do meio em
background(0, 200, 0);
ou os números emx = x + 0.1;
ouif var_2 > 1.23:
- por outro lado, ter espaços ao seu redor resulta em realce adequado, por exemplo
y = 0 ;
(com espaço antes do ponto e vírgula) ou o número1000
emelif (var3 <= 1000 and var_2 is None):
Alguém poderia me ajudar a ajustar esse trecho para que os números sejam destacados de forma consistente nessas situações, embora ainda não sejam destacados em nomes de variáveis e funções?
Editar: em poucas palavras, gostaria que os números fossem destacados se:
- eles vêm depois de qualquer um dos seguintes caracteres:
,
.
,(
,{
,[
,:
- eles vêm antes de qualquer um dos seguintes caracteres:
,
.
,)
,}
,]
,:
,;
- mas definitivamente não incluir
_
em nenhum dos grupos, pois isso pode quebrar a convenção de nomenclatura de variáveis em muitos trechos de código (mesmo que o Python aceite_
números para ajudar na identificação visual de grupos de 10 ^ 3, como emx = 1_000_000
.
Atualmente, o código acima identifica corretamente apenas e
.
de todos os caracteres mencionados nos marcadores acima.
Editar: infelizmente minted
não é uma opção para mim, não combina bem com meu arquivo de dissertação.
Responder1
Considere usar minted
e personalizar as folhas de estilo.
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{minted}
\usemintedstyle{colorful}
\begin{document}
\begin{minted}{python}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{minted}
\begin{minted}{c}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{minted}
\end{document}
Responder2
Se entendi a pergunta, você deseja colorir todos os dígitos, a menos que estejam em palavras-chave ou identificadores. Você pode fazer isso usando como fonte base uma fonte com dígitos coloridos e uma fonte diferente para as palavras-chave. Com lualatex isso aqui é possível:
\documentclass{article}
\usepackage{listings,xcolor}
\usepackage{fontspec}
\directlua{
luaotfload.add_colorscheme("colordigits",
{
["FF00FF"] = {"one","two","three","four","five","six","seven","eight","nine","zero"},
})}
\newfontfamily\colordigits{Latin Modern Mono}[RawFeature={color=colordigits}]
\lstset{
basicstyle = \colordigits,
identifierstyle = \ttfamily\color{blue},
keywordstyle = \ttfamily\color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
}
%
\begin{document}
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\section{Processing}
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}
Responder3
Para completar, uma solução não Lua usando interchartoks em xetex falha no último momento porque lstlistings insere cola entre os tokens. A cola é vista como um marcador de limite entre palavras pelos interchartoks.
Portanto, não é uma resposta (sem reescrever o pacote (usando joiners de largura zero?), mesmo que o cenário do pdflatex fosse superável.
Para ilustrar as transições entre classes de token:
vermelho é o limite da palavra para a transição de dígitos.
MWE
\documentclass{article}
\XeTeXinterchartokenstate=1
\usepackage{listings,xcolor}
\usepackage{fontspec}
\newXeTeXintercharclass\LetterClass
%from:
%https://tex.stackexchange.com/questions/411846/xelatex-minion-pro-and-italian-apostrophe-kerning/411850#411850
\makeatletter
\@tempcnta=`\A
\loop\unless\ifnum\@tempcnta>`\Z
\XeTeXcharclass \@tempcnta \LetterClass
\advance \@tempcnta by 1
\repeat
\@tempcnta=`\a
\loop\unless\ifnum\@tempcnta>`\z
\XeTeXcharclass \@tempcnta \LetterClass
\advance \@tempcnta by 1
\repeat
\XeTeXcharclass `\_ \LetterClass
\makeatother
% char class for digits
\newXeTeXintercharclass \mydigitsclass
\XeTeXcharclass `\0 \mydigitsclass
\XeTeXcharclass `\1 \mydigitsclass
\XeTeXcharclass `\2 \mydigitsclass
\XeTeXcharclass `\3 \mydigitsclass
\XeTeXcharclass `\4 \mydigitsclass
\XeTeXcharclass `\5 \mydigitsclass
\XeTeXcharclass `\6 \mydigitsclass
\XeTeXcharclass `\7 \mydigitsclass
\XeTeXcharclass `\8 \mydigitsclass
\XeTeXcharclass `\9 \mydigitsclass
% def interchartokes
\XeTeXinterchartoks \LetterClass \mydigitsclass = {\begingroup\huge}
\XeTeXinterchartoks \mydigitsclass \LetterClass = {\endgroup}
\XeTeXinterchartoks 0 \mydigitsclass = {\begingroup\color{green}}
\XeTeXinterchartoks \mydigitsclass 0 = {\endgroup}
\XeTeXinterchartoks 4095 \mydigitsclass = {\begingroup\color{red}}
\XeTeXinterchartoks \mydigitsclass 4095 = {\endgroup}
\lstset{
% basicstyle = \colordigits,
identifierstyle = \ttfamily\color{blue},
keywordstyle = \ttfamily\color{green!80!black},
keywords = {foo},
moredelim = [il][]{**},
moredelim = [l][\color{gray}]{/},
morestring = [d][\color{gray}]{"},
morestring = *[d][\color{gray}\itshape]{!},
morestring = **[d][\color{gray}\itshape]{?},
}
\begin{document}
\XeTeXinterchartokenstate=0
\section{Test}
\XeTeXinterchartokenstate=1
abc 012 345 678 9 xyz
[The lstlisting environment adds "\textbackslash glue 0 plus 1fil minus 1fil" betweeen every token]
%https://tex.stackexchange.com/questions/281566/xetex-special-xetexcharclass-needed-for-null-glues/321664#321664
\XeTeXinterchartokenstate=0
\subsection{Inline}
\XeTeXinterchartokenstate=1
def foobar(self):
var = 123 + 456
var\_2 = 4.56
var3 = 789
for \_ in range(3):
print(test)
if var\_2 > 1.23:
print(1024)
\XeTeXinterchartokenstate=0
\subsection{Verbatim}
\XeTeXinterchartokenstate=1
\begin{verbatim}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
\end{verbatim}
\XeTeXinterchartokenstate=0
\subsection{Listing}
\XeTeXinterchartokenstate=1
\begin{lstlisting}
def foobar(self):
var = 123 + 456
var_2 = 4.56
var3 = 789
for _ in range(3):
print(test)
if var_2 > 1.23:
print(1024)
elif (var3 <= 1000 and var_2 is None):
print(0)
\end{lstlisting}
\XeTeXinterchartokenstate=0
\section{Processing}
\XeTeXinterchartokenstate=1
\begin{lstlisting}
void setup() {
size(300, 300);
background(0, 200, 0);
}
void draw() {
drawFlower(150, 150, 100);
for (int i = 0; i < 80; i = i+5) {
line(30, i, 80, i);
}
x = x + 0.1;
y = 0.1 + y;
if (x > 1.23) {
x = 0;
y = 0 ;
}
}
\end{lstlisting}
\end{document}