markdownの編集環境をいい感じに整えてみた[vim + quickrun + pandoc]

最近はmarkdownでちょっとしたメモを残すことが多いのですが、そのままで見やすいとは言え、やっぱり簡単にHTMLにレンダリングして表示したいという気持ちになることも多いでしょう。

ということで、僕がmarkdownエディタとして期待することは以下の項目。

- シンタックスハイライトが効く
- Vimみたいに動く
- リアルタイムプレビュー
- でもしょっちゅう更新して重くなってしまうようなものはナシ
- 当然数式も表示できる
- vim

以上の条件を満たすような環境を整えることができたと思うので、ここで紹介していきたいと思います。

前提条件は

- [thinca/vim-quickrun](https://github.com/thinca/vim-quickrun)
- [Shougo/vimproc.vim](https://github.com/Shougo/vimproc.vim)
- [pandoc](http://pandoc.org/)
- firefox  
    (コマンドから新しいタブを開くことができ、ローカルファイルが変更された時自動で読み込むアドオン(firefoxであれば[Auto Reload](https://addons.mozilla.org/en-US/firefox/addon/auto-reload/?src=api)等)があれば何でもよい)

となっています。下の画像をクリックするとYoutubeにあげた、実際に動作する動画を見ることができます。グダグダしているのはご愛嬌ということで・・・

[![ live preview of markdown in Vim [Vim + vim-quickrun + pandoc] ](http://img.youtube.com/vi/pYeur5foyoo/0.jpg)](http://www.youtube.com/watch?v=pYeur5foyoo)

## vim + quickrun + pandoc で幸せになれた。

まず、はじめにやったことは先人たちの作り上げたプラグインを入れて試してみることからでした。[previm](https://github.com/kannokanno/previm)、[vim-instant-markdown](https://github.com/suan/vim-instant-markdown)などを試してみて、使いやすいんだけど、自分でも何とか改善できないかなぁといった感じでした。特に数式やCSSでのスタイルの指定など、うまく設定すればなんとかなったのかもしれませんが、うまい解決策を見つけられませんでした。また、できるだけ最小構成でいきたい自分としては、これらは便利ではありましたが、ベストチョイスとは言えませんでした。そこで[thinca](http://d.hatena.ne.jp/thinca/)さんによる[vim-quickrun](https://github.com/thinca/vim-quickrun)を使って、変換と表示を行うようにしてみました。

このプラグインを用いれば、例えば今編集しているファイルのタイプにしたがって:QuickRunを実行することによって、そのコードのテストを走らせたり、自動でインデントや構文の調整を行ったり、LaTeXのコンパイルから表示まで行ったり、そして自分で作った任意の関数やコードを実行することが出来るのです。

自分の環境ではmarkdownからHTMLへの変換ツールとして[pandoc](http://pandoc.org/)が一番使いやすそうだったので、これを使ってmarkdownからHTMLに変換し、作成したHTMLをブラウザで見るようにすることにしました。


### 下準備

vimでのmarkdownの編集をするために、

* [plasticboy/vim-markdown](https://github.com/plasticboy/vim-markdown)
    
* vimrcに以下を追記(拡張子".md"もしくは".mkd"のファイルはファイルタイプmarkdownとして認識される)

```
autocmd BufRead,BufNewFile *.{mkd,md} set filetype=markdown
autocmd! FileType markdown hi! def link markdownItalic Normal
autocmd FileType markdown set commentstring=<\!--\ %s\ -->

" for plasticboy/vim-markdown
let g:vim_markdown_no_default_key_mappings = 1
let g:vim_markdown_math = 1
let g:vim_markdown_frontmatter = 1
let g:vim_markdown_toc_autofit = 1
let g:vim_markdown_folding_style_pythonic = 1
```

### pandocを使ってHTML形式に変換、表示するシェルスクリプト

変換用のスクリプトは、以下のようにシェルスクリプトとして準備しました([mkdpreview](https://github.com/ssh0/dotfiles/blob/master/bin/mkdpreview))。

ここで、オプションは

- "-s"  
    引数がファイル名か文字列かによって、カレントディレクトリか/tmp以下にHTML形式のファイルを保存
- "-u"  
    同名のHTMLファイルが存在しているとき、HTMLファイルを更新する
- "-o (ファイル名)"  
    指定したファイル名でHTMLファイルを保存(sは自動で有効化)
- "-p"  
    Firefoxの新しいタブでHTMLファイルを表示する

のようになっています。

また、[pandocのDemo](http://pandoc.org/demos.html)を見てもらうと分かるように、自由にヘッダーとフッター、それからCSSファイルを指定することができるので、ここに好きなHTMLファイルやスタイルシートを指定しておきます(相対リンクだと/tmp以下に配置されたときに読み込まれないので、絶対パスにするか、Web上を参照させるのがいいと思います)。

それから、数式もLaTeX形式で書いていれば、pandocへ渡すオプションに`-s --mathjax`などと入れておけば、[MathJax](https://www.mathjax.org/)で数式に自動変換してくれます。MathJaxはオンラインで数式のレンダリングを行うので、オフラインで作業したい人は別の数式レンダリングのオプションを使うといいかもしれません。

* [mkdpreview](https://github.com/ssh0/dotfiles/blob/master/bin/mkdpreview)

```bash:mkdpreview
#!/bin/sh
#=#=#=
# ```
# NAME
#       mkdpreview - Simply render markdown by pandoc.
#
# SYNOPSYS
#       mkdpreview [OPTION] markdownfile
#
# OPTIONS
#       -s: Save html file in the source file dir.
#       -u: Update (the same name's) html file in the source file dir.
#       -o: Set the name of html file. \`mkdpreview -o bar.html foo.md\`
#       -p: Preview HTML file in firefox.
#       -h: Show this message.
##
# ```
#
# This script make it easy to use pandoc for converting markdown to html file.
# It is assumed that this script is called from vim-quickrun
# in order to edit markdown file with live-preview.
#
# You can change your style sheet file.
#
# ```sh
# template="$HOME/Workspace/blog/styles/stylesheet.css"
# ```
#
# Of cource you can load the CSS file from the web.
#
# ```sh
# template='http://szk-engineering.com/markdown.css'
# ```
#
# You may change these files in order to show a header bar or a footer bar.
#
# ```
# header="$HOME/Workspace/blog/html/header.html"
# footer="$HOME/Workspace/blog/html/footer.html"
# ```
#
# my header.html
#
# ```html
# <div id="main_content_wrap" class="outer">
# <section id="main_content" class="inner">
# ```
#
# my footer.html
#
# ```html
# </section>
# </div>
# ```
#
# If the executed file is in "source" directory,
# this script converts a html file to the upper directory.
# (And if "html" directory exists, the html file will be converted to there.)
#
#=#=

# You cah change your style sheet file.
template="$HOME/Workspace/blog/styles/stylesheet.css"
# Of cource you cah load from the web.
# template='http://szk-engineering.com/markdown.css'

# You may change these files in order to show a header bar or a footer bar.
header="$HOME/Workspace/blog/html/header.html"
footer="$HOME/Workspace/blog/html/footer.html"

# If the file is in this directory,
# this script converts a html file to the upper directory.
sourcedir='source'

usage() {
  sed -n '/^# NAME$/,/^##$/p' "$f" | sed -e '$d' | cut -b3- >&2
  exit 1
}

# default settings
save=false
update=false
output=""
preview=false
previewprg="firefox -new-tab"

# option handling
while getopts suo:ph OPT
do
  case $OPT in
    "s" ) save=true ;;
    "u" ) save=true; update=true ;;
    "o" ) save=true; output="${OPTARG}" ;;
    "p" ) preview=true ;;
    "h" ) usage ;;
  esac
done

# shift arg
shift $((OPTIND-1))

# if $1 is file, check its directory.
if [ -f "$1" ]; then
  dir="$(cd "$(dirname $1)"; pwd)"
  currentdir="$(basename $dir)"
  dir_up="$(dirname $dir)"
  if [ $currentdir = $sourcedir ]; then
    dir="${dir_up}"
  fi
  namewithext=$(basename "$1")
  name=${namewithext%.*}
# save the file in /tmp dir.
else 
  dir=""
  name="/tmp/$(tr -cd 'a-f0-9' < /dev/urandom | head -c 32)"
fi

# set the saving direction
if [ "${output}" = "" ]; then
  if [ -d "${dir}/html" ]; then
    output="${dir}/html/${name}.html"
  else
    output="${dir}/${name}.html"
  fi
fi

# save to the file direction.
if $save; then
  # update option
  if $update; then
    if [ -f "${output}" ];then
      pandoc -f markdown -S -t html5 -c "${template}" -B "${header}" -A \
        "${footer}" -s --mathjax -o "${output}" "$@"
    # if file doesn't exist, do nothing.
    else
      exit 0
    fi
  # save as new file
  else
    pandoc -f markdown -S -t html5 -c "${template}" -B "${header}" -A \
      "${footer}" -s --mathjax -o "${output}" "$@"
  fi
fi

# preview in web browser.
if $preview; then
  $previewprg "file://${output}"
fi


```


### 自作スクリプトをquickrunで動かす(もちろんキーマッピングもする)

次にvim-quickrunで作成したスクリプトが実行できるようにします。`~/.vim/ftplugin/markdown_quickrun.vim`に以下のように記述します。説明はのちほど。

- [markdown_quickrun.vim](https://github.com/ssh0/dotfiles/blob/master/vimfiles/ftplugin/markdown_quickrun.vim)


```vim:markdown_quickrun.vim
" markdown
let g:quickrun_config = {
\ 'markdown/update' : {
\   'runner' : 'vimproc',
\   'outputter' : 'error',
\   'outputter/error/error' : 'message',
\   'command' : 'mkdpreview',
\   'srcfile' : expand("%"),
\   'cmdopt' : '-u',
\   'exec': '%c %o %s',
\   },
\
\ 'markdown/visual' : {
\   'runner' : 'vimproc',
\   'outputter' : 'error',
\   'outputter/error/error' : 'message',
\   'command' : 'mkdpreview',
\   'cmdopt' : '-s -p',
\   'exec': '%c %o %s',
\   },
\}

let g:quickrun_config['markdown'] = {
\ 'runner' : 'vimproc',
\ 'outputter' : 'error',
\ 'outputter/error/error' : 'message',
\ 'command' : 'mkdpreview',
\ 'cmdopt' : '-s -p',
\ 'exec': '%c %o %s',
\}

" QuickRun and view compile result quickly
nnoremap <silent> <F5> :QuickRun -type markdown<CR>
vnoremap <silent> <F5> :QuickRun -type markdown/visual<CR>

augroup markdown_pandoc
  autocmd!
  autocmd BufWritePost,FileWritePost *.md :QuickRun -type markdown/update
augroup END
```

このように書くと、vim-quickrunがこのファイル内を参照してくれるので、markdownファイルを開いた後、普通にノーマルモードでF5キーを押すと、firefoxの新しいタブで現在のファイルがHTMLに変換されたものが表示されます(同名のHTMLファイルがディレクトリ内に作成されます)。それ以後はマークダウンファイルを上書きするたびにHTMLファイルが更新されます。また、ビジュアルモードで範囲を指定してF5キーを押せば、その範囲だけでレンダリングされ、/tmp以下に臨時ファイルが作られてそれをブラウザで表示して見ることができます。

それと、はじめの前提条件のところでも少し言及しましたが、この設定自体にはブラウザの再読み込みの操作は入っていないので、Firefoxだったら[Auto Reload](https://addons.mozilla.org/en-US/firefox/addon/auto-reload/?src=api)のようなアドオンが別途必要になります。他のプラグインなどではローカルサーバーをたてて、そこを見るようにしてこの問題を解決しているようですね。

## まとめ

ということで、はじめに示した条件を満たす環境を構築することができたのではないかと思います。quickrunの仕様をしっかりと理解した作りになっているかはわかりませんが、個人でシェルスクリプトを作りためてる人はこのようにしていけば簡単に自分の思った通りの挙動をさせることができて便利だと思います。今後の課題としては、markdown中で数式のシンタックスハイライトを有効にしたいということです。今のところこれがうまくいかないので、なんとかなるとすごく助かります。どなたか教えていただけると幸いです。

また、LaTeXの編集に関しても、latexmkを使った全体のコンパイルと部分コンパイルの設定を同じように行ったので、そちらもまとめ次第こちらにアップしたいと思います。

> **追記 (2016/04/11)**
> * [VimでLaTeX編集！vim-quickrunとlatexmkで自動コンパイルと部分コンパイル - Qiita]
(http://qiita.com/ssh0/items/4aea2d3849667717b36d)
> * [TeXをもっと便利に使う!(自動コンパイル・部分コンパイル・分割ファイルから親ファイルのコンパイル)【Vim + vim-quickrun + latexmk】 - Qiita](http://qiita.com/ssh0/items/e6d7540cd46fac580bc2)

お疲れ様でした。