LaTeX-suite じゃない vim-latex を使ってvimによるLaTeX作成環境を整える

2017-1-7 追記 このページに今でも検索から辿り着く方がいるようなので追記. 以下で説明しているvim-latexですが,Latex-Suiteと名前が被っているということで2015年3月にvimtexに名称が変わりました.

github.com

それに伴い変数のprefixがg:latex_... = ... から g:vimtex_... = ... に変更されています. 他にもいろいろと機能が追加・更新されていますので,使用する際はhelpの一読をお勧めします.

どうでもいい話

vimでのLaTeX文章作成を補助するプラグインとして,代表的なものに LaTeX-suite a.k.a. Vim-LaTeXがあります. 自分も遥か前にこんな記事を 書いてしばらく使っていたんですが,いかんせんLaTeX-suiteは巨大すぎて, 何をやっているのかよく分からないとこも多かったため,結局使わなくなってしまいま した.

それからは自分があまりプラグインを使用しない派になったこともあって,特に何も使わ ずにtexを書いていましたが,最近emacsAUCTeX というものがあることを知りました. AUCTeXで羨ましいなと思ったのは, 数式のプレビュー機能です. vimではこんな風に画像は扱えないのでtexを書くときだけemacsを使おうかなと思っちゃ うぐらい魅力的でした.実際Evilを使って Emacsを試してみたんですが,自分には半日と持ちませんでした..

で,数式のプレビューとは言わなくてもtex文章作成は時間がかかるので,やっぱり何か 良いプラグインが無いかなと思って久しぶりに探してみ たところ, https://github.com/lervag/vim-latex を発 見しました.

本題

名前が紛らわしいですが,LaTeX-suiteではないvim-latexというものがあります (以下でvim-latexといったらこのプラグンのことです).

https://github.com/lervag/vim-latex

vimLaTeX文章作成をサポートするためのプラグインです.主な機能としては,

  • latexmkを利用したコンパイル
  • 分割したtexファイルのサポート
  • 自動コンパイル
  • \refや\citeのオムニ補完
  • アウトライン表示
  • 新しい インデント / 折りたたみ

などがあります.インストール方法はgithubのドキュメントに書いてあるとおりです. このプラグインは自分で設定が変更しやすくなっていますし,プラグイン自体も読みやす いと思います.また,ヘルプがしっかりしている点も良いです.

ちなみに,tex自体の補完やスニペットを使いたいという場合は,何か別のプラグイン (例えばneocomplete, ultisnips, neosnippet, emmet-vimなど)を使うことになります.

また,自分は使ったことがありませんが他のLaTeXプラグインとしては LaTeX-Boxなどもあります.

基本的な使い方

vim-latexはhelpが充実していますので,とりあえずヘルプを読みましょう.

なんでもいいから設定例が知りたいという場合はこの文章の末尾に自分の設定例がありま す.

代表的なコマンド / マッピング

いろいろコマンドやマッピングがありますが,とりあえずよく使いそうなもの

  • コマンド(()内はデフォルトマッピングです)

    • VimLatexHelp (<localleader>lh) : vim-latex関連の現在のマッピング設定が表示されます.
    • VimLatexStatus (<localleader>lg) : latxmkのステータス(実行中かどうかなど)を表示
    • VimLatexStop (<localleader>lk) : 現在のバッファのlatexmkを停止します
    • VimLatexClean (<localleader>lc) : latexmk -c を使ってファイルを削除します.
    • VimLatexCompileToggle (<localleader>lc) : latexmk を使ってファイルをコンパイル / 停止
    • VimLatexErrors (<localleader>le) : コンパイル時のエラーをquickfixに表示
    • VimLatexOutput (<localleader>lo) : コンパイルの出力を表示
    • VimLatexTocOpen (<localleader>lt) : アウトラインの表示
    • VimLatexView (<localleader>lv) : ビューワを用いて生成したファイルを開く
  • オペレータ

    • a$ / i$ : $..$ 内を選択
    • ae / ie : environmentを選択
    • ad / id : delimiterを選択
    • [[ / ]] : セクション開始位置 / セクション終了位置まで選択
  • その他主要マッピング

    • [[ / ]] (normal mode) : 前のセクション / 次のセクションに移動
    • % (normal mode) : begin / end 間の移動
    • dse (normal mode) : 現在のenvironmentを削除します
    • cse (normal mode) : 現在のenvironmentを変更します(プロンプトが出る)
    • tse (normal mode) : 現在のenvironmentの*をトグルしますks
    • ]] (insert mode) : environmentを閉じます
    • <C-x><C-o> (insert mode) : \refや\citeを入力中の場合補完します

