2016/03/12

marked.js の code highlight を SyntaxHighlighter にする

このブログに marked.js を適用して Markdown でブログを書けるようにしました。 marked.js は Code Highlighter に任意のライブラリを使用できるよう設計されている1ので、これまで通りSyntaxHighlighter を使えるようにしました。

Renderer を定義する

以下のように Renderer の codeプロパティを定義すると、好みの Highlighter でコード装飾をすることができます。

1
2
3
4
5
var renderer = new marked.Renderer();
renderer.code = function(code, lang) {
  return '<pre class="brush: ' + lang + ';">' + code + '</pre>';
};
article.innerHTML = marked(article.innerHTML, {renderer: renderer});

SyntaxHighlighter のパラメータを使えるようにする

SyntaxHighlighter を使うメリットの一つに特定の行を強調表示できるというものがあります。 しかし、Markdown 記法でそういった表示を実現する方法はありません。

SyntaxHighlighter にパラメータを与えつつ、他の Markdown 記法に移行しても使える方法を模索した結果、 最初の一行が `だった場合、それをパラメータとして使うという方式に落ち着きました。

コードは以下です。

1
2
3
4
5
6
7
8
9
10
11
12
13
var renderer = new marked.Renderer();
renderer.code = function(code, lang) {
  // 1行目が ` で始まっているかどうか確認
  params = code.match(/^`(.+)\n/);
  if (params != null) {
    // 1行目を削除
    code = code.replace(/^`.+\n/, '');
    return '<pre class="brush: ' + lang + ';' + params[1] + '">' + code + '</pre>';
  } else {
    return '<pre class="brush: ' + lang + ';">' + code + '</pre>';
  }
};
article.innerHTML = marked(article.innerHTML, {renderer: renderer});

Markedown の記述

```java
`highlight: 1;
private int x = 0;
private int y = 1;
```

実行結果

1
2
private int x = 0;
private int y = 1;

他の問題も修正

使ってみると、その他にもうまく行かない場合があったので、それらを回避するコードを追加しました。 具体的には以下のようなケースです。

  • Language 指定しなかった場合エラーになる
  • XML 等タグを含む場合表示が崩れる

最終コードは以下になりました2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var renderer = new marked.Renderer();
renderer.code = function(code, lang) {
  // lang 指定が無かったら text にする
  if (!lang) {
    lang = 'text';
  }
  // タグをリプレース
  code = code.replace(/</g, '&lt;').replace(/>/g, '&gt;');
  // 1行目が ` で始まっているかどうか確認
  params = code.match(/^`(.+)\n/);
  if (params != null) {
    // 1行目を削除
    code = code.replace(/^`.+\n/, '');
    return '<pre class="brush: ' + lang + ';' + params[1] + '">' + code + '</pre>';
  } else {
    return '<pre class="brush: ' + lang + ';">' + code + '</pre>';
  }
};
$('.marked').each(function(i, val) {
  txt = val.innerHTML.replace(/(\n+)&gt;|^&gt;/g, '$1>');
  val.innerHTML = marked(txt, {renderer: renderer});
});

  1. 素晴らしい! 
  2. このコードを Markdown から直接コピペすると正しく動作しません。
    Syntax Highlighter で処理した時に正しく表示されるようにしています。 
?

0 件のコメント: