21

I'm trying to highlight simple YAML (the markup language, not the CSS framework) code. I know that there is a solution using pygments and minted, however, I would prefer a solution with \lstdefinelanguage.

This is my code so far:

\lstdefinelanguage{yaml}{
  keywords={true,false,null,y,n},
  keywordstyle=\color{darkgray}\bfseries,
  ndkeywords={},
  ndkeywordstyle=\color{black}\bfseries,
  identifierstyle=\color{black},
  sensitive=false,
  %moredelim=[l]{}{:},
  comment=[l]{#},
  morecomment=[s]{/*}{*/},
  commentstyle=\color{purple}\ttfamily,
  stringstyle=\color{blue}\ttfamily,
  %morestring=[l]{-}{},
  morestring=[b]',
  morestring=[b]"
}

Two things are missing, though:

  1. I would like to print all keys bold
  2. I would like to print all strings, also the ones without qotes, to be blue.

I tried to accomplish these two things with the commented lines in the code above. Unfortunately, they did not work. Any suggestions on how I can make this work?

Here is a small YAML example:

key: value
map:
    key1: value1
    key2: value2
list:
  - element1
  - element2
# This is a comment
listOfMaps:
  - key1: value1a
    key2: value1b
  - key1: value2a
    key2: value2b

This is the output I currently get:

enter image description here

  • 1
    Could you define "all strings, also the ones without quotes"? I'm not familiar with YAML and from the wikipedia page I cannot understand what other strings there are, apart from those in single or double quotes. – nickie Jan 7 '14 at 16:20
  • I had a bad experience with listings and YAML in a manual I wrote; I used some delimiters in order to achieve syntax highlighting, but it's quite messy. Take a look at minted, it relies on pygments under the hood and it has built-in YAML support. – Paulo Cereda Jan 7 '14 at 16:28
  • 1
    Unfortunately, because YAML uses no delimiters for its keys, you'll have a hard time implementing the key style you want. One solution would be to declare all the key names you use as listings' keywords, and set the style for those keywords as you wish. Not a very satisfying solution but viable if the number of distinct key names is small. – jub0bs Jan 7 '14 at 16:33
  • @nickie Sorry for not being clear on that. In YAML, the types of values are inferred and thus, strings are mostly not enclosed by quotes. key: value and key: "value" are equivalent, value is a string for both. I would like to color strings, either with or without quotes, in the same color. I hope, this makes it clear. – str Jan 7 '14 at 16:40
  • @Jubobs I might consider that as a fallback. And thanks for the edit. – str Jan 7 '14 at 16:41
19

Here is a partial solution involving some juggling with the literate and moredelim keys. The values, if delimited by double quotes, can contain colons.

Caveat: values that span multiple lines won't be correctly highlighted.

enter image description here

\documentclass{article}

\usepackage[dvipsnames]{xcolor}
\usepackage{listings}

\newcommand\YAMLcolonstyle{\color{red}\mdseries}
\newcommand\YAMLkeystyle{\color{black}\bfseries}
\newcommand\YAMLvaluestyle{\color{blue}\mdseries}

\makeatletter

% here is a macro expanding to the name of the language
% (handy if you decide to change it further down the road)
\newcommand\language@yaml{yaml}

\expandafter\expandafter\expandafter\lstdefinelanguage
\expandafter{\language@yaml}
{
  keywords={true,false,null,y,n},
  keywordstyle=\color{darkgray}\bfseries,
  basicstyle=\YAMLkeystyle,                                 % assuming a key comes first
  sensitive=false,
  comment=[l]{\#},
  morecomment=[s]{/*}{*/},
  commentstyle=\color{purple}\ttfamily,
  stringstyle=\YAMLvaluestyle\ttfamily,
  moredelim=[l][\color{orange}]{\&},
  moredelim=[l][\color{magenta}]{*},
  moredelim=**[il][\YAMLcolonstyle{:}\YAMLvaluestyle]{:},   % switch to value style at :
  morestring=[b]',
  morestring=[b]",
  literate =    {---}{{\ProcessThreeDashes}}3
                {>}{{\textcolor{red}\textgreater}}1     
                {|}{{\textcolor{red}\textbar}}1 
                {\ -\ }{{\mdseries\ -\ }}3,
}

% switch to key style at EOL
\lst@AddToHook{EveryLine}{\ifx\lst@language\language@yaml\YAMLkeystyle\fi}
\makeatother

\newcommand\ProcessThreeDashes{\llap{\color{cyan}\mdseries-{-}-}}

\begin{document}

\begin{lstlisting}[language=yaml]
---
key: value
map:
    key1: "foo:bar"
    key2: value2
list:
  - element1
  - element2
# This is a comment
listOfMaps:
  - key1: value1a
    key2: value1b
  - key1: value2a
    key2: value2b
---
\end{lstlisting}

\begin{lstlisting}[frame=single]
some
other
listing
\end{lstlisting}

\end{document}
|improve this answer|||||
  • 4
    Wow, it's awesome! :)` – Paulo Cereda Jan 16 '14 at 9:17
  • Is there any way to make that \lst@AddToHook{EOL}{\YAMLkeystyle} be yaml-specific? As of now, it's destroying the highlighting for other languages as well: i.stack.imgur.com/28HCE.png – Sean Allred Apr 4 '14 at 18:06
  • @SeanAllred See my edit. – jub0bs Apr 4 '14 at 20:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.