TL;DR
今回紹介するプラグイン
xuhdev/vim-latex-live-preview
VimでTeXのリアルタイムプレビューを可能にするプラグインです。
今回はこれにページ追従を加えます。
プラグイン導入
プラグインマネージャとしてdeinを使っている場合はこれで動くと思います。
pdfビューアはevinceを指定しています。試した限りではevinceが最もよく動きました。
pLaTeXでなくLuaLaTeXを指定しているのは中間ファイルを作らず、直接pdfを出力するからです。
jsarticle/jsreport/jsbook
と高い互換性のある文書クラスltjsarticle/ltjsreport/ltjsbook
があるので、表紙テンプレートがpLaTeX版で渡されるなどしても簡単に対応できると思います。
[[plugins]]
repo = 'xuhdev/vim-latex-live-preview'
on_ft = 'tex'
hook_add = '''
let g:livepreview_previewer = 'evince'
" let g:livepreview_engine = 'luajittex --fmt=luajitlatex.fmt' "コンパイル速度を上げたい場合はこちら
let g:livepreview_engine = 'lualatex'
set swapfile
set updatetime=1000
'''
追加する関数
自分でプラグインを変更したくない方はこちら
ソースコードの行番号と生成されたpdfのページ番号の対応をダンプする関数
function! s:Preprocess(file)
execute s:py_exe "<< EEOOFF"
with open(vim.eval("a:file"), "r") as f:
lines = f.readlines()
for i in range(len(lines) - 1):
lines[i] = '\write\pagedump{\ \\thepage ,}' + lines[i]
lines[-1] = '\write\pagedump{\ \\thepage ]}' + lines[-1]
lines.insert(0, '\\newwrite\pagedump\n')
lines.insert(1, '\openout\pagedump=pagedump.txt\n')
lines.insert(2, '\write\pagedump{let pagedump = [}')
lines.append('\closeout\pagedump')
with open(vim.eval("a:file"), "w") as f:
f.writelines(lines)
EEOOFF
endfunction
この関数の動きを説明します。以下のようなTeXソースコードがあったとき、
\documentclass{ltjsarticle}
\begin{document}
page1
\newpage
page2
\end{document}
次のようにコンパイル前に前処理をします。
\newwrite\pagedump
\openout\pagedump=pagedump.txt
\write\pagedump{let pagedump = [}
\write\pagedump{\ \thepage ,}\documentclass{ltjsarticle}
\write\pagedump{\ \thepage ,}\begin{document}
\write\pagedump{\ \thepage ,}page1
\write\pagedump{\ \thepage ,}\newpage
\write\pagedump{\ \thepage ,}page2
\write\pagedump{\ \thepage ]}\end{document}
\closeout\pagedump
コンパイルすると次のような配列の定義ファイルが$TEXMFOUTPUT/pagedump.txt
に書き出されます。
これをvimからsource pagedump.txt
することでカーソル行とpdfのページ番号の対応を扱うことができます。
let pagedump = [
\ 1,
\ 1,
\ 1,
\ 1,
\ 2,
\ 2]
s:Compile()
の末尾でコンパイル直前にs:Preprocess
を呼ぶように書き換えます
" Write the current buffer in a temporary file
silent exec 'write! ' . b:livepreview_buf_data['tmp_src_file']
call s:Preprocess(b:livepreview_buf_data['tmp_src_file'])
call s:RunInBackground(b:livepreview_buf_data['run_cmd'])
lcd -
endfunction
evinceにページ番号を指定するキーストロークを投げる関数
私の使っているWSLとXmingの組み合わせでは、WSL内からxdotoolでキーを投げるとXmingが扱っているウィンドウのうち、直近に選択されたウィンドウに投げられる。という挙動になっています。
そのため、Vimの中からフォーカスを外さずに裏のevinceにキーストロークを投げることができます。
当然ながら、他の環境ではこの関数を書き換える必要があります。
function! g:EvinceGoTo()
execute 'source ' .
\ b:livepreview_buf_data['tmp_dir'] .
\ expand('%:p:h') .
\ '/pagedump.txt'
call system("xdotool key 'ctrl+l'")
call system("xdotool key 'ctrl+a'")
call system("xdotool key " . g:pagedump[getcurpos()[1]-1])
call system("xdotool key KP_Enter")
endfunction
操作方法
:LLPStartPreview
でevinceを表示したのち、:call EvinceGoTo()
でカーソル行のページが表示されます。
nnoremap <Leader>e :<C-u>call EvinceGoTo()<CR>
としておけばSpace e
ですみます。(私は<Leader>
にスペースを指定している)
ただし、現状:call EvinceGoTo()
ごとにpagedump.txt
を読み込みに行っているので、autocmd cursormoved
でフックするにはもうすこしpagedump.txt
の読み出しタイミングを工夫する必要がありそうです。
〆
明日はクリスマス・イブですね、VimConf2018ではDark Poweredな発表で話題だったΛlisueさんの記事になります。
全く関係ないですが下は大学で最近見かけたポスターです。いったいモデルは何すえさんなのか…?。
そういえばVimConf2018ではVimの父Bramさんからサインを頂いちゃいました。
Vimの父Bram氏からSurfaceにサイン貰った!#vimconf pic.twitter.com/5L52g5v8ed
— ℕ (@mathbbN) 2018年11月24日
それでは、Happy Vimming!