[Tex/LaTex] Adding Keywords to Existing Language for Listings Package

highlightingkeywordslistings

I would like to add more keywords to an existing language definition so that when I use \begin{lstlisting} ... \end{lstlisting}, the new keywords are highlighted along with the predefined ones.

This question has been asked many times but I've found that none of the solutions work.

Let's review some of the previous work:

  1. At this question, the selected answer was to either define a new language, or define a new style for the language. But I don't want to define a new language or style. I want to add keywords to an existing language, using the existing styling.

  2. At this other question, marked duplicate, the comment was made to use \lstset{language=Lisp, morekeywords={define}}, which doesn't work (for me). One commenter told the OP to refer to section 3.2 of the manual, which doesn't actually say anything about modifying existing language definitions.

  3. At yet another question, the solution was to not set the keywords but just tell the listings package to emphasize the new list of words, which means you have to duplicate the style for emphasis with the style for keywords.

If any of these solutions is in fact the correct one and it just isn't working for me, then please help me point out what it is that I'm doing wrong. Here is my MWE:

\documentclass{article}
\usepackage{listings}
\begin{document}
Listing 1:
\begin{lstlisting}[language=Haskell, morekeywords={fix}]
fibs = fix ((0:) . scanl (+) 1)
\end{lstlisting}    
Listing 2:
\begin{lstlisting}[language=Haskell]
fibs = fix ((0:) . scanl (+) 1)
\end{lstlisting}
\end{document}

If you process this document, you'll find that the first listing has fix highlighted and the second listing doesn't, because fix is not in the list of predefined keywords. Using morekeywords adds it for that one listing.

enter image description here

I thought adding the following in the preamble (immediately above \begin{document}) would make it apply to all listings, but it doesn't. The output is identical to the output above.

  \lstset{language=Haskell, morekeywords={fix}}

You'll notice this is the same as the recommendation in the second question I referenced above.

How do you do this globally for all listings?

Best Answer

Why morekeywords doesn't seem to work

Your question stems from a misunderstanding of the morekeywords key. Contrary to what you think, writing

\lstset{language=Haskell, morekeywords={fix}}

does not alter the definition of listings' Haskell language. That's why the fix identifier is not highlighted in your second listing.

How to modify an existing language

The listings does not provide a mechanism for "renewing" or modifying an existing language. Of the three approaches you mention, the first one makes the most sense. Note that you don't have to redefine a language from scratch; you can simply define a custom language based on the existing one with your modifications,

\lstdefinelanguage{Haskellana}{%
  language     = Haskell,
  morekeywords = {fix},
}

and then invoke it where needed in place of the original language:

\documentclass{article}

\usepackage{listings}
\lstdefinelanguage{Haskellana}{
  language     = Haskell,
  morekeywords = {fix},
}

\begin{document}
Listing 1:
\begin{lstlisting}[language=Haskellana]
fibs = fix ((0:) . scanl (+) 1)
\end{lstlisting}
Listing 2:
\begin{lstlisting}[language=Haskellana]
fibs = fix ((0:) . scanl (+) 1)
\end{lstlisting}
\end{document}

enter image description here

As a Haskeller, strive for laziness :)

To avoid having to invoke the language for each Haskell listing, I suggest declaring a custom lstlisting environment:

\documentclass{article}

\usepackage{listings}
\lstdefinelanguage{Haskellana}{
  language     = Haskell,
  morekeywords = {fix},
}

\lstnewenvironment{haskellcode}
  {\lstset{language = Haskellana}}
  {}

\begin{document}
Listing 1:
\begin{haskellcode}
fibs = fix ((0:) . scanl (+) 1)
\end{haskellcode}
Listing 2:
\begin{haskellcode}
fibs = fix ((0:) . scanl (+) 1)
\end{haskellcode}
\end{document}