基本的な使い方としては<localleader>lltexファイルをコンパイル<localleader>le<localleader>loで出力をチェックし, <localleader>lvでビューワで確認といった感じになると思います.

ちなみにlocalleaderのデフォルトはバックスラッシュだと思います. 自分で変更したい場合は.vimrcでlet maplocalleader = "\<Space>"とかすればできま す.

latexmkによるコンパイル

latexmkというのは platex hoge.tex && platex hoge.tex && dvipdfmx hogeみたいな 処理を自動でおこなってくれるコマンドです.TexLive等でインストールすれば最初から 使えます.vim-latexではこのlatexmkを使ってtex文章のコンパイルをおこないます. latexmkを使用する場合には,latexmk用の設定ファイルが必要です. unix系なら~/.latexmkrcに以下のようなファイルを作っておきます

$latex='platex -kanji=utf8 -guess-input-enc -synctex=1 -interaction=nonstopmode %S';
$dvipdf='dvipdfmx  %S';
$bibtex='pbibtex -kanji=utf8 %B';

platexのsynctex=1のオプションは後述するSyncTeXを使用するのに必要です. さて,以上のように設定すると,あるTeX文章があったときにlatexmk -pdfdvi hoge.texとすればplatex hoge && dvipdfmx hogeとしてpdfを生成してくれます. latexmkのオプションは以下のように.vimrcに設定します.

let g:latex_latexmk_options = '-pdfdvi'

texファイルが分割されている場合

texファイルを\input{}命令を使って分割するということがあると思います. vim-latexではそのような場合に最初から対応していて,再帰的に親ディレクトリ を遡って親のtexファイルを探してくれます.特に何か設定する必要はありません.

つまり,例えば以下のような構成に対応できます.

main.tex
chapter1/chapter1.tex
chapter2/chapter2.tex
...

main.tex内で\input{}命令を使ってchapter1/chapter1.texなどを取り込みます. ただし,以下のような場合は駄目です.

a/main.tex
b/chapter1.tex

このようなファイル構成に対応したい場合はtexファイルの先頭に%! TEX root = /path/to/main.texのように記述します.

自動コンパイル

g:latex_latexmk_continuousを1に設定し,:VimLatexCompileToggle (<localleader>ll)をすると,ファイルが上書きされると自動的にlatexmkを実行す るようになります(停止する場合は再び:VimLatexCompileToggle).この場合自動更新に 対応しているビューワを使うとさらに便利です.ただし,大きいファイルを編集している場合には この機能はオフにした方がいいかもしれません.

この機能を使用するためには+clientserver機能のあるvimが必要です.端末のvimで実行 すると自動的にgvimが起動します.

自動コンパイルをおこなうプラグインとしてはvim-latex-live-preview などがありますが,こちらは+pythonが必要です.

\refや\citeの補完

\refや\citeを入力中に<C-x><C-o>を押すと適当に補完してくれます. bibtexにも対応しています.ただ補完時に候補を集めるため\citeはちょっと重いです.

アウトライン表示

:VimLatexTocOpen (<localleader>lt) を実行すると,現在編集中のファイルのア ウトラインを表示してくれます.ファイルが分割されていてもokです.

ビューワの設定

使用するビューワは以下のように設定します.今自分の作業PCはMacなので Skimを 指定しています.

let g:latex_view_method = 'general'
let g:latex_view_general_viewer = '/Applications/Skim.app/Contents/MacOS/Skim'

:VimLatexViewをしたとき,コンパイルしたファイルと同名のpdfファイルがあれば pdfファイルを,dviファイルがあればdviファイルを開きます.

折り畳み

