2

How do I modify the key-value option

\lstdefinelanguage{mybnf}{
  morestring   = [b]''
}

To obtain the following result:

enter image description here

that is, to be able to have the delimiters defined in a different style (in this case different color) from the content?

Following is my MWE:

\documentclass{article}
\usepackage{fontspec}
\usepackage{longtable, booktabs}
\usepackage{listings, listings-ext, listingsutf8}
\usepackage{xcolor}

\setmainfont{Tisa OT}
\setsansfont{TeX Gyre Heros Cn}
\setmonofont{Fira Code}


%
% general listing colors
%
\definecolor{listing-background}{HTML}{F7F7F7}
\definecolor{listing-rule}{HTML}{B3B2B3}
\definecolor{listing-numbers}{HTML}{B3B2B3}
\definecolor{listing-text-color}{HTML}{000000}
\definecolor{listing-keyword}{HTML}{435489}
\definecolor{listing-keyword-2}{HTML}{1284CA} % additional keywords
\definecolor{listing-keyword-3}{HTML}{9137CB} % additional keywords
\definecolor{listing-identifier}{HTML}{435489}
\definecolor{listing-string}{HTML}{00999A}
\definecolor{listing-comment}{HTML}{8E8E8E}

\lstdefinestyle{etturaz_listings_style}{
    language         = java,
    alsolanguage     = scala,
    numbers          = left,
    xleftmargin      = 2.7em,
    framexleftmargin = 2.5em,
    backgroundcolor  = \color{white},
    basicstyle       = \color{listing-text-color}\linespread{1.0}\small\ttfamily,
    breaklines       = true,
    frame            = single,
    framesep         = 0.19em,
    rulecolor        = \color{listing-rule},
    frameround       = ffff,
    tabsize          = 3,
    numberstyle      = \color{listing-numbers},
    aboveskip        = 1.0em,
    belowskip        = 0.1em,
    abovecaptionskip = 0em,
    belowcaptionskip = 1.0em,
    keywordstyle     = {\color{listing-keyword}\bfseries},
    keywordstyle     = {[2]\color{listing-keyword-2}\bfseries},
    keywordstyle     = {[3]\color{listing-keyword-3}\bfseries\itshape},
    sensitive        = true,
    identifierstyle  = \color{listing-identifier},
    commentstyle     = \color{listing-comment},
    stringstyle      = \color{listing-string},
    showstringspaces = false,
    escapeinside     = {/*@}{@*/}, % Allow LaTeX inside these special comments
    literate         = {«}{{\guillemotleft}}1 {»}{{\guillemotright}}1
    {…}{{\ldots}}1 {≥}{{>=}}1 {≤}{{<=}}1 {„}{{\glqq}}1 {“}{{\grqq}}1
    {”}{{''}}1 {<\%}{{{\color{listing-keyword}<\%}}}2
}
\lstset{style=etturaz_listings_style}


\lstdefinelanguage{Scala}{
    morekeywords={
        % normal keywords (without data types)
        abstract, case, catch, class, def, do, else, extends, false, final,
        finally, for, forSome, if, implicit, import, lazy, macro, match, new,
        null, object, override, package, private, protected, return, sealed, 
        super, this, throw, trait, try, true, type, val, var, while, with, yield, 
        _, :, ;, =, =>, <-, <:
    },
    morekeywords={[2] % data types
        String, Boolean,Byte,Character,Double,Float,Integer,Long,Short, Number,BigDecimal,BigInteger
    },
    morekeywords={[2] % data types
        Seq, List, Map
    },
    sensitive,
    morecomment  = [l]//,
    morecomment  = [s]{/*}{*/},
    morecomment  = [s]{/**}{*/},
%
    morestring   = [b]',
    morestring   = [s][\color{black}]{"}{"}
}

\lstdefinelanguage{xbnf}{
    morekeywords={
        % normal keywords (without data types)
        ::=
    }
    sensitive,
    morecomment  = [l]//,
    morecomment  = [s]{(*}{*)},
    morestring   = [b]',
    morestring   = [s][\color{black}]{"}{"}
}


\begin{document}
%   \lstset{language=Scala}
    \begin{lstlisting}[language=Scala]
        def stringDivideBy(aStr: String, bStr: String): Option[Int] =
            parseInt(aStr).flatMap { aNum =>
                parseInt(bStr).flatMap { bNum =>
                    divide(aNum, bNum)
                }
            }
    \end{lstlisting}

    \begin{lstlisting}[language=xbnf]
        json ::= element
        value ::= object | array | string | number | "true" | "false" | "null"
        (* So here the two apostrophes in '{' should be green and the bracket black *)
        object ::= '{' ws '}' | '{' member {',' member} '}'
        member ::= ws string ws ':' element
        array ::= '[' ws ']' | '[' element {',' element} ']'
        element ::= ws value ws
        (* Here, again, two green black and the double quote black*)
        string ::= '"' '"' | character {character} '"'
        character ::= 'A' | ... | 'Z' | 'a' | ... | 'z' | escape
    \end{lstlisting}

\end{document}

Here's the result: enter image description here

Thanks

