仅在没有错误的情况下编译 TeX 源并启动 PDF 的 Vim 脚本
我正在改用 Vim 作为我的 LaTeX 编辑环境。我希望能够从 Vim 中解析源文件,并在编译成功时启动外部查看。
我了解 Vim-Latex 套件,但如果可能的话,我宁愿避免使用它:它相当重量级,劫持了我的很多密钥,并且用很多东西弄乱了我的 vimruntime文件数量。
这是我现在所拥有的:
if exists('b:tex_build_mapped')
finish
endif
" use maparg or mapcheck to see if key is free
command! -buffer -nargs=* BuildTex call BuildTex(0, <f-args>)
command! -buffer -nargs=* BuildAndViewTex call BuildTex(1, <f-args>)
noremap <buffer> <silent> <F9> <Esc>:call BuildTex(0)<CR>
noremap <buffer> <silent> <S-F9> <Esc>:call BuildTex(1)<CR>
let b:tex_build_mapped = 1
if exists('g:tex_build_loaded')
finish
endif
let g:tex_build_loaded = 1
function! BuildTex(view_results, ...)
write
if filereadable("Makefile")
" If Makefile is available in current working directory, run 'make' with arguments
echo "(using Makefile)"
let l:cmd = "!make ".join(a:000, ' ')
echo l:cmd
execute l:cmd
if a:view_results && v:shell_error == 0
call ViewTexResults()
endif
else
let b:tex_flavor = 'pdflatex'
compiler tex
make %
if a:view_results && v:shell_error == 0
call ViewTexResults()
endif
endif
endfunction
function! ViewTexResults(...)
if a:0 == 0
let l:target = expand("%:p:r") . ".pdf"
else
let l:target = a:1
endif
if has('mac')
execute "! open -a Preview ".l:target
endif
endfunction
问题是,即使存在编译错误,也未设置 v:shell_error
。任何有关如何检测编译是否成功的建议或见解将不胜感激!谢谢!
通过这里给出的答案,再加上对其他方法的一些研究,我认为这个问题已经得到了令人满意的解决。我将解决方案发布在这里,以防其他人感兴趣。
基本上,最好的解决方案似乎是使用 Rubber,它是一个包装器LaTeX,通常“正常工作”,并提供非常干净的输出/错误。如果在系统上找到了 Rubber 并且在当前目录中找不到 Makefile,我下面介绍的解决方案会优先使用 Rubber。如果找到 Makefile,它将使用该文件。如果没有Makefile且未安装Rubber,则使用pdflatex。在所有情况下,如果源代码无法编译,(已过滤和解析的)错误将发送到 QuickFix 缓冲区,并自动打开 QuickFix 窗口。如果编译成功,则会写入一条短信,如果用户请求,则会打开 PDF 进行查看。
在我自己的安装中,我从 中提升了(优秀)“SetLatexEfm()”函数Vim-Latex 解析和过滤 tex 构建输出。但是,如果找不到此函数,则下面的函数默认设置一种错误消息格式,该格式足以在 QuickFix 窗口中识别并突出显示错误,尽管有很多繁琐的内容。
function! BuildTex(view_results, ...)
" record position
let save_cursor = getpos(".")
" save work
silent write
" From: http://stackoverflow.com/questions/2679475/vim-script-to-compile-tex-source-and-launch-pdf-only-if-no-errors
" If your shell is bash, you can use the ${PIPESTATUS} array variable to get
" the correct exit code (borrowed from this answer to another question).
silent setlocal shell=bash
silent setlocal shellpipe=2>&1\ \|\ tee\ %s;exit\ \${PIPESTATUS[0]}
let success = 1
if filereadable("Makefile")
" If Makefile is available in current working directory, run 'make' with arguments
echon "compiling using Makefile ..."
let l:makecmd = "make\\ ".join(a:000, '\\ ')
silent execute "setlocal makeprg=" . l:makecmd
try
" This function is defined in the Vim-Latex package,
" and provides excellent parsing and filtering of the error messages
" when running latex outside of the Rubber wrapper.
call s:SetLatexEfm()
catch /E117/
set errorformat=%E!\ LaTeX\ %trror:\ %m,
\%E!\ %m,
\%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#,
\%+W%.%#\ at\ lines\ %l--%*\\d,
\%WLaTeX\ %.%#Warning:\ %m,
\%Cl.%l\ %m,
\%+C\ \ %m.,
\%+C%.%#-%.%#,
\%+C%.%#[]%.%#,
\%+C[]%.%#,
\%+C%.%#%[{}\\]%.%#,
\%+C<%.%#>%.%#,
\%C\ \ %m,
\%-GSee\ the\ LaTeX%m,
\%-GType\ \ H\ <return>%m,
\%-G\ ...%.%#,
\%-G%.%#\ (C)\ %.%#,
\%-G(see\ the\ transcript%.%#),
\%-G\\s%#,
\%+O(%f)%r,
\%+P(%f%r,
\%+P\ %\\=(%f%r,
\%+P%*[^()](%f%r,
\%+P[%\\d%[^()]%#(%f%r,
\%+Q)%r,
\%+Q%*[^()])%r,
\%+Q[%\\d%*[^()])%r
endtry
silent make
else
let l:special_tex_compiler = "rubber"
if executable(l:special_tex_compiler)
echon "compiling with Rubber ..."
silent execute "setlocal makeprg=" . l:special_tex_compiler . "\\ -dfs\\ %"
setlocal errorformat=%f:%l:\ %m
silent make %
else
echon "compiling ..."
let b:tex_flavor = 'pdflatex'
compiler tex
silent make %
endif
endif
" set/report compile status
if v:shell_error
let l:success = 0
" let l:wheight = winheight(bufnr("%")) / 2
" execute "copen ".l:wheight
copen
else
let l:success = 1
cclose
redraw
echon "successfully compiled"
endif
" view results if successful compile
if l:success && a:view_results
call ViewTexResults()
endif
" restore position
call setpos('.', save_cursor)
endfunction
function! ViewTexResults(...)
if a:0 == 0
let l:target = expand("%:p:r") . ".pdf"
else
let l:target = a:1
endif
if has('mac')
silent execute "! open -a Preview ".l:target
" obviously, you will need to write specific commands for other systems
" left as an exercise for the reader ...
endif
endfunction
command! -buffer -nargs=* BuildTex call BuildTex(0, <f-args>)
command! -buffer -nargs=* BuildAndViewTex call BuildTex(1, <f-args>)
noremap <buffer> <silent> <F9> <Esc>:call BuildTex(0)<CR>
noremap <buffer> <silent> <S-F9> <Esc>:call BuildTex(1)<CR>
更新:我已将其打包并发布为 Vim 文件类型插件脚本,可在以下位置获取: http://www.vim.org/scripts/script.php?script_id=3230。
I am switching to using Vim for for my LaTeX editing environment. I would like to be able to tex the source file from within Vim, and launch an external viewing if the compile was successful.
I know about the Vim-Latex suite, but, if possible, would prefer to avoid using it: it is pretty heavy-weight, hijacks a lot of my keys, and clutters up my vimruntime with a lot of files.
Here is what I have now:
if exists('b:tex_build_mapped')
finish
endif
" use maparg or mapcheck to see if key is free
command! -buffer -nargs=* BuildTex call BuildTex(0, <f-args>)
command! -buffer -nargs=* BuildAndViewTex call BuildTex(1, <f-args>)
noremap <buffer> <silent> <F9> <Esc>:call BuildTex(0)<CR>
noremap <buffer> <silent> <S-F9> <Esc>:call BuildTex(1)<CR>
let b:tex_build_mapped = 1
if exists('g:tex_build_loaded')
finish
endif
let g:tex_build_loaded = 1
function! BuildTex(view_results, ...)
write
if filereadable("Makefile")
" If Makefile is available in current working directory, run 'make' with arguments
echo "(using Makefile)"
let l:cmd = "!make ".join(a:000, ' ')
echo l:cmd
execute l:cmd
if a:view_results && v:shell_error == 0
call ViewTexResults()
endif
else
let b:tex_flavor = 'pdflatex'
compiler tex
make %
if a:view_results && v:shell_error == 0
call ViewTexResults()
endif
endif
endfunction
function! ViewTexResults(...)
if a:0 == 0
let l:target = expand("%:p:r") . ".pdf"
else
let l:target = a:1
endif
if has('mac')
execute "! open -a Preview ".l:target
endif
endfunction
The problem is that v:shell_error
is not set, even if there are compile errors. Any suggestions or insight on how to detect whether a compile was successful or not would be greatly appreciated! Thanks!
Between the answers given here, plus some study of other approaches, I think that this has been satisfactorily solved. I am posting the solution here in case anyone else is interested.
Basically, the best solution appears to be to use Rubber, a wrapper around LaTeX, that generally "just works", and provides very clean output/errors. The solution I present below preferentially uses Rubber if it is found on the system and no Makefile is found in the current directory. If a Makefile is found, it uses that instead. If there is no Makefile and Rubber is not installed, it uses pdflatex. In all cases, if the source fails to compile, the (filtered and parsed) errors are sent to the QuickFix buffer and the QuickFix window is automatically opened. If it compiles successfully, a short message is written, and if the user requested it, the PDF will be opened for viewing.
In my own installation, I have lifted the (excellent) "SetLatexEfm()" function from Vim-Latex to parse and filter the tex build output. If this function is not found, however, the function below defaults to setting an error message format that works fine enough for the errors to be identified and highlighted in the QuickFix window, albeit with lots of crud.
function! BuildTex(view_results, ...)
" record position
let save_cursor = getpos(".")
" save work
silent write
" From: http://stackoverflow.com/questions/2679475/vim-script-to-compile-tex-source-and-launch-pdf-only-if-no-errors
" If your shell is bash, you can use the ${PIPESTATUS} array variable to get
" the correct exit code (borrowed from this answer to another question).
silent setlocal shell=bash
silent setlocal shellpipe=2>&1\ \|\ tee\ %s;exit\ \${PIPESTATUS[0]}
let success = 1
if filereadable("Makefile")
" If Makefile is available in current working directory, run 'make' with arguments
echon "compiling using Makefile ..."
let l:makecmd = "make\\ ".join(a:000, '\\ ')
silent execute "setlocal makeprg=" . l:makecmd
try
" This function is defined in the Vim-Latex package,
" and provides excellent parsing and filtering of the error messages
" when running latex outside of the Rubber wrapper.
call s:SetLatexEfm()
catch /E117/
set errorformat=%E!\ LaTeX\ %trror:\ %m,
\%E!\ %m,
\%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#,
\%+W%.%#\ at\ lines\ %l--%*\\d,
\%WLaTeX\ %.%#Warning:\ %m,
\%Cl.%l\ %m,
\%+C\ \ %m.,
\%+C%.%#-%.%#,
\%+C%.%#[]%.%#,
\%+C[]%.%#,
\%+C%.%#%[{}\\]%.%#,
\%+C<%.%#>%.%#,
\%C\ \ %m,
\%-GSee\ the\ LaTeX%m,
\%-GType\ \ H\ <return>%m,
\%-G\ ...%.%#,
\%-G%.%#\ (C)\ %.%#,
\%-G(see\ the\ transcript%.%#),
\%-G\\s%#,
\%+O(%f)%r,
\%+P(%f%r,
\%+P\ %\\=(%f%r,
\%+P%*[^()](%f%r,
\%+P[%\\d%[^()]%#(%f%r,
\%+Q)%r,
\%+Q%*[^()])%r,
\%+Q[%\\d%*[^()])%r
endtry
silent make
else
let l:special_tex_compiler = "rubber"
if executable(l:special_tex_compiler)
echon "compiling with Rubber ..."
silent execute "setlocal makeprg=" . l:special_tex_compiler . "\\ -dfs\\ %"
setlocal errorformat=%f:%l:\ %m
silent make %
else
echon "compiling ..."
let b:tex_flavor = 'pdflatex'
compiler tex
silent make %
endif
endif
" set/report compile status
if v:shell_error
let l:success = 0
" let l:wheight = winheight(bufnr("%")) / 2
" execute "copen ".l:wheight
copen
else
let l:success = 1
cclose
redraw
echon "successfully compiled"
endif
" view results if successful compile
if l:success && a:view_results
call ViewTexResults()
endif
" restore position
call setpos('.', save_cursor)
endfunction
function! ViewTexResults(...)
if a:0 == 0
let l:target = expand("%:p:r") . ".pdf"
else
let l:target = a:1
endif
if has('mac')
silent execute "! open -a Preview ".l:target
" obviously, you will need to write specific commands for other systems
" left as an exercise for the reader ...
endif
endfunction
command! -buffer -nargs=* BuildTex call BuildTex(0, <f-args>)
command! -buffer -nargs=* BuildAndViewTex call BuildTex(1, <f-args>)
noremap <buffer> <silent> <F9> <Esc>:call BuildTex(0)<CR>
noremap <buffer> <silent> <S-F9> <Esc>:call BuildTex(1)<CR>
Update: I have packaged and published this as a Vim file-type plugin script, available at: http://www.vim.org/scripts/script.php?script_id=3230.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设您陷入了 else-theres-no-makefile 部分,问题可能出在
shellpipe
变量上。在我的系统(Ubuntu)上,
shellpipe=2>&1| tee
和内置make
调用在失败时不会设置v:shell_error
。| 的返回状态tee
可能是v:shell_error
设置的内容。如果您的 shell 是 bash,则可以使用
${PIPESTATUS}
数组变量来获取正确的退出代码(借自 这个答案到另一个问题)。否则,您可以尝试:
这会在失败时设置
v:shell_error
,但我不确定这是否会扰乱 go-to-error-line-number 功能(如果有)。要查看变量设置的内容:
Assuming you're falling into the else-theres-no-makefile section, the issue may be with the
shellpipe
variable.On my system (Ubuntu),
shellpipe=2>&1| tee
and the built-inmake
call doesn't setv:shell_error
if it fails.The return status of
| tee
might be whatv:shell_error
is getting set to.If your shell is bash, you can use the
${PIPESTATUS}
array variable to get the correct exit code (borrowed from this answer to another question).Otherwise, you can try:
This sets
v:shell_error
when it fails but I'm not sure if that will mess with the go-to-error-line-number functionality, if there is any.To see what the variable is set to:
我知道它与 vim 无关,但我认为 latexmk 完成工作。
这是一个脚本(用 perl 编写),用于编译 Latex 文件并更新 pdf。最有用的未来是自动更新。一旦你保存文件,“latexmk”就会编译它,如果你的 pdf 查看器支持它,视图就会更新。
latexmk -pdf -pvc
I know it's not related to vim, but I think that latexmk does the job.
It's a script (written in perl) which compile the latex file and update the pdf. The most useful future is the auto-update one. As soon as you save your file, 'latexmk' compile it, and if your pdf viewer supports it, the view is updated.
latexmk -pdf -pvc
如果 Latexmk 使用“-halt-on-error”选项(或在不间断模式下)运行 Latex,编译将停止而不会暂停输入。
If latexmk runs latex with the '-halt-on-error' option (or in nonstop mode), compilation will cease without pausing for input.