9

I have a problem with the definition of literate:

\lstset{
  numbers=left, numberstyle=\footnotesize, stepnumber=1, numbersep=12pt,
  frame=none, framesep=7pt,
  breaklines=true,
  basicstyle=\footnotesize,
  showstringspaces=false,
  upquote=true,
  columns=fullflexible,
  showstringspaces=false,
  commentstyle=\color{gray}\upshape,
  stringstyle=\color{black}\ttfamily,
  keywordstyle=\color{darkblue},
  captionpos=b,
  extendedchars=true,
  literate=
  *{0}{{{\color{DarkGreen}0}}}1
  {1}{{{\color{DarkGreen}1}}}1
  {2}{{{\color{DarkGreen}2}}}1
  {3}{{{\color{DarkGreen}3}}}1
  {4}{{{\color{DarkGreen}4}}}1
  {5}{{{\color{DarkGreen}5}}}1
  {6}{{{\color{DarkGreen}6}}}1
  {7}{{{\color{DarkGreen}7}}}1
  {8}{{{\color{DarkGreen}8}}}1
  {9}{{{\color{DarkGreen}9}}}1
  {á}{{\'a}}1
  {é}{{\'e}}1
  {í}{{\'i}}1
  {ó}{{\'o}}1
  {ú}{{\'u}}1
}

The coloring of the numerals has the be ignored inside comments and strings (hence the * at the beginning) BUT the rules for the acute accents shouldn't. This is because source code with strings in different languages is included later with the \lstinputlisting option, and if the unicode characters are not changed, it crashes.

So, does anyone know any way to apply the * to only part of the literate definitions? I tried to define them in the specific listing where the file is included, but a second literate eliminates the previous definitions.

PS: I tried to change the encoding of the file with the \inputencoding=utf8/latin1 as well, but it makes the compilation REALLY slow and returns a Missing $ inserted. error.

EDIT: I'm adding a fully compilable MWE that I think represents the problem. The output highlights the colors according to the rules defined for Javascript. However, as I said before, in line 22 (see output) the numerals are in green, even being a comment. If the * is added before the numerals, the compilation crashes because the unicode characters inside the strings are not replaced.

(NOTE: the javascript doesn't make any sense)

\documentclass[spanish, 11pt]{book}

\usepackage[utf8]{inputenc}
\usepackage[margin=2.5cm]{geometry}
\usepackage[spanish]{babel}
\usepackage{fancyhdr}
\usepackage{graphicx}
\usepackage[colorlinks=true, linkcolor=black, citecolor=black, urlcolor=blue]{hyperref}
\usepackage[format=hang]{caption}
\usepackage{appendix}
\usepackage{color}
\usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
\usepackage{listings}
\usepackage{listingsutf8}
\usepackage{float}
\usepackage{textcomp}
\usepackage{underscore}


\lstdefinelanguage{JavaScript}{
  keywords={typeof, new, true, false, catch, function, return, null, catch, switch, var, if, in, while, do, else, case, break, ajax, each, get, post},
  keywordstyle=\color{darkblue}\bfseries,
  keywords=[2]{class, export, boolean, throw, implements, import, this},
  keywordstyle=[2]\color{darkgray}\bfseries,
  identifierstyle=\color{black},
  sensitive=false,
  comment=[l]{//},
  morecomment=[s]{/*}{*/},
  commentstyle=\color{FireBrick}\ttfamily,
  stringstyle=\color{DarkOrange}\ttfamily,
  morestring=[b]',
  morestring=[b]"
}

\lstdefinestyle{Javascript}{
   language=JavaScript,
   extendedchars=true,
   basicstyle=\footnotesize,
   showstringspaces=false,
   showspaces=false,
   tabsize=2,
   breaklines=true,
   showtabs=false,
   captionpos=b,
}

\lstset{
language=Javascript,
style=Javascript,
  numbers=left, numberstyle=\footnotesize, stepnumber=1, numbersep=12pt,
  frame=none, framesep=7pt,
  breaklines=true,
  basicstyle=\footnotesize,
  showstringspaces=false,
  upquote=true,
  columns=fullflexible,
  showstringspaces=false,
  keywordstyle=\color{DarkBlue},
  captionpos=b,
  extendedchars=true,
  literate=
  {0}{{{\color{DarkGreen}0}}}1
  {1}{{{\color{DarkGreen}1}}}1
  {2}{{{\color{DarkGreen}2}}}1
  {3}{{{\color{DarkGreen}3}}}1
  {4}{{{\color{DarkGreen}4}}}1
  {5}{{{\color{DarkGreen}5}}}1
  {6}{{{\color{DarkGreen}6}}}1
  {7}{{{\color{DarkGreen}7}}}1
  {8}{{{\color{DarkGreen}8}}}1
  {9}{{{\color{DarkGreen}9}}}1
  {á}{{\'a}}1 
  {é}{{\'e}}1
  {í}{{\'i}}1
  {ó}{{\'o}}1
  {ú}{{\'u}}1
  {Á}{{\'A}}1
  {É}{{\'E}}1
  {Í}{{\'I}}1
  {Ó}{{\'O}}1
  {Ú}{{\'U}}1
  {¡}{{!`}}1
  {¿}{{?`}}1
  {·}{{$\cdot$}}1
}

\begin{document}
\begin{lstlisting}
function manageLanguage(text)
{ // Language options in interface and errors
    switch (language)
    {
case "Welcome":
        return '¡Bienvenido a '

        case "Browse":
        return '<b>Navega</b> por tu disco duro y selecciona lo(s) fichero(s) a visualizar o simplemente <b>arrástralos</b> al área del botón'

        case "Default":
        return 'Ejemplo por Defecto'
    }

    case "Catalan":
        switch (text)
        {

        case "AlreadySession":
        return 'Ja tens una sessió oberta. Sel·lecciona Nou al menú Fitxer per tancarla i apujar nous fitxers.'

        //var start = (Math.round(this.x*100)/100);
                if (start % intervals == 0)         
                return "<b>" + manageLanguage("Interval") +":</b> [" + Math.round(this.x*10)/10 + " - " + Math.round((this.x+intervals)*10)/10+"]<br/><b>" + manageLanguage(this.series.name) + ":</b> " + this.y + " ";
                else return false; //"<b>" + manageLanguage("Interval") +":</b> [" + this.key + " - " + (this.key+intervals)+"]<br/><b>" + manageLanguage(this.series.name) + ":</b> " + this.y;
\end{lstlisting}

\end{document}

1 Answers1

10

The following example now uses the trick of Jubobs' comment, the context checking via \lst@mode.

\documentclass[spanish, 11pt]{book}

\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}
\usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
\usepackage{listings}
\usepackage{listingsutf8}
\usepackage{textcomp}

\makeatletter
\newcommand*{\lstnumcolor}{%
  \ifnum\lst@mode=\lst@Pmode
    \color{DarkGreen}%
  \fi
}
\makeatother

\lstdefinelanguage{JavaScript}{
  keywords={typeof, new, true, false, catch, function, return, null, catch, switch, var, if, in, while, do, else, case, break, ajax, each, get, post},
  keywordstyle=\color{darkblue}\bfseries,
  keywords=[2]{class, export, boolean, throw, implements, import, this},
  keywordstyle=[2]\color{darkgray}\bfseries,
  identifierstyle=\color{black},
  sensitive=false,
  comment=[l]{//},
  morecomment=[s]{/*}{*/},
  commentstyle=\color{FireBrick}\ttfamily,
  stringstyle=\color{DarkOrange}\ttfamily,
  morestring=[b]',
  morestring=[b]"
}

\lstdefinestyle{Javascript}{
   language=JavaScript,
   extendedchars=true,
   basicstyle=\footnotesize,
   showstringspaces=false,
   showspaces=false,
   tabsize=2,
   breaklines=true,
   showtabs=false,
   captionpos=b,
   keepspaces,
}

\lstset{
language=Javascript,
style=Javascript,
  numbers=left, numberstyle=\footnotesize, stepnumber=1, numbersep=12pt,
  frame=none, framesep=7pt,
  breaklines=true,
  basicstyle=\footnotesize,
  showstringspaces=false,
  upquote=true,
  columns=fullflexible,
  showstringspaces=false,
  keywordstyle=\color{DarkBlue},
  captionpos=b,
  extendedchars=true,
  literate=
  {0}{{{\lstnumcolor0}}}1
  {1}{{{\lstnumcolor1}}}1
  {2}{{{\lstnumcolor2}}}1
  {3}{{{\lstnumcolor3}}}1
  {4}{{{\lstnumcolor4}}}1
  {5}{{{\lstnumcolor5}}}1
  {6}{{{\lstnumcolor6}}}1
  {7}{{{\lstnumcolor7}}}1
  {8}{{{\lstnumcolor8}}}1
  {9}{{{\lstnumcolor9}}}1
  {á}{{\'a}}1 
  {é}{{\'e}}1
  {í}{{\'i}}1
  {ó}{{\'o}}1
  {ú}{{\'u}}1
  {Á}{{\'A}}1
  {É}{{\'E}}1
  {Í}{{\'I}}1
  {Ó}{{\'O}}1
  {Ú}{{\'U}}1
  {¡}{{!`}}1
  {¿}{{?`}}1
  {·}{{$\cdot$}}1
}

\begin{document}
\begin{lstlisting}
function manageLanguage(text)
{ // Language options in interface and errors
    String str4 = "Numbers 123 and 4 in string"; // Numbers 123 and 4 in comment
    switch (language)
    {
        case "Welcome":
        return '¡Bienvenido a '

        case "Browse":
        return '<b>Navega</b> por tu disco duro y selecciona lo(s) fichero(s) a visualizar o simplemente <b>arrástralos</b> al área del botón'

        case "Default":
        return 'Ejemplo por Defecto'
    }

    case "Catalan":
        switch (text)
        {

        case "AlreadySession":
        return 'Ja tens una sessió oberta. Sel·lecciona Nou al menú Fitxer per tancarla i apujar nous fitxers.'

        //var start = (Math.round(this.x*100)/100);
                if (start % intervals == 0)         
                return "<b>" + manageLanguage("Interval") +":</b> [" + Math.round(this.x*10)/10 + " - " + Math.round((this.x+intervals)*10)/10+"]<br/><b>" + manageLanguage(this.series.name) + ":</b> " + this.y + " ";
                else return false; //"<b>" + manageLanguage("Interval") +":</b> [" + this.key + " - " + (this.key+intervals)+"]<br/><b>" + manageLanguage(this.series.name) + ":</b> " + this.y;
\end{lstlisting}

\end{document}

Result

Remark:

Limitation:

  • Numbers inside identifiers are colored, too.

Package listingsutf8

The trick with converting UTF-8 to a 8-bit encoding via package listingsutf8 only works for \lstinputlisting. Thus the code needs to be put into a separate file. But then utf8/latin1 (or utf8/x-iso-8859-1) works together with literate=*... for the digits excluding comments.

Heiko Oberdiek
  • 271,626
  • One problem with you approach is that literal replacements of digits also occur in strings, which the OP doesn't want. You can get around that problem by using the following definition for your \lstnumcolor macro instead: \newcommand*{\lstnumcolor}{\ifnum\lst@mode=\lst@Pmode \color{DarkGreen}\fi}. See this answer in which I used the same trick. – jub0bs Mar 06 '14 at 09:46
  • @Jubobs: Thanks, answer updated. However severe limitations remain, see answer. – Heiko Oberdiek Mar 06 '14 at 09:54
  • The space problem can be fixed by using the keepspaces option. See http://tex.stackexchange.com/a/46695/21891. – jub0bs Mar 06 '14 at 11:36