diff --git a/autoload/vimtex.vim b/autoload/vimtex.vim index 8cfc270..b3d938b 100644 --- a/autoload/vimtex.vim +++ b/autoload/vimtex.vim @@ -365,6 +365,8 @@ function! s:init_mappings() " {{{1 if g:vimtex_latexmk_enabled call s:map('n', 'll', '(vimtex-compile-toggle)') call s:map('n', 'lo', '(vimtex-compile-output)') + call s:map('n', 'lL', '(vimtex-compile-selected)') + call s:map('x', 'lL', '(vimtex-compile-selected)') call s:map('n', 'lk', '(vimtex-stop)') call s:map('n', 'lK', '(vimtex-stop-all)') call s:map('n', 'le', '(vimtex-errors)') diff --git a/autoload/vimtex/latexmk.vim b/autoload/vimtex/latexmk.vim index cb2069a..c2dc9f2 100644 --- a/autoload/vimtex/latexmk.vim +++ b/autoload/vimtex/latexmk.vim @@ -81,6 +81,8 @@ function! vimtex#latexmk#init_buffer() " {{{1 command! -buffer -bang VimtexClean call vimtex#latexmk#clean( == "!") command! -buffer -bang VimtexStatus call vimtex#latexmk#status( == "!") command! -buffer VimtexLacheck call vimtex#latexmk#lacheck() + command! -buffer -range VimtexCompileSelected + \ ,call vimtex#latexmk#compile_selected('cmd') " Define mappings nnoremap (vimtex-compile) :call vimtex#latexmk#compile() @@ -95,6 +97,10 @@ function! vimtex#latexmk#init_buffer() " {{{1 nnoremap (vimtex-status) :call vimtex#latexmk#status(0) nnoremap (vimtex-status-all) :call vimtex#latexmk#status(1) nnoremap (vimtex-lacheck) :call vimtex#latexmk#lacheck() + nnoremap (vimtex-compile-selected) + \ :set opfunc=vimtex#latexmk#compile_selectedg@ + xnoremap (vimtex-compile-selected) + \ :call vimtex#latexmk#compile_selected('visual') endfunction " }}}1 @@ -223,6 +229,101 @@ function! vimtex#latexmk#compile_ss(verbose) " {{{1 let g:vimtex_latexmk_background = l:vimtex_latexmk_background endfunction +" }}}1 +function! vimtex#latexmk#compile_selected(type) range " {{{1 + " + " Get selected lines. Method depends on type of selection, which may be + " either of + " + " 1. Command range + " 2. Visual mapping + " 3. Operator mapping + " + if a:type == 'cmd' + let l:lines = getline(a:firstline, a:lastline) + elseif a:type == 'visual' + let l:lines = getline(line("'<"), line("'>")) + else + let l:lines = getline(line("'["), line("']")) + endif + + " + " Use only the part of the selection that is within the + " + " \begin{document} ... \end{document} + " + " environment. + " + let l:start = 0 + let l:end = len(l:lines) + for l:n in range(len(l:lines)) + if l:lines[l:n] =~# '\\begin\s*{document}' + let l:start = l:n + 1 + elseif l:lines[l:n] =~# '\\end\s*{document}' + let l:end = l:n - 1 + break + endif + endfor + + " + " Check if the selection has any real content + " + if l:start >= len(l:lines) + \ || l:end < 0 + \ || empty(substitute(join(l:lines[l:start : l:end], ''), '\s*', '', '')) + return + endif + + " + " Define the set of lines to compile + " + let l:lines = vimtex#parser#tex(b:vimtex.tex, { + \ 'detailed' : 0, + \ 're_stop' : '\\begin\s*{document}', + \}) + \ + ['\begin{document}'] + \ + l:lines[l:start : l:end] + \ + ['\end{document}'] + + " + " Write content to temporary file + " + let l:file = {} + let l:file.base = b:vimtex.name . '_vimtex_selected.tex' + let l:file.tex = b:vimtex.root . '/' . l:file.base + let l:file.pdf = fnamemodify(l:file.tex, ':r') . '.pdf' + let l:file.log = fnamemodify(l:file.tex, ':r') . '.log' + call writefile(l:lines, l:file.tex) + + " + " Compile the temporary file + " + let l:exe = s:latexmk_build_cmd_selected(l:file.base) + let l:exe.bg = 0 + let l:exe.silent = 1 + call vimtex#echo#status([ + \ ['VimtexInfo', 'vimtex: '], + \ ['VimtexMsg', 'compiling selected lines ...']]) + call vimtex#util#execute(l:exe) + + " + " Check if successful + " + if vimtex#latexmk#errors_inquire(l:file) + call vimtex#echo#formatted([ + \ ['VimtexInfo', 'vimtex: '], + \ ['VimtexMsg', 'compiling selected lines ...'], + \ ['VimtexWarning', ' failed!']]) + botright cwindow + else + call vimtex#latexmk#clean(0, l:file.base) + call vimtex#echo#status([ + \ ['VimtexInfo', 'vimtex: '], + \ ['VimtexMsg', 'compiling selected lines ... done!']]) + call b:vimtex.viewer.view(l:file.pdf) + endif +endfunction + " }}}1 function! vimtex#latexmk#errors() " {{{1 if s:open_quickfix_window @@ -493,6 +594,47 @@ function! s:latexmk_build_cmd() " {{{1 return exe endfunction +" }}}1 +function! s:latexmk_build_cmd_selected(fname) " {{{1 + let exe = {} + let exe.null = 0 + + if has('win32') + let cmd = 'cd /D "' . b:vimtex.root . '"' + let cmd .= ' && set max_print_line=2000 & latexmk' + let l:shellslash = &shellslash + set noshellslash + else + let cmd = 'cd ' . vimtex#util#shellescape(b:vimtex.root) + if fnamemodify(&shell, ':t') ==# 'fish' + let cmd .= '; and set max_print_line 2000; and latexmk' + elseif fnamemodify(&shell, ':t') ==# 'tcsh' + let cmd .= ' && set max_print_line=2000 && latexmk' + else + let cmd .= ' && max_print_line=2000 latexmk' + endif + endif + + " Add general options for latexmk + if !empty(g:vimtex_latexmk_options) + let cmd .= ' ' . g:vimtex_latexmk_options + else + let cmd .= ' -verbose -pdf -file-line-error' + let cmd .= ' -synctex=1 -interaction=nonstopmode' + endif + + let cmd .= ' ' . vimtex#util#shellescape(a:fname) + + let exe.cmd = cmd + let b:vimtex.cmd_latexmk_compile_selected = cmd + + if has('win32') + let &shellslash = l:shellslash + endif + + return exe +endfunction + " }}}1 function! s:latexmk_init_pid() " {{{1 " diff --git a/doc/vimtex.txt b/doc/vimtex.txt index 81fd1b9..ba16bec 100644 --- a/doc/vimtex.txt +++ b/doc/vimtex.txt @@ -296,6 +296,7 @@ This feature is explained in more detail later, see |vimtex-imaps|. lv |(vimtex-view)| `n` lr |(vimtex-reverse-search)| `n` ll |(vimtex-compile-toggle)| `n` + lL |(vimtex-compile-selected)| `nx` lk |(vimtex-stop)| `n` lK |(vimtex-stop-all)| `n` le |(vimtex-errors)| `n` @@ -1061,6 +1062,20 @@ Commands~ *VimtexCompileSS!* :VimtexCompileSS! Like |VimtexCompileSS|, but in foreground. + *VimtexCompileSelected* + *(vimtex-compile-selected)* +:VimtexCompileSelected Compile the selected part of the current LaTeX file. + When used as a command, it takes a range, e.g.: > + + :start,end VimtexCompileSelected + +< When used as a normal mode mapping, the mapping + will act as an |operator| on the following motion or + text object. Finally, when used as a visual mode + mapping, it will act on the selected lines. + + Note: This always works linewise! + *VimtexOutput* *(vimtex-compile-output)* :VimtexOutput Open file where `latexmk` output is redirected. @@ -1736,6 +1751,14 @@ compilation should run in the foreground or the background. Regardless of the |g:vimtex_latexmk_continuous| option, single shot compilation may always be issued with |VimtexCompileSS|. +It is also possible to compile a selection of the file. To do this, one may +either use the mapping, |(vimtex-compile-selected)|, or the command +|VimtexCompileSelected|. This will compile the selected text by copying it to +a temporary file with the same preamble as the current file. It will be +compiled similarly to a single shot compile, and if there are errors, they +will be shown in the quickfix list. For more info, see +|VimtexCompileSelected|. + |vimtex| passes a "sensible" default set of options to `latexmk`. This may be customized with |g:vimtex_latexmk_options|, where the default options are also described.