sci

最果て風呂

Windows や OS X 環境で Vim と Emacs から軽量マークアップを使う

GitHub を使うようになったのだけど、Readme を書いたりコメントをする際に Markdown 記法を使えると便利ということなので勉強することにした。自分ははてな記法を使っているのでこういった軽量マークアップの便利さは体感しているのだけど、書式が似ていることもあり間違えることが多い。手元でプレビューができればいいなぁと思い環境構築をすることにした。

検索結果から訪問された方で、もし私と同じような現象でお困りでしたら、最後のまとめを先に読んで試してみてください。解決すればしめたものですが、解決しなければ以下の文章を読むのは無駄になってしまいます。

軽量マークアップ事はじめ

まずは Emacs で確認できるようにした

手順は下記の通り。

  • daringfireball.net から Markdown_1.0.1 をダウンロードして中にある Markdown.pl を ~/bin 以下にコピー
  • jblevins.org/projects/markdown-mode から markdown-mode.el をダウンロードして ~/elisp 以下にコピー
  • .emacs.d/init.el にごにょごにょ
  • C-c C-c m で html ファイルを生成し、C-c C-c p で w3m にて閲覧(ちなみに C-c C-c p のみでも、自動的に生成してからブラウザで表示してくれる)

解説の通りにすればトラブルもなく動作した。

次は Vim から確認できるように

Vim でも QuickRun を使えば markdown ファイルを開いて「\r」とすることにより自動的に動作する。Emacs と違うのは、ヘッダやら何やらが付加されないので、そのままでは閲覧することが出来ないことかな?たぶん設定があるはずなので、これから調べてみる。

Windows Vim ではシェバングをいじってないのに Markdown.pl が動いた。'command' の部分も ‘Markdwon.pl’ のままで ‘perl ~/bin/Markdown.pl’ のような修正をしていないのにっ!すげ〜どんな仕組みだ?他にも変換するプログラムがたくさんあるみたい。これも調べてみよう。

PDCA ではないけれど、問題発生→調査→知識が増えるのサイクルになってお得。素直に動かない方が自分にとっては良いのかな?生業にしていない者には無駄な知識ではあるけどね(^_^;)。

あ、今頃気が付いたけど、Vimプラグインの autoload フォルダって Emacs でいうところの load-path で設定したフォルダのことで、(autoload ‘markdown …) と同じように使う時になって初めて自動的に読み込むのか。でも同じ階層にある plugin との違い違いがわからないな。autoload から plugin 以下のファイルが呼び出されるのか?

kramdown を試してみる

ここから先は Windows 上での話し(iBook にはあまり gem を入れたくない)。Markdown.pl は 2004 年製なので、新しそうな kramdown というものを試してみる。これは Ruby のライブラリとのことで、

sudo gem install kramdown

とすればインストールすることが出来る。HTML だけではなく LaTeX への出力もできるし、拡張表現として定義リストも認識できるんだって、すっげ〜(でも github では使えるのかな)。~/bin/Markdown.pl をパスから外して「\r」としてみると、

ruby.exe: No such file or directory -- c:/hoge/kramdown (LoadError)

となってしまった。何が見付からないんだ?QuickRun では

'type': executable('Markdown.pl') ...
        executable('kramdown') ...

のように実行ファイルの存在を順番に確認していってるので、実行ファイルとしての kramdown は認識しているわけだよねぇ。