vim-latexにはfoldの設定ファイルがついてきます. vimのfoldのキーマッピングはいろ いろありますが,とりあえずzRで全ての折りたたみを展開,zMで全ての折りたたみ を閉じます. 折りたたみをオフにしたい場合にはlet g:latex_fold_enabled = 0とし ます.

SyncTexの設定

SyncTex という機能を使うと,ソースコードと生成したfファイルの位置の対応付けをお こなうことができるようになります.SyncTexを使う場合にはlatexmkのオプションで指定 します.

pdfファイルでSyncTeXが使えるかどうかはビューワによります. MuPDF, SumatraPDF, okular, SkimなどがSyncTexに対応しています.

試してないですがvim-latexはMuPDF, SumatraPDFにデフォルトで対応しているようです. また,helpにokularの設定例が載っています.

Skimの場合以下のようにすれば<localleader>lsでSyncTeXを使ってカーソル位置 の文章を検索ができます.

function! s:syncTexForward()
  call system('/Applications/Skim.app/Contents/SharedSupport/displayline -g '
    \ . line(".") . " "
    \ . g:latex#data[b:latex.id].out() . " "
    \ . expand('%:p'))
endfunction
autocmd FileType tex
            \ nnoremap <buffer> <localleader>ls :call <SID>syncTexForward()<CR>

TeXの一部分だけプレビューする

.vimrcに以下のように設定して,ビジュアルモードでプレビューしたい部分を選択して <localleader>laとすれば一部分だけプレビューできるようになります (Windowsの場合は最後のsystem部分を適当に変更する必要があります).

function! s:previewTex() range
    let l:tmp = @@
    silent normal gvy
    let l:selected = split(@@, "\n")
    let @@ = l:tmp

    let l:template1 = ["\\documentclass[a4paper]{jsarticle}",
                      \"\\usepackage[dvipdfmx]{graphicx}",
                      \"\\usepackage{amsmath,amssymb,bm}",
                      \"\\pagestyle{empty}",
                      \"\\begin{document}"]
    let l:template2 = ["\\end{document}"]

    let l:output_file = "preview.tex"
    call writefile(extend(extend(l:template1, l:selected), template2), l:output_file)
    silent call system("latexmk -pdfdvi preview &")
endfunction
autocmd FileType tex
            \   nnoremap <buffer> <localleader>la :call latex#motion#next_section(0,1,0)<CR>v:call latex#motion#next_section(0,0,1)<CR>:call <SID>previewTex()<CR>
            \ | vnoremap <buffer> <localleader>la :call <SID>previewTex()<CR>

やっていることは単純で,選択範囲をもとにpreview.texを作成して,それをコンパイル します.また,上の例ではvim-latexの関数を使って,ノーマルモードで <localleader>laを実行した場合現在のセクションをプレビューします.

AUCTeXのように数式を画像で置き換えるということはできませんが,自動更新のある ビューワを使ってpreview.pdfを表示させておくとまぁ便利なんじゃないかと思います.

設定例

自分の設定は以下のようになっています.一部デフォルト設定を明示的に記述していま す.ビューワ等はMac用の設定になっていますので,他環境で使用する場合には適当に 変更が必要です.

なお,vim-latexは2014年現在でも活発に開発が行われていますので,オプション名が変 更あるいは追加される可能性は十分あります.

augroup MyAutoCmd
  autocmd!
augroup END

let g:latex_latexmk_enabled = 1
let g:latex_latexmk_options = '-pdfdvi'

let g:latex_view_method = 'general'
"let g:latex_view_general_viewer = 'open'
let g:latex_view_general_viewer = '/Applications/Skim.app/Contents/MacOS/Skim'

" fold
let g:latex_fold_parts = [
      \ "appendix",
      \ "frontmatter",
      \ "mainmatter",
      \ "backmatter",
    \ ]
let g:latex_fold_sections = [
      \ "part",
      \ "chapter",
      \ "section",
      \ "subsection",
      \ "subsubsection",
    \ ]
let g:latex_fold_enabled = 1
let g:latex_fold_automatic = 1
let g:latex_fold_envs = 0

" 自動コンパイル
let g:latex_latexmk_continuous = 1
let g:latex_latexmk_background = 1
" コンパイル終了後のエラー通知オフ
let g:latex_latexmk_callback = 0

