listingsの言語を追加する

めっちゃブログサボってます。

TeXlistingsは便利ですよね。 TeX文書内にソースコードシンタックスハイライト付きで よしなに表示するためのパッケージです。 情報系の学生御用達のパッケージですよね。

ですが、わりと標準で対応してる言語が少ないようにも思います。 以前、Schemeを使って関数プログラミングの思想を学ぶ感じの講義で レポートを書くときに、対応してないじゃん、ってなった記憶があります。

もちろん、そういうことにはちゃんと対応していて、 言語設定を追加することができます。 上記の講義レポートに関してはググッて出てきた設定を使うだけで十分だったのですが、 ちょっと自分でそういう設定を書かなきゃいけなかったので、 備忘録代わりに書いておきます。

……まあ、マニュアル読めば分かるんですけど、 毎回英語ドキュメント読むのもかったるいし、 日本語文献少ない気がするのでこういうこと書いていてもいいかなあという感じで 雑に書きます。

概形

lstdefinelanguageというものを使って定義します。

\lstdefinelanguage{言語名}{
  キー名=値,
  キー名=値,
  キー名=値,
  ...
}

最初の引数に言語名(後でソースコード貼り付けるときに使う)を設定して、 次の引数に色々と設定を書いていきます。 なんか言語名の前にオプションを設定できるみたいなんですけど、 よくわからないので飛ばします。

キーワードの追加

morekeywordsというキーに値を設定していきます。 例えばJavaScriptを例にするとこんな感じ。*1

\lstdefinelanguage{javascript}{
  morekeywords = [1]{ %keywords
    await, break, case, catch, class, const, continue, debugger, default, delete, 
    do, else, enum, export, extends, finally, for, function, function*, if, implements, import, in, 
    instanceof, interface, let, new, package, private, protected, public, return, static, super,
    switch, this, throw, try, typeof, var, void, while, with, yield, yield*
  },
  morekeywords = [2]{ %literal
    false, Infinity, NaN, null, true, undefined
  },
  morekeywords = [3] { %Classes
    Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array,
    Function, Generator, GeneratorFunction, Int16Array, Int32Array, Int8Array, InternalError,
    JSON, Map, Math, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect,
    RegExp, Set, String, Symbol, SyntaxError, TypeError, URIError, Uint16Array, Uint32Array,
    Uint8Array, Uint8ClampedArray, WeakMap, WeakSet
  },
  sensitive = true
}

{}の中にカンマ区切りでキーワードを追加していきます。 [1]などのオプションは後でシンタックスハイライトなどの設定をするときに スタイルを別に付けることを可能にするためにつけておくと嬉しいかもです。

本当はkeywordsというキーにキーワードを設定して、 morekeywordsでキーワードを追加、deletekeywordsでキーワードを削除 とやるようなんですが、別の言語設定をベースに言語設定を定義する際にkeywordsを使われていると ベース言語のkeywordsの設定がぶっ飛ばされるのかなんかでこういう使われ方している方が多いみたいです。

sensitiveっていうのをtrueにしておくと、 大文字小文字を区別してくれます。

使える文字について

listingsの中ではアルファベットはletter、数字はdigitというように文字がクラス分けされていて、 通常ではletterとdigitの組み合わせで成り立つキーワードしか追加できません(リストに入れてても無視される)。 CSSfont-heightのように記号を含むようなキーワードを追加したいときは

  alsoletter = {-},

のようにalso<class>というキーに記号を追加すれば大丈夫っぽいです。

文字列・コメントの設定

文字列・コメントの設定もキーワード同様、morestringmorecommentsを使って定義します。

  morecomment = [l]{//},
  morecomment = [s]{/*}{*/},
  morestring = [b]{"},
  morestring = [b]{'},

morecomments[l]{<pattern>}は行コメント、 morecomments[s]{<begin>}{<end>}複数行コメントです。 似たようなものにmorecomments[n]{<begin>}{<end>}というものもあって、 こちらはネスト可能な複数行コメントらしいです。

morestringの方は文字列として表現するために囲むときの記号を指定します。 オプションはその記号を文字列に含む際の方法を指定するもので、 [b]はバックスラッシュでエスケープ、[d]は2つ続けるとエスケープされます。

JavaScriptの完成形

以上の設定を組み合わせるとそこそこうまくいきそうなJavaScriptの設定になります。

\lstdefinelanguage{javascript}{
  morekeywords = [1]{ %keywords
    await, break, case, catch, class, const, continue, debugger, default, delete, 
    do, else, enum, export, extends, finally, for, function, function*, if, implements, import, in, 
    instanceof, interface, let, new, package, private, protected, public, return, static, super,
    switch, this, throw, try, typeof, var, void, while, with, yield, yield*
  },
  morekeywords = [2]{ %literal
    false, Infinity, NaN, null, true, undefined
  },
  morekeywords = [3] { %Classes
    Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array,
    Function, Generator, GeneratorFunction, Int16Array, Int32Array, Int8Array, InternalError,
    JSON, Map, Math, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect,
    RegExp, Set, String, Symbol, SyntaxError, TypeError, URIError, Uint16Array, Uint32Array,
    Uint8Array, Uint8ClampedArray, WeakMap, WeakSet
  },
  morecomment = [l]{//},
  morecomment = [s]{/*}{*/},
  morestring = [b]{"},
  morestring = [b]{'},
  alsodigit = {-},
  sensitive = true
}

使ってみる

オプション付きでキーワードを追加すると、色んなスタイルが適応できてイケです。

\documentclass[a4j]{jsarticle}
\usepackage[dvipdfmx]{color} %dvipdfmxを使わない人はよしなに変更すべし
\usepackage{listings}

% solarized
\definecolor{base}{gray}{0} %black
\definecolor{comment}{rgb}{0.52,0.60,0.00} %green
\definecolor{string}{rgb}{0.83,0.21,0.51} %magenta
\definecolor{keyword1}{rgb}{0.15,0.55,0.82} %blue
\definecolor{keyword2}{rgb}{0.80,0.29,0.09} %orange
\definecolor{keyword3}{rgb}{0.71,0.54,0.00} %yellow
\definecolor{keyword4}{rgb}{0.42,0.44,0.77} %violet[f:id:e8l:20151129232557p:plain][f:id:e8l:20151129232557p:plain][f:id:e8l:20151129232557p:plain]

% 上記コードのJavaScriptの言語設定がされてる

\lstset
{
    basicstyle={\ttfamily\color{base}\scriptsize},%コードの基本書式
    keywordstyle=[1]{\color{keyword1}\textbf},%キーワード1のスタイル
    keywordstyle=[2]{\color{keyword2}\textbf},%キーワード2のスタイル
    keywordstyle=[3]{\color{keyword3}\textbf},%キーワード3のスタイル
    keywordstyle=[4]{\color{keyword4}\textbf},%キーワード4のスタイル
    commentstyle={\gtfamily\scriptsize\color{comment}},%コメントのスタイル
    stringstyle={\gtfamily\scriptsize\color{string}},%文字列のスタイル
    numbers=left,%行番号は左
    stepnumber=1,%一行ずつ行番号をふる
    numberstyle={\sffamily\scriptsize},%行番号の書式
    xleftmargin=0zw, %左余白
    xrightmargin=0zw,%右余白
    tabsize=4,%タブの空白数
    frame=single,%フレームの書式
    frameround=tttt,%角を丸めるかどうか tで丸める
    breaklines=true,%長くなったら途中で改行
    captionpos=b,%タイトルの位置
    breakindent=10pt,%改行されたときの送り幅
    showstringspaces=false,%文字列中の半角スペースを表示させない
    lineskip=-1pt%通常の文章より行送りを狭くする
}

\begin{document}
\begin{figure}[h]
  \centering
  \begin{lstlisting}[language=javascript]
  // comment 1
  /* comment
       style 2
  */
  var hoge = 1;
  var x = undefined;
  var str = "string";
  var str2 = 'str';
  var cls = new Map();
  \end{lstlisting}
\end{figure}
\end{document}

f:id:e8l:20151129232557p:plain

もっとスゴイ設定とかできるならぜひとも教えて下さい。

*1:実はJavaScriptについて設定を作る必要があったので、そのとき作ったものをそのままサンプルに使っているのは内緒だぞ