Guidone
  • 127
  • 1
    Could perhaps be done with literal. – Skillmon Apr 04 '20 at 15:52
  • @Skillmonlikestopanswers.xyz Thanks for you prompt reply. Actually, I thought about that, but what happens if I encounter the case: " " "; i.e., the double quote, which is by a chance the delimiter, needs to be defined within two double quote, wouldn't it end up having the same color? – Guidone Apr 04 '20 at 16:02
  • if your language isn't Python (or another language that uses triple-quotes as a special delimiter) that's a syntax error. – Skillmon Apr 04 '20 at 16:08
  • @Skillmonlikestopanswers.xyz, actually, I' m trying to define a style for ebnf, so the double quotes (or the single one for that matter) could be both delimiters and content ; e.g. ' " " ' or " ' ". I know, EBNF doesn' t qualify as a programming language, but I thought of giving a try. :-))) – Guidone Apr 04 '20 at 16:31
  • 1
    Ah, now I understand what you meant. Your first comment has """ which isn't quite the same as '"' or "'"... You could achieve that by setting a switch for single and double quotes. – Skillmon Apr 04 '20 at 17:31
  • @Skillmonlikestopanswers.xyz, mmh, sounds interesting. Could I just ask you to be so kind to elaborate a little further; that is, how do I set the switch you are talking about? – Guidone Apr 04 '20 at 17:52
  • You can define a new switch (or boolean macro, or how you want to name it) with using \newif\ifGuidoneInSingleQuotes and \newif\ifGuidoneInDoubleQuotes then you use \GuidoneInSingleQuotestrue in the literal of ' and \GuidoneInDoubleQuotestrue in the literal of ". You can then check whether you're currently in quotes using \ifGuidoneInSingleQuotes <true>\else <false>\fi. – Skillmon Apr 04 '20 at 18:35
  • @Skillmonlikestopanswers.xyz Wow, I'm sorry man, but do you think it would be toooo much to ask for a sort of MWE, because I'm afraid I'm not that familiar with the \newif control structure; that is, do I write literate = {"}{_what do I put here?_}. Thanks for your support, really appreciated. – Guidone Apr 04 '20 at 20:34
  • If you could provide some code for me to play with I'd try things (hah, turned the table, now you have to provide an MWE). In general questions asking for solutions should show the problem in a way such that possible answerers can copy your code and see the problem. – Skillmon Apr 04 '20 at 20:43
  • @Skillmonlikestopanswers.xyz I'm sorry, you' re right, so I re-edited my post and added the all MWE. Thanks for your patience. – Guidone Apr 05 '20 at 06:24
  • Even if it is involving, I would do that via Pygments and minted. – projetmbc May 01 '21 at 12:16

1 Answers1

3

Well, for some reason I missed a relevant Q&A: Emphasize (color) contents between two delimiters in listings, but not the delimiters themselves which contains the answer to part of my problem. So, accordingly, I've modified the MWE as follows:

\documentclass{article}
\usepackage{fontspec}
\usepackage{longtable, booktabs}
\usepackage{listings, listings-ext, listingsutf8}
\usepackage[
                usenames,%
                svgnames,%
                dvipsnames,%
                x11names]{xcolor}

\setmainfont{Tisa OT}
\setsansfont{TeX Gyre Heros Cn}
\setmonofont{Fira Code}


%
% general listing colors
%
\definecolor{listing-background}{HTML}{F7F7F7}
\definecolor{listing-rule}{HTML}{B3B2B3}
\definecolor{listing-numbers}{HTML}{B3B2B3}
\definecolor{listing-text-color}{HTML}{000000}
%\definecolor{listing-keyword}{HTML}{435489}
\definecolor{listing-keyword}{RGB}{95,95,211}
\definecolor{listing-keyword-2}{HTML}{1284CA} % additional keywords
\definecolor{listing-keyword-3}{HTML}{9137CB} % additional keywords
\definecolor{listing-identifier}{HTML}{435489}
\definecolor{listing-string}{HTML}{00999A}
\definecolor{listing-comment}{HTML}{8E8E8E}
%===============================%
%% Here the suggested solution %%
%
\def\beginlstdelim#1#2#3%
{%
    \def\endlstdelim{#2\egroup}%
    \small\ttfamily#1\bgroup\color{#3}\aftergroup\endlstdelim%
}
%===============================%
%
% (X)BNF Colors
%
\definecolor{xbnf-symbol}{RGB}{95,95,211}

\lstdefinestyle{etturaz_listings_style}{
    language         = scala,
    numbers          = left,
    xleftmargin      = 2.7em,
    framexleftmargin = 2.5em,
    backgroundcolor  = \color{white},
    basicstyle       = \color{listing-text-color}\linespread{1.0}\small\ttfamily,
    breaklines       = true,
    frame            = single,
    framesep         = 0.19em,
    rulecolor        = \color{listing-rule},
    frameround       = ffff,
    tabsize          = 3,
    numberstyle      = \color{listing-numbers},
    aboveskip        = 1.0em,
    belowskip        = 0.1em,
    abovecaptionskip = 0em,
    belowcaptionskip = 1.0em,
    keywordstyle     = {\color{listing-keyword}\bfseries},
    keywordstyle     = {[2]\color{listing-keyword-2}\bfseries},
    keywordstyle     = {[3]\color{listing-keyword-3}\bfseries\itshape},
    sensitive        = true,
    identifierstyle  = \color{listing-identifier},
    commentstyle     = \color{listing-comment},
    stringstyle      = \color{listing-string},
    showstringspaces = false,
    escapeinside     = {/*@}{@*/}, % Allow LaTeX inside these special comments
%   mathescape       = true,
    literate         = {«}{{\guillemotleft}}1 {»}{{\guillemotright}}1
    {…}{{\ldots}}1 {≥}{{>=}}1 {≤}{{<=}}1 {„}{{\glqq}}1 {“}{{\grqq}}1
    {”}{{''}}1 
}
\lstset{style=etturaz_listings_style}


\lstdefinelanguage{Scala}{
    morekeywords={
        % normal keywords (without data types)
        abstract, case, catch, class, def, do, else, extends, false, final,
        finally, for, forSome, if, implicit, import, lazy, macro, match, new,
        null, object, override, package, private, protected, return, sealed, 
        super, this, throw, trait, try, true, type, val, var, while, with, yield, 
        _, :, ;, =, <-, <:
    },
    morekeywords={[2] % data types
        String, Boolean,Byte,Character,Double,Float,Integer,Long,Short, Number,BigDecimal,BigInteger
    },
    morekeywords={[2] % data types
        Seq, List, Map
    },
    otherkeywords = {=>, {, }, (, ) },
    sensitive,
    morecomment  = [l]//,
    morecomment  = [s]{/*}{*/},
    morecomment  = [s]{/**}{*/},
%
    morestring   = [b]',
    morestring   = [s]{"}{"},
    alsoletter   = {\%},
    literate     = 
        {+=}{{{\color{listing-keyword}+=}}}2
        {=>}{{{\color{listing-keyword}=>}}}2
        {<\%}{{{\bfseries\color{listing-keyword}<\%}}}2
        {\{ }{{{\bfseries\color{listing-keyword}\{}}}1
        {[}{{{\bfseries\color{listing-keyword}[}}}1
        {()}{{{\bfseries\color{listing-keyword}(}}}1
        {)}{{{\bfseries\color{listing-keyword})}}}1
        {]}{{{\bfseries\color{listing-keyword}]}}}1
        {\} }{{{\bfseries\color{listing-keyword}\}}}}1
        {:}{{{\bfseries\color{listing-keyword}:}}}1
        {=}{{{\bfseries\color{listing-keyword}=}}}1
}

\lstdefinelanguage{xbnf}{
    keywordstyle     = {\color{xbnf-symbol}\bfseries},
    morekeywords={
        % normal keywords (without data types)
        {::=}
    }
    sensitive,
    morecomment  = [l]//,
    morecomment  = [s]{(*}{*)},
    morestring   = [b]',
%===============================%
%% Here the suggested solution %%
%
    moredelim = **[is][{\color{red}\beginlstdelim{"}{"}{listing-identifier}}]{"}{"},
    moredelim = **[is][{\color{red}\beginlstdelim{'}{'}{listing-identifier}}]{'}{'},
%===============================%
    literate     =
%       {::=}{{{\bfseries\color{xbnf-symbol}::=}}}3
        {|}{{{\bfseries\color{xbnf-symbol}|}}}1
        {\{ }{{{\bfseries\color{xbnf-symbol}\{}}}1
        {[}{{{\bfseries\color{xbnf-symbol}[}}}1
        {()}{{{\bfseries\color{xbnf-symbol}(}}}1
        {)}{{{\bfseries\color{xbnf-symbol})}}}1
        {]}{{{\bfseries\color{xbnf-symbol}]}}}1
        {\} }{{{\bfseries\color{xbnf-symbol}\}}}}1
}


\begin{document}
%   \lstset{language=Scala}
    \begin{lstlisting}[language=Scala]
        /**
         * A small snippet taken from Cat UG
         */
        def stringDivideBy(aStr: String, bStr: String ) : Option[Int] =
            parseInt(aStr).flatMap { aNum =>
                parseInt(bStr).flatMap { bNum =>
                    divide(aNum, bNum)
                }
            }
        val str: String = "This is a string"
    \end{lstlisting}

    \begin{lstlisting}[language=xbnf]
        json ::= element
        value ::= object | array | string | number | "true" | "false" | "null"
        (* So here the two apostrophes in '{' should be green and the bracket black *)
        object ::= '{tests' ws '}' | '{' member {',' member} '}'
        member ::= ws string ws ':' element
        array ::= '[' ws ']' | '[' element {',' element} ']'
        element ::= ws value ws
        (* Here, again, two green black and the double quote black*)
        string ::= '"' '"' | character {character} '"'
        character ::= 'A' | ... | 'Z' | 'a' | ... | 'z' | escape
    \end{lstlisting}

\end{document}

Which gives me the following result: enter image description here

Still, as you can see, there is still a couple of problems:

  • The starting delimiter is followed by a very nasty whitespace, and I cannot figure out why, even because when I run the snippet taken from the solution of referred question, everything works fine;
  • The double and single quotes, once defined as delimiters, cannot be used also as regular text.

Any idea? Thanks

Guidone
  • 127