let g:latex_toc_split_pos = "topleft"
let g:latex_toc_width = 10

" SyncTex
function! s:syncTexForward()
  call system('/Applications/Skim.app/Contents/SharedSupport/displayline -g '
    \ . line(".") . " "
    \ . g:latex#data[b:latex.id].out() . " "
    \ . expand('%:p'))
endfunction

" Preview
function! s:previewTex() range
    let l:tmp = @@
    silent normal gvy
    let l:selected = split(@@, "\n")
    let @@ = l:tmp

    let l:template1 = ["\\documentclass[a4paper]{jsarticle}",
                      \"\\usepackage[dvipdfmx]{graphicx}",
                      \"\\usepackage{amsmath,amssymb,bm}",
                      \"\\pagestyle{empty}",
                      \"\\begin{document}"]
    let l:template2 = ["\\end{document}"]

    let l:output_file = "preview.tex"
    call writefile(extend(extend(l:template1, l:selected), template2), l:output_file)
    silent call system("latexmk -pdfdvi preview &")
endfunction

autocmd MyAutoCmd FileType tex
            \   nnoremap <buffer> <Space>la :call latex#motion#next_section(0,1,0)<CR>v:call latex#motion#next_section(0,0,1)<CR>:call <SID>previewTex()<CR>
            \ | vnoremap <buffer> <Space>la :call <SID>previewTex()<CR>
            \ | nnoremap <buffer> <Space>ls :call <SID>syncTexForward()<CR>

" for neocomplete
if !exists('g:neocomplete#sources#omni#input_patterns')
  let g:neocomplete#sources#omni#input_patterns = {}
endif
let g:neocomplete#sources#omni#input_patterns.tex = '\\ref{\s*[0-9A-Za-z_:]*'
"\citeも自動補完するなら
"let g:neocomplete#sources#omni#input_patterns.tex = '\\cite{\s*[0-9A-Za-z_:]*\|\\ref{\s*[0-9A-Za-z_:]*'

自分はなるべく.vimrcに書く派なのでtex filetype用のマッピングをautocmdで色々設定 していますが,それが嫌な人は vim/after/filetype/tex.vimとかに書くといいんじゃないで しょうか.

2017-1-7 追記 今自分は以下のように設定しています.

let g:tex_flavor = "latex"

let g:vimtex_latexmk_enabled = 1
let g:vimtex_latexmk_options = '-pdfdvi'
let g:vimtex_view_method = 'general'
let g:vimtex_view_general_viewer
      \ = '/Applications/Skim.app/Contents/SharedSupport/displayline'
let g:vimtex_view_general_options = '-r @line @pdf @tex'
let g:vimtex_latexmk_callback_hooks = ['UpdateSkim']
function! UpdateSkim(status)
  if !a:status | return | endif

  let l:out = b:vimtex.out()
  let l:tex = expand('%:p')
  let l:cmd = [g:vimtex_view_general_viewer, '-r']
  if !empty(system('pgrep Skim'))
    call extend(l:cmd, ['-g'])
  endif
  if has('nvim')
    call jobstart(l:cmd + [line('.'), l:out, l:tex])
  elseif has('job')
    call job_start(l:cmd + [line('.'), l:out, l:tex])
  else
    call system(join(l:cmd + [line('.'), shellescape(l:out), shellescape(l:tex)], ' '))
  endif
endfunction

let g:vimtex_latexmk_continuous = 1
let g:vimtex_latexmk_background = 1
let g:vimtex_latexmk_callback = 1

let g:vimtex_toc_split_pos = "topleft"
let g:vimtex_toc_width = 10


" for neocomplete
if !exists('g:neocomplete#sources#omni#input_patterns')
  let g:neocomplete#sources#omni#input_patterns = {}
endif
let g:neocomplete#sources#omni#input_patterns.tex = '\\ref{\s*[0-9A-Za-z_:]*'
let g:neocomplete#sources#omni#input_patterns.tex = '\\cite{\s*[0-9A-Za-z_:]*\|\\ref{\s*[0-9A-Za-z_:]*'