:echo executable(kramdown')
 => 1

のように返事がくるし。シェル上で単に

kramdown README.md

とすると変換されたものが出力されるので、プログラムの動作は問題ない(あれ、こっちの方がタグ付けが綺麗?)。ということは、

'command': 'kramdown',

のところを修正する必要があるのか。そもそも gem ってどこにインストールされるの?あったあった、

Ruby193/lib/ruby/gems/1.9.1/gems/kramdown-0.13.4/bin/kramdown

こんな深いところにあった。でもここにはパスを通してないんだけど。ん〜、

Ruby193/bin/kramdown.bat

というのを発見!こんな浅い所に…。Windows は難しい。ということで、

'command': 'kramdown',
 => 'command': 'c:\Ruby193\bin\kramdown',

のように QuickRun 側を修正すると動くようになった。いつも思うことなんだけど、パスの区切りをスラッシュにするのかバックスラッシュにするのか迷ってしまう。Windows Vista 以降はスラッシュになったんだっけか?

先日 Windows で入れた kramdown だけれど、定義リストを使いたくて MacOSX にも入れちゃった。う〜んなんか動かん。ターミナルから使うと動くのだけど、Emacs から起動させるとエラーになってしまう。起動初期に時間がかかるので、やっぱり Perl版の Markdown.pl と比べると速度はかなり遅い感じ。

kramdown で日本語を含むものが変換できない

MacOSXEmacs から kramdown を呼び出して使うとエラーになってしまう件。Windows でも再現した。どうやら日本語が含まれているとエラーになるみたい。状況をまとめてみると下記のようになった。

MacOSX

デフォルトでの挙動

作業 結果
Yash 上での変換 OK
Vim から quickrun を通しての変換 OK
Emacs から markdown-mode を通しての変換 NG

入力ファイル UTF-8、ターミナル UTF-8

cat README.md | nkf -s | kramdown              => NG 処理されない
cat README.md | nkf -j | kramdown | nkf32 -w   => NG 文字化け
cat README.md | nkf -e | kramdown              => NG 処理されない
cat README.md | nkf -w | kramdown              => OK

エラー内容

gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:101:in `gsub': invalid byte sequence in UTF-8 (ArgumentError)
from gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:101:in `adapt_source'
from gems/kramdown-0.13.4/lib/kramdown/parser/kramdown.rb:101:in `parse'
from gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:78:in `parse'
from gems/kramdown-0.13.4/lib/kramdown/document.rb:90:in `initialize'
from gems/kramdown-0.13.4/bin/kramdown:72:in `new'
from gems/kramdown-0.13.4/bin/kramdown:72:in `<top (required)>'
from /usr/local/bin/kramdown:19:in `load'
from /usr/local/bin/kramdown:19:in `<main>'

Windows

デフォルトでの挙動

作業 結果
bash 上での変換 NG
Vim から quickrun を通しての変換 NG
Emacs から markdown-mode を通しての変換 NG

入力ファイル UTF-8、ターミナル CP932

cat README.md | nkf32 -s | kramdown              => OK
cat README.md | nkf32 -j | kramdown | nkf32 -s   => 文字化け(01/27訂正)
cat README.md | nkf32 -e | kramdown | nkf32 -s   => NG 処理されない(01/27訂正)
cat README.md | nkf32 -w | kramdown              => NG 処理されない

エラー内容

gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:101:in `gsub': invalid byte sequence in Windows-31J (ArgumentError)
gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:101:in `adapt_source'
gems/kramdown-0.13.4/lib/kramdown/parser/kramdown.rb:101:in `parse'
gems/kramdown-0.13.4/lib/kramdown/parser/base.rb:78:in `parse'
gems/kramdown-0.13.4/lib/kramdown/document.rb:90:in `initialize'
gems/kramdown-0.13.4/bin/kramdown:72:in `new'
gems/kramdown-0.13.4/bin/kramdown:72:in `<top (required)>'
Ruby193/bin/kramdown:19:in `load'
Ruby193/bin/kramdown:19:in `<main>'

文字コードを疑う

挙動が一意に決ってない…。当初は Emacs から kramdown へ渡すバッファに問題があると思っていたのだけど、色々と調べてみると Vim でも shell でもダメな場合があるので、kramdown の方に問題がありそう。だって PerlMarkdown.pl を利用する場合は問題が出ないんだもの。文字コードの問題なのか…。

MacOSX ではファイルの権限とかがあって編集するのが面倒なので、Windows で kramdown ライブラリを調べてみる。こういう時は便利だね、Win。エラーとなっている場所は下記の部分。

def adapt_source(source)
  source.gsub(/\r\n?/, "\n").chomp + "\n"
end

source って読み込んだ行のことだと思うのだけど、それの改行を改行に置換してさらに改行を削除して改行を付加してるってこと?ってかこのソース、80 行で改行されてないから読み難い。それにクラスを使ったこともないし、複数ファイルも使ったことないのでさっぱりわからん。とりあえず改行の種類だけまとめておこう。

環境 改行
UNIX, MacOSX \n
Windows \r\n
Under OS9 \r

Windows での作業

この前の続き(Windows での作業)。文字コードは良く(いや全く)わからないのだが。

def adapt_source(source)
  puts Encoding.default_external
  puts Encoding.default_internal
  puts source.encoding
  source.gsub(/\r\n?/, "\n").chomp + "\n"
end

上記のようにしてターミナルから実行してみると、nkf32 のオプションが「-s, -j, -e」の全てにおいて

Encoding.default_external  => Windows-31J
Encoding.default_internal  =>
source.encoding            => Windows-31J

の結果を得た。「-w」の場合はエラーとなる。あの…開いているファイルは UTF-8 なんですけど…(nkf32で変換したものまで)内部で「Windows-31J」に変換されてしまうの?

「source.encode(“utf-8”)」として文字列自体を変換してしまうとエラーになるので、下記のように文字コード情報だけを変更させると、うまいこと変換された(String の実際の文字コード文字コード情報の不一致がどうして生じるのかは不明)。

def adapt_source(source)
  source.force_encoding('utf-8')
  source.gsub(/\r\n?/, "\n").chomp + "\n"
end

ただしこうすると、今度は utf-8 以外のファイルでエラーが発生してしまう。個人的には UTF-8 ONLY の環境だし、VimEmacs からの変換が出来るようになったのは大きい。bash では nkf32 を使って変換してやれば良いのだし、サーバ上で運用するとか無いからこれで行くことにする。

作業 結果
Vim から quickrun を通しての変換 OK
Emacs から markdown-mode を通しての変換 OK
bash 上での変換 OK

ただし、

文字コードが UTF-8 の場合は
kramdown README.md

それ以外の場合は
cat README.md | nkf32 -w | kramdown

とする。

MacOS X での作業

この前の続き。Windows 上での実験を踏まえて、今回は MacOSX で調整する。Windows の時と違うのは、現時点で quickrun on Vim が問題なく動いていること。Emacs のみが問題なのだ。

gem 以下のファイルを編集するのだけど、権限の問題があって Emacs では編集しづらい。こういう時は sudo を使って瞬時に起動・終了ができる Vim は便利。ちなみに quickrun on Vim および、kramdown README.md on Yash での状況は下記の通り。

Encoding.default_external  => UTF-8
Encoding.default_internal  =>
source.encoding            => UTF-8

さて、Emacs から markdown-mode を利用して変換をすると、

Encoding.default_external  => US-ASCII
Encoding.default_internal  =>
source.encoding            => US-ASCII

のようになっていた。あれ?やっぱり emacs から kramdown へのバッファ渡しがおかしいのか。そうだよね〜、たくさん使われているプログラムなんだから、エラーで動かないとなったら情報がたくさんあるハズだものね〜。ネットでの情報が無いわけだ。Emacs のバージョンが 22 というのもあるのかもしれないけど、結論は「自分の環境が特殊」ってことか。

これどうしよう…。kramdown には問題がないようなので、手を付けるのはやめておこう。gem だから(他のgem updateで)知らずにアップデートされてしまう可能性もあるし…。よし、このままにしておく。修正すべきは markdown-mode の方だろうけど、Emacs Lisp を読むのも辛いのでそのままにしておく。

解決策。「Yash および Vim での変換には kramdown を使い、Emacs からの変換には Perl スクリプトである Markdown.pl を使う」こと。ただしこの場合、quickrun での優先順位を変更させる手間が必要となる(先日の順番を上下入れ替えるだけ)。

小細工をしてみる

先日の続き。Emacsmarkdown-mode から呼び出す専用物として、/usr/local/bin/kramdown~/bin/em-kramdown のようにコピーし、その em-kramdwon のシェバングを

#!/usr/local/bin/ruby
 => #!/usr/loca/bin/ruby -Ku

のように修正し、さらに ~/emacs.d/init.el の設定部分でこの改造 em-kramdown を利用するように、

(setq markdown-command "~/bin/em-kramdown")

と設定すれば使えるようになる。

はじめは init.el のみを弄って

(setq markdown-command "ruby -Ku /usr/local/bin/kramdown")

としたのだけど、

/usr/local/bin/kramdown:9:in `require': No such file to load -- rubygems (LoadError)
    from /usr/local/bin/kramdown:9

のようなエラーが生じてしまいうまくいかなかったのでした。

ちなみに Windows で試してみるとエラーも出ずに変換されたので、gem を修正する方法はやめて元に戻した。オプションで解決できるならその方が良いから。残るは Vim 側なんだけど、quickrun のオプション設定を良く読んでみないとわからんね。

WindowsVim でも quickrun で変換することができた。 plugin/quickrun/autoload/quickrun.vimmarkdown/kramdown 設定のところ。

'markdown/kramdown': {
  'command': 'c:\Ruby193\bin\ruby',
  'cmdopt': '-Ku c:\Ruby193\bin\kramdown',
},

とすれば良い。.vimrc で設定できるそうだけどわからん。

.vimrc でできた。マニュアルの最後に書いてあった。下記で OK。

let g:quickrun_config = {}
let g:quickrun_config['markdown'] = {
\ 'type': 'markdown/kramdown',
\ 'command': 'c:\Ruby193\bin\ruby',
\ 'cmdopt': '-Ku c:\Ruby193\bin\kramdown'
\ }

とりあえずこれで Windows での問題は解決した。あとは iBookEmacs だけだ。

まとめ

先日から長々と書いてきたのだけど、経過を書いただけなので読み返してもわからないのだった。ということでまとめ。gem 側には手を入れずにエディタ側の設定で解決する。

問題点

VimEmacs から kramdown を利用すると日本語を含む文章の場合にエラーになってしまう。環境によって挙動が異るので分けて考える。

環境

WindowsXP SP3
  kaoriya-Vim 7.3.409, QuickRun 0.5.0
  GNU Emacs 23.3.1, markdown-mode 1.8.1

MacOSX 10.3.9
  野良ビルドVim 7.3.409, QuickRun 0.5.0
  Carbon Emacs 22.1.1, markdown-mode 1.8.1

解決策 WindowsXP SP3

Vim の場合:

.vimrc に下記を記述する。

let g:quickrun_config = {}
let g:quickrun_config['markdown'] = {
\ 'type': 'markdown/kramdown',
\ 'command': 'c:\Ruby193\bin\ruby',
\ 'cmdopt': '-Ku c:\Ruby193\bin\kramdown'
\ }

Emacs の場合:

.emacs.d/init.el に下記を記述する。

(autoload 'markdown-mode "markdown-mode"
  "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.md$" . markdown-mode))
(defun markdown-custom ()
  "markdown-mode-hook"
  (setq markdown-command "ruby -Ku c:/Ruby193/bin/kramdown"))
(add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))

解決策 MacOSX 10.3.9

Vim の場合:

.vimrc に下記を記述する。

let g:quickrun_config = {}
let g:quickrun_config['markdown'] = {
\ 'type': 'markdown/kramdown'
\ }

Emacs の場合:

.emacs.d/init.el に下記を記述する。

(autoload 'markdown-mode "markdown-mode"
  "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.md$" . markdown-mode))
(defun markdown-custom ()
  "markdown-mode-hook"
  (setq markdown-command "/usr/local/bin/ruby -Ku -S kramdown"))
(add-hook 'markdown-mode-hook '(lambda() (markdown-custom)))

Emacs でのエラーについてはどうやら Carbon Emacs から呼び出していた ruby/usr/bin/ruby-1.6.8 だったからみたい。「-E」オプションを使った時にエラーになって、はじめてパス捜索の順番(優先)が shell のものとは異っていることに気が付いた。自分は「-Ku」としたけど「-EUTF-8」でも良いらしい。どちらを使った方がいいのかな?