メモを揉め

お勉強の覚書。

はてなブログのシンタックスハイライトにCodeMirrorを使う

はてなブログのコードの表示に個人的になんとなく違和感があって、特にモバイル環境で見た時の折り返しが見難い。
どうにもこういうものは見た目をカスタマイズしたい願望があって、はてなブログはモバイルのデザインをカスタマイズできない*1のがどうにもつらい気持ちがあった。*2

ブログを始めた当初は自分でシンタックスハイライトを作ったりもしたんだけど、最近見たらおもくそバグってたのと、自動化できてないので投稿前に手動でマークアップ済みのHTMLを貼り付けて投稿するのが死ぬほど面倒臭かった。

そしてCoffeeScriptRubySwiftだと徐々に他の言語にも手を出し始めると、いちいちやってられっかぁぁーーーって感じになった。
でも、見た目だけはいっちょ前に気になってしまうので、既存のもので何か良い物はないか探していたのであった。

確かこんなものがあったような気がするリスト

  • SyntaxHighlighter
    結構いろんなブログで見かけたような気がする。
    これにしようかとも思ったんだけど、どこかの記事でソースコード中の<とか&とかをエスケープできていなかったせいで、表示が崩れちゃっているのを見て、なんとなくエスケープは自分で手動なり自動なりでする必要があるなら、あんまり変わらないんじゃないか?と思ってしまったのでやめた。
    あと好みのカラースキームが見つからなそうな感じがした(そこまでちゃんと探してない)。

  • Gist
    これもかなり有力な候補だったんだけど、一度書いてアップしたあとで貼り付けなければならず、ソースコードの細かい修正とかが面倒そうだなっと思ってしまいやめた。
    ある程度まとまったコードならいいけど、一行とかの大量のGistを管理するのは大変そうだし。

    対応言語の多さと新しい言語への対応の早さは信頼出来るので、これからも要所要所で使うと思う。
    エスケープを気にする必要が無いのも良い。

  • はてなブログシンタックスハイライト
    えーと、そうですね、なんか書いてるうちになんかこれでいいんじゃないかって気がしてきてしまったんですけど、エスケープも勝手にやってくれるし、これじゃダメな理由としては、、、う~ん無いですね、なんかあったような気がしたんですけどね。
    どちらかと言うとCodeMirrorでやってみたいっていう技術的好奇心の方が大きくて、はてなブログの機能としての欠点は特に無いです。

  • JSFiddleCODEPEN
    実際に使ってみたことはあるのですが、調子に乗って貼りまくってたらものすごく重くなりました。
    これもGistと同じで管理が大変そうなのと一行とかのソースコードをたくさん貼るのに向かないかなあって。
    シンタックスハイライトのためだけに使うには高カロリー。

CodeMirrorにした理由

とてもパーソナルな理由です。

  • LightTableを使っている
    はい、これ。まずこれなんです。
    メモを揉め: LightTableについて
    LightTableはUIの描画にHTMLが使われていて、ベースにCodeMirrorが使われています。
    CodeMirrorとは、

    CodeMirror is a JavaScript component that provides a code editor in the browser.
    github: CodeMirror

    ブラウザで動作するJavaScript製のエディタ。

    エディタとしての機能はめちゃくちゃ強力なのですが、今回はそれを全く使わず、シンタックスハイライトの機能のみを使おうという魂胆です。
    このCodeMirrorにはたくさんの言語モードが用意されていて、全てプラグイン形式になっています。そして、LightTableではカラースキームとしてこのCodeMirrorのカラースキームがおそらくそのまま使われているっぽくて、どうやら互換性があります。
    ということは、LightTableで使っているカラースキームをCodeMirrorに持ってこれるのでは?と思ってやってみたら見事成功。

    ブログのソースコードを自分のエディタ環境と同じ見た目、同じルールにできるので、だいぶ素敵だと思います。

  • DarkSystemCDというカラースキームがドンピシャ
    たまたまLightTableのプラグインマネージャを開いたら新しいテーマがアップロードされていて、それがこのDarkSystemCDというカラースキーム。

    github: wds-connections/darksystemcd-lighttable-theme

    DarkSystemCD

    かっこいい。
    これをブログでも使いたいというのが理由。

    一応フォントは使い慣れているSouce Code Proに変えました。Courier Newも好きなんだけどね。

MarkDownとの併用

ブログはMarkDownで書いているので、できればその中で完結させたいです。

例えばSyntaxHighlighterのように<pre>にクラスを割り当てて、それにシンタックスハイライトを適用するという仕組みだと、MarkDownでコードブロックを利用した際、クラスを割り当てられません。
回避策としてそこだけHTMLを直に書くという方法も考えましたが、そうすると今度はMarkDownのコードブロックの自動的なエスケープの恩恵を受けられないので、結局別途エスケープする必要が出て振り出しに戻ります。

一つは、<pre>の前にコメントでアノテーションを入れる方法を思いつきましたが、はてなブログだとコメントが除去されちゃうのでNG。

もう一つは<p>要素*3にクラスを割り当てて、その要素をアノテーションにする方法。結局今はこの方法で運用している。

ちなみにこの方法はCodeMirror以外にも応用出来るので、MarkDownと組み合わせたい場合にはいいかもしれないです。

RoomMirrorというモジュールにしました

これらの機能をRoomMirrorというnpmのモジュールにしました。
初めてのnpmモジュールです、緊張してます。

RoomMirror

デモ

カラースキーム + エディタブル

<p class="rm-a" data-eval="{ mode: 'javascript', readOnly: false }"></p>

というアノテーションをコードブロックの直前に書くことでCodeMirrorシンタックスハイライトを行うような仕組みになっています。
data-evalCodeMirrorにオプションを渡せる。

readOnlyfalseを指定しているので以下のデモは全て編集可能です。

darksystemcd

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

monokai

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

solarized
今気づいたけどこれ背景にテクスチャが使われている…。かっこいい。

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

default (in LightTable)
LightTableのデフォルトのテーマです。

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

zenburn

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

paraiso-dark

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

pastel-on-dark

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

the-matrix

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

vibrant-ink

var test = 'test';
/test/i.test(test);
function add(a, b) {
  return a + b;
}
[0, 1, 2, 3, 4].reduce(add, 0); // 10

CodeMirrorLightTableでは、同名のスキームでもかなり違いがありました。
ここでは、同名の物は全てLightTable版のものを使っています。

*1:Proだとできるのかもしれない

*2:設定で<head>内で読み込む物を指定できるので、カスタムCSSを読み込むことは出来る

*3:<div>でもなんでも良いけど空の<span>だとやっぱり除去されちゃうので<p>要素