読者です 読者をやめる 読者になる 読者になる

端っこプログラマーの手帳

主にプログラムに関する手記です

Webページでシンタックスハイライト

「この関数以前使ったことあるけど、どんな点に注意すれば良いんだっけ?」

使ったことは覚えているのに詳細は忘れてしまった。プログラムを書いているとよく起こります。 こんなとき自分の過去のコードをすぐに振り返れるようにWeb上で検索できるシステムを作ってみました。

Web上でコードをそのまま表示しても味気なかったため、テキストエディタのようにシンタックスハイライトで見やすくしてみました。 今回は、Web上でシンタックスハイライトを導入する方法を紹介します。

目次

実現したいこと

もう少し具体的に実現したいことを整理しました。

・htmlとPHPが対象となること
・行数を表示したい

検討したJSライブラリ

シンタックスハイライトを調べてみるとJavaScriptのライブラリが多数出てきました。 その中で3つをピックアップして試してみます。

highlight.js

ライブラリは公式サイトから入手できます。

highlight.js
│  highlight.pack.js … メイン処理
│
└─styles            … カラーリング用CSSファイル
       agate.css
       androidstudio.css
       arduino-light.css
       …
ライブラリ読み込み・初期化

カラーリングは、CSSを読み込むことによって指定します。 豊富に用意されているため、公式サイトで表示を確認*1し、好みのものを選択しましょう。 今回は、atom-one-dark を読み込んでみます。あとはJSライブラリを読み込んで初期化します。

<head>
<link rel="stylesheet" href="styles/atom-one-dark.css">
<script type="text/javascript" src="highlight.pack.js"></script>
<script type="text/javascript">
   hljs.initHighlightingOnLoad();
</script>
</head>
ハイライトするコードの設置

codeタグのclass属性で、言語を指定します。*2 コード部分の先頭の改行は、ハイライト後も反映されてしまうのでない方がいいでしょう。 <(小なり)と>(大なり)は、htmlとして解釈されないようにエスケープが必要です。*3

html

<body>
<pre>
<code class="html"><!-- ハイライトしたいコード start--><?php 
$code = <<<EOL
<h4>プルダウン</h4>
<select id="select" name="select">
    <option value="0">丹下段平</option>
    <option value="1" selected>矢吹丈</option>
    <option value="2">マンモス西</option>
    <option value="3">力石徹</option>
    <option value="4">カーロス・リベラ</option>
</select>
EOL;
echo htmlspecialchars($code, ENT_QUOTES, 'UTF-8');
?><!-- ハイライトしたいコード end-->
</code>
</pre>
</body>

php

<body>
<pre>
<code class="php"><!-- コード部分 start-->&lt;?php 
define('ARCHIVE_KEEP_NUM', 5);
$archive_dir = $argv[1];
$list_archive = array();

foreach(glob($archive_dir.'*.tar.gz') as $archivename){
    $created = filemtime($archivename);
    $list_archive[$created] = $archivename;
}<!-- コード部分 end-->
</code>
</pre>
</body>
表示キャプチャ

html
f:id:kzhishu:20170408023814p:plain

php
f:id:kzhishu:20170408023835p:plain

シンプルで悪くないのですが「行数を出せない」「PHPのカラーリングが弱い」という2点で採用は見送りました。

prism.js

ファイルダウンロード

公式サイトから、カラーリング(Themes)・言語(Languages)・プラグイン(Plugins)を指定して 次の2ファイルをダウンロードします。 カラーリング変更やプラグイン追加をするには再度ダウンロードする必要があるようです。「これは使いたいかも」と思ったものは入れておきます。

prism.css
prism.js
① カラーリング(Themes)

公式サイトTOPの Examplesで表示を確認できます。 [DOWNLOAD] 下の[THEME:]を切り替えて試してみましょう。 柔らかな感じで見やすい Coy に決めました。

② 言語(Languages)

知っている言語は全て選択しました。

プラグイン(Plugins)

色々とあるのですが、次の3つを選択しました。

Line Numbers(行番号表示)
Copy to Clipboard (クリップボードにコピー)
Show Language (言語名の表示)
ライブラリ読み込み

単純に読み込むだけで問題ありません。

<head>
    <link rel="stylesheet" href="prism.css">
    <script type="text/javascript" src="prism.js"></script>
</head>
ハイライトしたいコードの設置

<pre><code></code></pre> でハイライトしたいコードを囲う点は、highlight.js と同じです。 言語の指定は、codeタグに、language-[言語コード] のクラス名を付与します。*4 [言語コード]は、TOPページ Supported languages のところに載っています。 preタグの line-numbersクラスは、「Line Numberプラグイン」の機能で行数の表示 codeタグの data-languageクラスは、「Show Languageプラグイン」の言語名タグが表示されます。

html

<body>
<pre class="line-numbers">
<code class="language-html" data-language="html"><!--ハイライトしたいコード start--><?php 
$code = <<<EOL
<h4>プルダウン</h4>
<select id="select" name="select">
    <option value="0">丹下段平</option>
    <option value="1" selected>矢吹丈</option>
    <option value="2">マンモス西</option>
    <option value="3">力石徹</option>
    <option value="4">カーロス・リベラ</option>
</select>
EOL;
echo htmlspecialchars($code, ENT_QUOTES, 'UTF-8');
?><!--ハイライトしたいコード end--></code>
</pre>
</body>

php

<body>
<pre class="line-numbers">
<code class="language-php" data-language="php">&lt;?php 
define('ARCHIVE_KEEP_NUM', 5);
$archive_dir = $argv[1];
$list_archive = array();

foreach(glob($archive_dir.'*.tar.gz') as $archivename){
    $created = filemtime($archivename);
    $list_archive[$created] = $archivename;
}</code>
</pre>
</body>
表示キャプチャ

html
f:id:kzhishu:20170408023859p:plain

php
f:id:kzhishu:20170408023914p:plain

行番号も表示でき、色もきれいですが、次に紹介するJSライブラリの方が用途に合っていたためこちらも採用は見送りました。

google-code-prettify

オートローダー版

オートローダーを読み込み、preタグ内にコードを設置すれば簡単にハイライトを導入できます。

<!DOCTYPE html>
<html>
    <head>
       <title></title>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
       <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
   </head>
    <body>
        <pre class="prettyprint linenums"><?php 
$code = <<<EOL
<h4>プルダウン</h4>
<select id="select" name="select">
    <option value="0">丹下段平</option>
    <option value="1" selected>矢吹丈</option>
    <option value="2">マンモス西</option>
    <option value="3">力石徹</option>
    <option value="4">カーロス・リベラ</option>
</select>
EOL;
echo htmlspecialchars($code, ENT_QUOTES, 'UTF-8');
?>
    </pre>
    </body>
</html>

表示結果
f:id:kzhishu:20170411000148p:plain

… 5行ずつでしか行番号が出ないため、GitHubからコードを入手しカスタマイズしてみます。

GitHub - google/code-prettify: Automatically exported from code.google.com/p/google-code-prettify

ダウンロード

prettify.css と prettify.js を使います。 lang-XXX.js は、デフォルトで非対応の言語のときに読み込む必要がありますが、 今回ハイライトしたい言語には対応しているので使いません。 styles 配下は、カラーリングのテーマを変えることができるようです。 こちらもデフォルトが気にいったので使いません。

code-prettify-master
├─distrib
├─docs
├─examples
├─js-modules
├─loader
│  └─skins
├─src
│      lang-XXX.js    ○ 言語拡張スクリプト
│      prettify.css   ★ メインのCSSファイル
│      prettify.js    ★ メインのJSファイル
│      run_prettify.js
│
├─styles             ○ カラーリング別テーマ
│      desert.css
│      doxy.css
│      sons-of-obsidian.css
│      sunburst.css
├─tasks
│  └─lib
├─tests
└─tools
    └─closure-compiler
1行ずつ行番号を表示

prettify.css 55行目あたりで、5番目・10番目以外のリスト先頭部分を消しており、 以下の通りコメントアウトすることで行番号が表示されるようになります。

/* Specify class=linenums on a pre to get line numbering */
ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */
/*li.L0,
li.L1,
li.L2,
li.L3,
li.L5,
li.L6,
li.L7,
li.L8 { list-style-type: none }*/
ハイライトするコードの設置

head内で、ダウンロード・カスタマイズした prettify.css を読み込みます

<head>
   <title></title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <link rel="stylesheet" href="./prettify.css">
</head>

bodyの閉じタグの前で、prettify.js を読み込み、prettyPrint()でカラーリングを実行します。

<script type="text/javascript" src="./prettify.js"></script>
<script type="text/javascript">
   prettyPrint();
</script>

例のごとく、htmlエスケープしたコードをpreタグで囲います。 prettyprintクラスを付与するとカラーリング対象となります。 また、linenumsクラスで行数を表示します。

html

<pre class="prettyprint linenums"><?php 
$code = <<<EOL
<h4>プルダウン</h4>
<select id="select" name="select">
    <option value="0">丹下段平</option>
    <option value="1" selected>矢吹丈</option>
    <option value="2">マンモス西</option>
    <option value="3">力石徹</option>
    <option value="4">カーロス・リベラ</option>
</select>
EOL;
echo htmlspecialchars($code, ENT_QUOTES, 'UTF-8');
?>
</pre>

php

<pre class="prettyprint linenums">&lt;?php 
define('ARCHIVE_KEEP_NUM', 5);
$archive_dir = $argv[1];
$list_archive = array();

foreach(glob($archive_dir.'*.tar.gz') as $archivename){
    $created = filemtime($archivename);
    $list_archive[$created] = $archivename;
}
</pre>
表示キャプチャ

html
f:id:kzhishu:20170412002642p:plain

php
f:id:kzhishu:20170412002657p:plain

表示は、シャープで見やすいです。言語も自動で判別してくれるてGoodです。 これを採用することに決めました。

*1:style:[カラーリング名] の下線部をクリックするとカラーリングが切り替わります。ダウンロードしたファイルの style/[カラーリング名].css が該当のCSSとなります

*2:言語を指定しないと自動判別されるようです。htmlとphpに関しては各言語クラスを指定したときと同じ表示になりました

*3:同じページでhtmlエスケープを実行したり、html特殊文字でハードコーディングしてますが、実装時にはサーバーサイドでエスケープをかけるべきでしょう

*4:highlight.js と違いクラスを指定しなかったらハイライトされないです