diff --git a/autoload/health/vimtex.vim b/autoload/health/vimtex.vim index 7e40bd28fd..feccacf5f7 100644 --- a/autoload/health/vimtex.vim +++ b/autoload/health/vimtex.vim @@ -58,7 +58,7 @@ function! s:check_view() abort " {{{1 if executable('xdotool') && !executable('pstree') call health#report_warn('pstree is not available', - \ 'vimtex#view#reverse_goto is better if pstree is available.') + \ 'vimtex#view#inverse_search is better if pstree is available.') endif endfunction diff --git a/autoload/vimtex.vim b/autoload/vimtex.vim index f71a3ce993..4054fa904d 100644 --- a/autoload/vimtex.vim +++ b/autoload/vimtex.vim @@ -290,7 +290,7 @@ function! s:init_default_mappings() abort " {{{1 if has_key(b:vimtex, 'viewer') call s:map(0, 'n', 'lv', '(vimtex-view)') - if has_key(b:vimtex.viewer, 'reverse_search') + if maparg('(vimtex-reverse-search)', 'n') call s:map(0, 'n', 'lr', '(vimtex-reverse-search)') endif endif diff --git a/autoload/vimtex/options.vim b/autoload/vimtex/options.vim index 1d2a311003..5894ea30fb 100644 --- a/autoload/vimtex/options.vim +++ b/autoload/vimtex/options.vim @@ -18,10 +18,6 @@ function! vimtex#options#init() abort " {{{1 call s:init_option('vimtex_compiler_enabled', 1) call s:init_option('vimtex_compiler_silent', 0) call s:init_option('vimtex_compiler_method', 'latexmk') - call s:init_option('vimtex_compiler_progname', - \ has('nvim') && executable('nvr') - \ ? 'nvr' - \ : get(v:, 'progpath', get(v:, 'progname', ''))) call s:init_option('vimtex_compiler_latexmk_engines', {}) call s:init_option('vimtex_compiler_latexrun_engines', {}) diff --git a/autoload/vimtex/paths.vim b/autoload/vimtex/paths.vim index d5c01795b4..36d92e33b3 100644 --- a/autoload/vimtex/paths.vim +++ b/autoload/vimtex/paths.vim @@ -23,6 +23,22 @@ endfunction " }}}1 +function! vimtex#paths#join(root, tail) abort " {{{1 + return vimtex#paths#s(a:root . '/' . a:tail) +endfunction + +" }}}1 + +function! vimtex#paths#s(path) abort " {{{1 + " Handle shellescape issues and simplify path + let l:path = exists('+shellslash') && !&shellslash + \ ? tr(a:path, '/', '\') + \ : a:path + + return simplify(l:path) +endfunction + +" }}}1 function! vimtex#paths#is_abs(path) abort " {{{1 return a:path =~# s:re_abs endfunction diff --git a/autoload/vimtex/view.vim b/autoload/vimtex/view.vim index af4b0230b3..76ab78683b 100644 --- a/autoload/vimtex/view.vim +++ b/autoload/vimtex/view.vim @@ -7,17 +7,15 @@ function! vimtex#view#init_buffer() abort " {{{1 if !g:vimtex_view_enabled | return | endif + " Store neovim servername for inheritance to inverse search + if has('nvim') && empty($NVIM_LISTEN_ADDRESS_VIMTEX) + let $NVIM_LISTEN_ADDRESS_VIMTEX = v:servername + endif + command! -buffer -nargs=? -complete=file VimtexView \ call vimtex#view#view() - if has_key(b:vimtex.viewer, 'reverse_search') - command! -buffer -nargs=* VimtexViewRSearch - \ call vimtex#view#reverse_search() - endif nnoremap (vimtex-view) :VimtexView - if has_key(b:vimtex.viewer, 'reverse_search') - nnoremap (vimtex-reverse-search) :VimtexViewRSearch - endif endfunction " }}}1 @@ -49,13 +47,6 @@ function! vimtex#view#view(...) abort " {{{1 endif endfunction -" }}}1 -function! vimtex#view#reverse_search() abort " {{{1 - if exists('*b:vimtex.viewer.reverse_search') - call b:vimtex.viewer.reverse_search() - endif -endfunction - " }}}1 function! vimtex#view#not_readable(output) abort " {{{1 if filereadable(a:output) | return 0 | endif @@ -66,10 +57,20 @@ endfunction " }}}1 -function! vimtex#view#reverse_goto(line, filename) abort " {{{1 - if mode() ==# 'i' | stopinsert | endif +function! vimtex#view#inverse_search(line, filename) abort " {{{1 + " Only activate in VimTeX buffers + if !exists('b:vimtex') | return -1 | endif + " Only activate in relevant VimTeX projects let l:file = resolve(a:filename) + let l:sources = copy(b:vimtex.sources) + if vimtex#paths#is_abs(l:file) + call map(l:sources, {_, x -> vimtex#paths#join(b:vimtex.root, x)}) + endif + if index(l:sources, l:file) < 0 | return -2 | endif + + + if mode() ==# 'i' | stopinsert | endif " Open file if necessary if !bufloaded(l:file) @@ -81,13 +82,13 @@ function! vimtex#view#reverse_goto(line, filename) abort " {{{1 \ 'Reverse goto failed!', \ printf('Command error: %s %s', \ g:vimtex_view_reverse_search_edit_cmd, l:file)]) - return + return -3 endtry else call vimtex#log#warning([ \ 'Reverse goto failed!', \ printf('File not readable: "%s"', l:file)]) - return + return -4 endif endif @@ -104,14 +105,85 @@ function! vimtex#view#reverse_goto(line, filename) abort " {{{1 endtry execute 'normal!' a:line . 'G' - redraw call s:focus_vim() + redraw if exists('#User#VimtexEventViewReverse') doautocmd User VimtexEventViewReverse endif endfunction +" }}}1 +function! vimtex#view#inverse_search_cmd(line, filename) abort " {{{1 + " One may call this function manually, but the main usage is to through the + " command "VimtexInverseSearch". See ":help vimtex-synctex-inverse-search" + " for more info. + + if a:line > 0 && !empty(a:filename) + try + if has('nvim') + call s:inverse_search_cmd_nvim(a:line, a:filename) + else + call s:inverse_search_cmd_vim(a:line, a:filename) + endif + catch + endtry + endif + + quitall! +endfunction + +" }}}1 + +function! s:inverse_search_cmd_nvim(line, filename) abort " {{{1 + " WARNING: The following code is somewhat messy, as it mixes Python with + " Vimscript. Read with care! + if empty($NVIM_LISTEN_ADDRESS_VIMTEX) + if vimtex#util#is_win() + py3 << EOF +import psutil + +sockets = [ + p.environ()["NVIM_LISTEN_ADDRESS_VIMTEX"] + for p in psutil.process_iter(attrs=["name"]) + if ("nvim" in p.info["name"] + and "NVIM_LISTEN_ADDRESS_VIMTEX" in p.environ()) +] +EOF + else + py3 << EOF +import psutil + +sockets = [] +for proc in (p for p in psutil.process_iter(attrs=['name']) + if p.info['name'] in ('nvim', 'nvim.exe', 'nvim-qt.exe')): + sockets += [c.laddr for c in proc.connections('unix') if c.laddr] +EOF + endif + let l:socket_ids = filter(py3eval('sockets'), 'v:val != v:servername') + unsilent echo l:socket_ids + else + let l:socket_ids = [$NVIM_LISTEN_ADDRESS_VIMTEX] + endif + + for l:socket_id in l:socket_ids + let l:socket = sockconnect('pipe', l:socket_id, {'rpc': 1}) + call rpcnotify(l:socket, + \ 'nvim_call_function', + \ 'vimtex#view#inverse_search', + \ [a:line, a:filename]) + call chanclose(l:socket) + endfor +endfunction + +" }}}1 +function! s:inverse_search_cmd_vim(line, filename) abort " {{{1 + for l:server in split(serverlist(), "\n") + call remote_expr(l:server, + \ printf("vimtex#view#inverse_search(%d, '%s')", a:line, a:filename)) + endfor +endfunction + " }}}1 function! s:focus_vim() abort " {{{1 diff --git a/autoload/vimtex/view/mupdf.vim b/autoload/vimtex/view/mupdf.vim index 4cc44c79f9..124e90da52 100644 --- a/autoload/vimtex/view/mupdf.vim +++ b/autoload/vimtex/view/mupdf.vim @@ -13,6 +13,10 @@ function! vimtex#view#mupdf#new() abort " {{{1 return {} endif + " Add reverse search mapping + nnoremap (vimtex-reverse-search) + \ :call b:vimtex.viewer.reverse_search() + return vimtex#view#_template_xwin#apply(deepcopy(s:mupdf)) endfunction diff --git a/autoload/vimtex/view/zathura.vim b/autoload/vimtex/view/zathura.vim index 9c2e0b721d..361a4d672b 100644 --- a/autoload/vimtex/view/zathura.vim +++ b/autoload/vimtex/view/zathura.vim @@ -35,10 +35,8 @@ let s:zathura = { function! s:zathura.start(outfile) dict abort " {{{1 let l:cmd = 'zathura' if self.has_synctex - let l:cmd .= ' -x "' . g:vimtex_compiler_progname - \ . ' --servername ' . v:servername - \ . ' --remote-expr ' - \ . '\"vimtex#view#reverse_goto(%{line}, ''%{input}'')\""' + let l:cmd .= ' -x "' . s:inverse_search_cmd + \ . ' -c \"VimtexInverseSearch %{line} ''%{input}''\""' if g:vimtex_view_forward_search_on_start let l:cmd .= ' --synctex-forward ' \ . line('.') @@ -77,20 +75,22 @@ endfunction " }}}1 function! s:zathura.latexmk_append_argument() dict abort " {{{1 if g:vimtex_view_use_temp_files - let cmd = ' -view=none' + let l:cmd = ' -view=none' else - let zathura = 'zathura ' . g:vimtex_view_zathura_options + let l:zathura = 'zathura ' . g:vimtex_view_zathura_options if self.has_synctex - let zathura .= ' -x \"' . g:vimtex_compiler_progname - \ . ' --servername ' . v:servername - \ . ' --remote-expr \"\\\"\"vimtex#view#reverse_goto(\%{line}, ''"''"''\%{input}''"''"'')\"\\\"\"\" \%S' + " The inverse search command requires insane amount of quote escapes, + " because the command is parsed through several layers of interpreting, + " e.g. perl -> shell, perhaps more. + let l:zathura .= ' -x \"' . s:inverse_search_cmd + \ . ' -c \"\\\"\"VimtexInverseSearch \%{line} ''"''"''\%{input}''"''"''\"\\\"\"\" \%S' endif - let cmd = vimtex#compiler#latexmk#wrap_option('new_viewer_always', '0') - let cmd .= vimtex#compiler#latexmk#wrap_option('pdf_previewer', zathura) + let l:cmd = vimtex#compiler#latexmk#wrap_option('new_viewer_always', '0') + let l:cmd .= vimtex#compiler#latexmk#wrap_option('pdf_previewer', l:zathura) endif - return cmd + return l:cmd endfunction " }}}1 @@ -109,3 +109,8 @@ function! s:zathura.get_pid() dict abort " {{{1 endfunction " }}}1 + +let s:inverse_search_cmd = get(v:, 'progpath', get(v:, 'progname', '')) + \ . (has('nvim') + \ ? ' --headless' + \ : ' -T dumb --not-a-term -n') diff --git a/doc/vimtex.txt b/doc/vimtex.txt index 0e71607151..391aac3241 100644 --- a/doc/vimtex.txt +++ b/doc/vimtex.txt @@ -211,8 +211,7 @@ FEATURE OVERVIEW *vimtex-features* REQUIREMENTS *vimtex-requirements* The following is a list of specific requirements for running VimTeX and some -of its key features. One may also be interested in reading |vimtex-faq-neovim| -and |vimtex-faq-windows|. +of its key features. Windows users should also read |vimtex-faq-windows|. Vim version~ *vimtex_version_check* @@ -269,38 +268,35 @@ Compiler backend~ Clientserver~ *vimtex-clientserver* Vim requires |+clientserver| in order to allow inverse search from the PDF - viewer to Vim (see |vimtex-synctex-inverse-search|). + viewer to Vim (see |vimtex-synctex-inverse-search|). The clientserver is + used by VimTeX. Thus, if one uses Vim one must ensure that it starts + a server. Neovim does not have this requirement. - Neovim does not have the same clientserver feature, but it implements the - MessagePack-RPC protocol (see |RPC|). This protocol be used in the same - fashion as the clientserver through neovim-remote (`nvr`); see - |vimtex-faq-neovim| for more info and installation help. - - Both Vim and neovim has the |v:servername| variable that contains the - name/location of the server with which we need to communicate. - - A server will be started automatically if Vim is running on Windows or if - running in a GUI. If you use Vim under a terminal in Linux or macOS, - a server will not be started by default. Since Vim version 8.0.475, one can - use |remote_startserver()| to start a server from your `vimrc` file. The - following vimrc configuration snippet will ensure Vim starts with a server, - if possible: > + A server will be started automatically if Vim is running on Windows or if it + is running in a GUI (gVim). If you use Vim under a terminal in Linux or + MacOS, a server will not be started by default. Since Vim version 8.0.475, + one can use |remote_startserver()| to start a server from your `vimrc` file. + The following vimrc configuration snippet will ensure that Vim starts with + a server, if possible: > if empty(v:servername) && exists('*remote_startserver') call remote_startserver('VIM') endif < Alternatively, Vim can be started with the command line option - `--servername`, e.g. `vim --servername VIM` . The simplest way to ensure + `--servername`, e.g. `vim --servername VIM` . The simplest way to ensure this is to add an alias to your `.bashrc` (or similar), that is, add: > alias vim='vim --servername VIM' < - For other methods of ensuring that Vim is started with a servername, see: - https://vim.fandom.com/wiki/Enable_servername_capability_in_vim/xterm + One can use |serverlist()| to check whether a server was successfully + started, e.g. with `:echo serverlist()`. - To test whether a server was successfully started, |serverlist()| can be - used. E.g. `:echo serverlist()` + Neovim does not implement the same clientserver feature. Instead, it + implements the MessagePack-RPC protocol (see |RPC|). VimTeX relies on this + protocol in the same fashion as the clientserver. Both Vim and neovim has + the |v:servername| variable that contains the name/location of the server + with which we need to communicate. ------------------------------------------------------------------------------ SUPPORT FOR MULTI-FILE PROJECTS *vimtex-multi-file* @@ -887,19 +883,6 @@ OPTIONS *vimtex-options* Default: 0 -*g:vimtex_compiler_progname* - Path to vim executable used for the automatic inverse search settings with - Zathura (|vimtex-view-zathura|). - - The reason it is called `_compiler_progname` is because it was previously - used for the compiler callback features. This is no longer the case, but to - avoid breaking changes the option name has not been changed. - - Default value on Vim: |v:progpath| or |v:progname| - Default value on neovim: `nvr` if available, else same as Vim - - See also: |vimtex-faq-neovim| - *g:vimtex_compiler_method* Set the compiler method. Available choices are: @@ -964,9 +947,6 @@ OPTIONS *vimtex-options* If enabled, this option tells `latexmk` to run |vimtex#compiler#callback| after compilation is finished. - Note: When using |clientserver|, the callback is run with the vim - executable defined by |g:vimtex_compiler_progname|. - continuous~ If enabled, `latexmk` will run in continuous mode, i.e. with the `-pvc` argument. This means that the document is compiled automatically by @@ -2831,8 +2811,8 @@ OPTIONS *vimtex-options* Default value: 1 *g:vimtex_view_reverse_search_edit_cmd* - When working in a multi-file project, initiating inverse search - |vimtex-synctex-inverse-search| may require opening a file that is not + When working in a multi-file project, initiating inverse search (see + |vimtex-synctex-inverse-search|) may require opening a file that is not currently open in a window. This option controls the command that is used to open files as a result of an inverse search. @@ -3072,11 +3052,6 @@ COMMANDS *vimtex-commands* :VimtexView View `pdf` for current project, perform forward search if available. - *:VimtexViewRSearch* - *(vimtex-reverse-search)* -:VimtexViewRSearch Do reverse search (only available for MuPDF viewer), - see also |vimtex-view-mupdf|. - *:VimtexReload* *(vimtex-reload)* :VimtexReload Reload VimTeX scripts. This is primarily useful @@ -3228,6 +3203,9 @@ MAP DEFINITIONS *vimtex-mappings* *(vimtex-delim-close)* Close the current environment or delimiter (insert mode). +*(vimtex-reverse-search)* + Do reverse search for the MuPDF viewer, see |vimtex-view-mupdf|. + *(vimtex-ac)* Commands *(vimtex-ic)* *(vimtex-ad)* Delimiters @@ -3508,7 +3486,7 @@ further customization. been performed by the command |:VimtexView| or the related mapping. *VimtexEventViewReverse* - This event is triggered at the end of the |vimtex#view#reverse_goto| + This event is triggered at the end of the |vimtex#view#inverse_search| function, which can be used as the callback function for reverse goto from a PDF viewer. @@ -4624,7 +4602,6 @@ Associated settings: * |g:vimtex_compiler_tectonic| * |g:vimtex_compiler_arara| * |g:vimtex_compiler_generic| -* |g:vimtex_compiler_progname| * |$VIMTEX_OUTPUT_DIRECTORY| Associated events: @@ -4997,12 +4974,11 @@ Associated events: VIEWER CONFIGURATION *vimtex-view-configuration* |g:vimtex_view_method| is the main configuration variable. It allows to choose -between a set of predefined viewers, including a general customizable -interface. For the specific, predefined viewers, both forward and inverse -search with synctex should usually work without any further configuration. -With the general viewer, one may often specify options to enable forward -search. But options for inverse search must be configured within the specific -viewer. +between a set of predefined viewers, including a generic customizable +interface. For the predefined viewers, forward search with synctex should +usually work without any further configuration. With the general viewer, one +may often specify options to enable forward search. Inverse search requires +configuration on the viewer side in most cases. The generic interface is flexible. It relies on three options: * |g:vimtex_view_general_viewer| @@ -5016,9 +4992,6 @@ The generic interface is flexible. It relies on three options: The following is a list of popular PDF viewers, in alphabetic order, and how they can be configured to work with VimTeX. -Note: Neovim users should ensure to have `nvr` (reovim-remote) and the - `pynvim` Python module available, please read |vimtex-faq-neovim|! - *vimtex-view-evince* Evince~ https://wiki.gnome.org/Apps/Evince @@ -5040,8 +5013,8 @@ MuPDF~ https://www.mupdf.com/ MuPDF is a very minimalistic and quick PDF viewer. It does not support synctex itself, but VimTeX provides both forward and inverse search by abusing -`xdotool`. Inverse search must be used from within VimTeX with the command -|:VimtexViewRSearch| (mapped to `'lr'`). +`xdotool`. Inverse search must be used from within VimTeX with the mapping +|(vimtex-reverse-search)| (default mapping: `'lr'`). One can also use |g:vimtex_view_mupdf_send_keys| to specify a set of keys that is sent to MuPDF on startup. @@ -5065,8 +5038,8 @@ Note: Viewer handling uses window title matching. If there exists another pdf *vimtex-view-okular* Okular~ https://okular.kde.org/ -Okular is a very feature rich PDF viewer that supports forward and inverse -search. +Okular is a very feature rich PDF viewer that supports both forward and +inverse search. Configuration: > let g:vimtex_view_general_viewer = 'okular' @@ -5074,18 +5047,22 @@ Configuration: > let g:vimtex_view_general_options_latexmk = '--unique' Inverse search can be set up within Okular in the settings pane under -"Settings > Editor > Custom Text Editor". Use configuration as explained in -|vimtex-synctex-inverse-search|. +"Settings > Editor > Custom Text Editor" [0]. Use the viewer configuration as +explained in |vimtex-synctex-inverse-search|. + +To perform an inverse search in Okular, do `shift + click` while browse mode +is enabled. -To perform a inverse search in Okular, do `shift + click` while browse mode is -enabled. +[0]: https://docs.kde.org/stable5/en/okular/okular/inverse_search.html *vimtex-view-qpdfview* qpdfview~ https://launchpad.net/qpdfview qpdfview is a tabbed document viewer. It supports both forward and inverse -search. The latter must be set up from within the viewer. Use configuration as -explained in |vimtex-synctex-inverse-search|. +search. The latter must be set up from within the viewer. Use the viewer +configuration as explained in |vimtex-synctex-inverse-search|, but note that +the interpolation variables should be `%1` for the filename and `%2` for the +line number. Configuration: > let g:vimtex_view_general_viewer = 'qpdfview' @@ -5101,10 +5078,10 @@ books. Configuration: > let g:vimtex_view_general_viewer = 'sioyek' - let g:vimtex_view_general_options = '--reuse-instance ' - \ . '--inverse-search ' - \ . '"nvr --remote-expr \"vimtex#view#reverse_goto(%2, ''%1'')\"" ' - \ . '--forward-search-file @tex --forward-search-line @line @pdf' + let g:vimtex_view_general_options = '--reuse-instance' + \ . ' --inverse-search' + \ . "nvim --headless -c \"VimtexInverseSearch %2 ''%1''\""' + \ . ' --forward-search-file @tex --forward-search-line @line @pdf' let g:vimtex_view_general_options_latexmk = '--reuse-instance' Note: The above configuration assumes that Sioyek is installed and available @@ -5112,6 +5089,9 @@ Note: The above configuration assumes that Sioyek is installed and available be named something like `'Sioyek-x86_64.AppImage'. Make sure to point the |g:vimtex_view_general_viewer| option to the correct path/name! +Note: The `--inverse-search` string should be adapted according to your Vim + flavor, see |vimtex-synctex-inverse-search| for more info. + *vimtex-view-skim* Skim~ https://skim-app.sourceforge.net/ @@ -5124,16 +5104,12 @@ update Skim after successful compilations. Configuration: > let g:vimtex_view_method = 'skim' -To configure inverse search: Open the `Sync` tab in the settings panel in -Skim and set the options according to your desired version of Vim. With -MacVim, one may use the `MacVim` preset. For other versions, one can specify -the `Custom` preset and use configuration as explained in -|vimtex-synctex-inverse-search|. Some remarks: - -* The `Command` should be `nvr` (neovim) or `vim` (Vim). -* The `Arguments` should be the remaining part of the shell commands listed - under |vimtex-synctex-inverse-search|. -* Use `%line` and `%file` instead of `%l` and `%f` to indicate line and file. +To configure inverse search: Open the `Sync` tab in the settings panel in Skim +and set the options according to your desired version of Vim. With MacVim, one +may use the `MacVim` preset. However, it may be more convenient to use a +`Custom` setting and configure the inverse search option as explained in +|vimtex-synctex-inverse-search|. Note that the interpolation variables should +be `%line` and `%file`, not `%l` and `%f`. Inverse search is activated by pressing `Shift` and `Command`, then clicking the text you want to search. @@ -5159,27 +5135,10 @@ For convenience, the above configuration is used by default on Windows if Inverse search must be configured under `Settings --> Options` from within SumatraPDF. Find the section `Set inverse search command-line` in the bottom -and use configuration as explained in |vimtex-synctex-inverse-search|. -Inverse search is activated with a double click in the PDF file. - -It is also possible to specify the inverse search options from Vim/neovim, -although it requires a relatively complex and nasty expression. Something -like this: > +and use the viewer configuration as explained in +|vimtex-synctex-inverse-search|. - let g:vimtex_view_general_options - \ = '-reuse-instance -forward-search @tex @line @pdf' - \ . ' -inverse-search "' . exepath(v:progpath) - \ . ' --servername ' . v:servername - \ . ' --remote-send \"^^' - \ . ':execute ''drop '' . fnameescape(''\%f'')^' - \ . ':\%l^:normal\! zzzv^' - \ . ':call remote_foreground('''.v:servername.''')^^\""' -< -Note: The expected behavior for the multi-line setting above is to refresh - the `InverseSearchCmdLine` setting in SumatraPDF. It may fail if the - Vim/gVim process is not running as Administrator on Windows 10. - A workaround is to ensure to launch Vim as Administrator when editing - tex files. +Inverse search is activated with a double click in the PDF file. Note: There is a known issue with VimTeX + SumatraPDF when you use `xelatex`, where the pdf file in SumatraPDF is not refreshed after compilation. @@ -5189,14 +5148,22 @@ Note: There is a known issue with VimTeX + SumatraPDF when you use `xelatex`, *vimtex-view-zathura* Zathura~ https://pwmt.org/projects/zathura/ -Zathura is, like MuPDF, a very fast and minimalistic viewer, but it allows -more user configuration. Zathura supports forward and inverse search. Zathura -should be straightforward to install and use on Linux with Xorg. It should -also work on macOS, but users may want to read |vimtex-faq-zathura-macos|. +Zathura is, like MuPDF, a very fast and minimalistic viewer. Compared to +MuPDF, it allows more user configuration. Zathura has full support for both +forward and inverse search. Zathura should be straightforward to install and +use on Linux with Xorg. It should also work on macOS, but users may want to +read |vimtex-faq-zathura-macos|. Configuration: > let g:vimtex_view_method = 'zathura' +VimTeX will try to start Zathura with the `-x` argument to specify the inverse +search options automatically. This means that, in most cases, inverse search +should work as expected without any further configuration. One may still be +interested in learning how inverse-search configuration works, in which case +one should read |vimtex-synctex-inverse-search|. The interpolation variables +for Zathura configuration are `%{line}` and `%{input}`, not `%l` and `%f`. + Associated settings: * |g:vimtex_view_zathura_check_libsynctex| * |g:vimtex_view_zathura_options| @@ -5206,9 +5173,6 @@ Note: Forward search requires `xdotool` to work properly. That is, `xdotool` |:VimtexView| command is issued. This is a more severe restriction if the |g:vimtex_view_forward_search_on_start| option is disabled. -Note: VimTeX attempts to pass the server name to zathura for use in reverse - searches. - Note: Recent versions of Zathura no longer ensures synctex support. This has resulted in synctex support being dropped on some platforms, e.g. on OpenSUSE, cf. https://github.com/lervag/vimtex/issues/384. A workaround @@ -5223,7 +5187,7 @@ Note: Viewer handling uses window title matching. If there exists another pdf SYNCTEX SUPPORT *vimtex-synctex* Synctex is a tool that enables synchronization of the text editor position and -the pdf viewer position. The tool may be used to add mappings in vim to go to +the pdf viewer position. The tool may be used to add mappings in vim to go to the current position in the compiled pdf document (forward search), and also to go from a specific position in the pdf file to the corresponding position in vim (inverse search). @@ -5238,112 +5202,59 @@ Alternatively, for |vimtex-compiler-latexmk|, one can put this in ones $pdflatex = 'pdflatex -synctex=1 %O %S'; -Note: For |neovim| users, one must use `neovim-remote` for inverse search. See - |vimtex-faq-neovim| for more info. - Forward search~ *vimtex-synctex-forward-search* For supported viewers, |:VimtexView| (lv) will issue a forward -search if the viewer is already opened. The forward search will take you to +search if the viewer is already opened. The forward search will take you to the page or position in the viewer that corresponds to the current line in -your vim session. See |g:vimtex_view_method| for a list of supported viewers. +your vim session. See |g:vimtex_view_method| for a list of supported viewers. Inverse search~ *vimtex-synctex-inverse-search* *vimtex-synctex-backward-search* -In supported viewers one may set up inverse search, sometimes also called -backward search. When correctly set up, this allows one to go directly from -a selected line in the viewer (typically by double clicking with the mouse or -something similar) to the corresponding line inside the Vim instance. - -NB! Users who want to have inverse search should read this entire section! The - concept is complicated and the best configuration requires some effort - from the user. +In supported viewers, one may set up inverse search, which allows one to go +directly from a selected line in the viewer (typically by double clicking with +the mouse or something similar) to the corresponding line inside the Vim +instance. This is sometimes also called backward search or reverse search. Inverse search relies on communicating with Vim/neovim from the viewer by use -of shell commands. Each Vim or neovim instance is normally available through -a server (see |vimtex-clientserver|). We can communicate by use of the -`--remote*` family of command-line arguments. These command-line arguments are -not available in neovim, but one may use the external utility `nvr` (see -|vimtex-faq-neovim|). - -Inverse search is usually set up within the specific viewer through an option -named something like "inverse search command-line". Here one specifies -a desired shell command where the target line and file are interpolated, -usually as `%l` and `%f` (but this may be different in some viewers, e.g. -|vimtex-view-okular|). The following are some simple examples of possible -configurations for Vim and neovim (`nvr`). This also shows how one may use the -utility function |vimtex#view#reverse_goto|. > - - vim --remote-silent +%l '%f' - nvr --remote-silent +%l '%f' - - vim --remote-expr vimtex#view#reverse_goto(%l, '%f') - nvr --remote-expr vimtex#view#reverse_goto(%l, '%f') - - vim --servername MYSERVER --remote-silent +%l '%f' - nvr --servername /tmp/mynvimserver --remote-silent +%l "%f" - -If one always uses a single instance of Vim/neovim, then one normally don't -need to specify the servername. A couple of caveats: -* With Vim, it is important to ensure that the server is running; please read - |vimtex-clientserver|! -* With neovim, `nvr` will not work unless it knows the correct servername! The - above simple solutions may still work, because neovim sets the environment - variable |$NVIM_LISTEN_ADDRESS|. If this environment variable is inherited - by the PDF viewer, then it will also be available to the forked `nvr` - command. - -Although the simple configuration examples above may work, they are prone to -failure. For instance, if you use multiple instances of Vim or neovim, or if -you for some reason open the viewer outside of VimTeX, then inverse search may -not work as expected. To get a more robust experience, one should configure -both VimTeX and the PDF viewer so as to use an explicit servername. - -The most straightforward way is to specify the servername when starting -Vim/neovim and then use that same servername in the viewer configuration. To -specify the servername for Vim and neovim, use the following command-line -arguments: > - - # For Vim - vim --servername NAME - - # For neovim - nvim --listen /tmp/mynvimservername - -This is simple and works, but may be somewhat cumbersome. Also, if you start -several instances of Vim or neovim and specify the same servername, then only -the first instance will actually have that specific servername. - -Another, possibly more convenient way to specify the servername is to use -a trick by @jdhao [0, 1]. The idea is to manually write the servername to -a file when we open a `.tex` file. Add the following to your init.vim: > - - augroup vimtex_common - autocmd! - autocmd FileType tex call writefile( - \ [v:servername], - \ (has('win32') ? $TEMP : "/tmp") . "/vimtexserver.txt") - augroup END +of shell commands executed by the viewer. Each Vim or neovim instance is +(normally) available for communication as a server. Vim users should be aware, +though, that one may need to ensure that the server is really running, see +|vimtex-clientserver|. + +Inverse search is set up within the specific viewer through an option named +something like "inverse search command-line". The option specifies the +necessary shell command to perform the inverse search. The target line and +file are provided as interpolation variables. In the following, we use `%l` +and `%f`, but the interpolation variables may be named different in some +viewers (e.g. |vimtex-view-skim|). + +Common configuration that one would find documented often looks like this: > + + vim --remote-silent +%l %f + +However, VimTeX provides a convenience function to simplify the viewer +configuration. So, instead it is recommended to use the following viewer +configuration with Vim or neovim, respectively: > -We also need to specify this servername within the viewer configuration. The -following shows commands that should work on both Linux, MacOS and Windows for -both Vim and neovim (`nvr`): > + vim -v --not-a-term -T dumb -c "VimtexInverseSearch %l '%f'" - # Linux and MacOS - vim --servername `cat /tmp/vimtexserver.txt` --remote-silent +%l "%f" - nvr --servername `cat /tmp/vimtexserver.txt` --remote-silent +%l "%f" + nvim --headless -c "VimtexInverseSearch %l '%f'" - # Windows - cmd /c for /F %i in ('type C:\Users\ADMINI~1\AppData\Local\Temp\vimtexserver.txt') do vim --servername %i --remote-silent +%l "%f" - cmd /c for /F %i in ('type C:\Users\ADMINI~1\AppData\Local\Temp\vimtexserver.txt') do nvr --servername %i --remote-silent +%l "%f" +The command `VimtexInverseSearch` will execute |vimtex#view#inverse_search| +with the target line and file as arguments inside the desired Vim or neovim +instance. The latter function is the one that really performs the inverse +search. The combined effect is a more robust experience that will seamlessly +handle multiple Vim or neovim instances and multiple VimTeX instances. The +user doesn't need to worry about passing the correct servernames. -On Windows, please note that you may need to change the exact file path above. -You can use the command `:echo $TEMP` within Vim/neovim to inspect the value. +Note: The above commands should work also on Windows, but there may be an + annoying command window "popup". This may be avoided, or at least + reduced, if one prepends `cmd /c start /min ""`, e.g.: > -[0]: https://jdhao.github.io/2021/02/20/inverse_search_setup_neovim_vimtex -[1]: https://jdhao.github.io/2019/03/26/nvim_latex_write_preview/#inverse-search-for-sumatra-pdf-on-windows + cmd /c start /min "" nvim --headless -c "VimtexInverseSearch %l '%f'" ============================================================================== LATEX DOCUMENTATION *vimtex-latexdoc* @@ -5491,11 +5402,10 @@ Note: This API is currently a work in progress! arguments, the position refers to the cursor position. Else must be called with two arguments: the line number and column number. -*vimtex#view#reverse_goto* +*vimtex#view#inverse_search* Utility function for reverse search from pdf viewer. Takes two arguments: the line number and a filename. The function runs the event - |VimtexEventViewReverse| at the end, which allows some user flexibility in - behaviour after the reverse goto was issued. + |VimtexEventViewReverse| at the end, which allows more user customization. *vimtex#env#get_inner* *vimtex#env#get_outer* @@ -5573,29 +5483,6 @@ A: This might be due to the |isfname| setting, which by default contains `{,}` set isfname-={,} < ------------------------------------------------------------------------------- - *vimtex-faq-neovim* -Q: Does VimTeX work with neovim? -A: Yes, but inverse search from PDF viewer to VimTeX requires `nvr` - (neovim-remote) [0]. This is because neovim does not have the `--remote` - family of options itself [0]. To install `nvr`: - - 1. Install the `pynvim` and `neovim-remote` modules for python3, e.g. > - - pip3 install --user pynvim neovim-remote -< - 2. Test; if the following returns without error and if `nvr` starts - neovim from the command line, you should be good to go. > - - python3 -c "import pynvim" -< - It is worth mentioning that for `nvr` to communicate with a neovim - instance, one generally needs to indicate the proper servername, see - |v:servername|. - - [0]: https://github.com/mhinz/neovim-remote - [1]: https://github.com/neovim/neovim/issues/1750 - ------------------------------------------------------------------------------ *vimtex-faq-tags* Q: How can I jump from a `\ref{label}` to the corresponding label? @@ -5680,12 +5567,6 @@ A: Yes and no. I personally don't use Windows, and as such, it is difficult should work. Here are some things that might not work quite as expected, with some workarounds. - * The full executable path for `gvim.exe` might include spaces, which might - lead to problems, see e.g. [0]. A workaround is to put the default - installation path of Vim (or neovim) to your %PATH% variable and set - |g:vimtex_compiler_progname| to |v:progname|. See [3] for a convenient - tool to adapt %PATH%. - * VimTeX does not work well with the 'shell' setting set to Windows PowerShell. It is therefore recommended to use the default 'shell' settings. See [4] for more information. @@ -5889,6 +5770,9 @@ The following changelog only logs particularly important changes, such as changes that break backwards compatibility. See the git log for the detailed changelog. +2021-10-25: Better inverse search~ +Deprecate *g:vimtex_compiler_progname* as it is no longer necessary. + 2021-10-09: Better options for syntax conceal~ Deprecate *g:vimtex_syntax_conceal_default* in favor of |g:vimtex_syntax_conceal_disable|. The new option makes things more explicit diff --git a/plugin/vimtex.vim b/plugin/vimtex.vim new file mode 100644 index 0000000000..bcf40dce1e --- /dev/null +++ b/plugin/vimtex.vim @@ -0,0 +1,25 @@ +" VimTeX - LaTeX plugin for Vim +" +" Maintainer: Karl Yngve LervÄg +" Email: karl.yngve@gmail.com +" + +if !get(g:, 'vimtex_enabled', 1) | finish | endif +if exists('g:loaded_vimtex') | finish | endif +let g:loaded_vimtex = 1 + + +command! -nargs=* VimtexInverseSearch + \ call call('vimtex#view#inverse_search_cmd', s:parse_args()) + + +function! s:parse_args(args) abort + let l:line = matchstr(a:args, '^\s*\zs\d\+') + if empty(l:line) | return [-1, ''] | endif + + let l:file = matchstr(a:args, '^\s*\d\+\s*\zs.*') + let l:file = substitute(l:file, '\v^([''"])(.*)\1\s*', '\2', '') + if empty(l:file) | return [-1, ''] | endif + + return [str2nr(l:line), l:file] +endfunction diff --git a/test/test-compiler/test-backend.vim b/test/test-compiler/test-backend.vim index 95ccc971a5..e44c9fd61e 100644 --- a/test/test-compiler/test-backend.vim +++ b/test/test-compiler/test-backend.vim @@ -7,10 +7,6 @@ set nomore let g:vimtex_view_automatic = 0 let g:vimtex_log_verbose = 0 -if has('nvim') - let g:vimtex_compiler_progname = 'nvr' -endif - function! RunTests(comp, list_opts) if !executable(a:comp) echo 'Warning! "' . a:comp . '" was not executable!' diff --git a/test/test-options/Makefile b/test/test-options/Makefile deleted file mode 100644 index e52fd6df64..0000000000 --- a/test/test-options/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -.PHONY: test - -MYVIM ?= nvim --headless - -INMAKE := 1 -export INMAKE - -test: - @$(MYVIM) -u test.vim diff --git a/test/test-options/main.tex b/test/test-options/main.tex deleted file mode 100644 index 2e99f1958a..0000000000 --- a/test/test-options/main.tex +++ /dev/null @@ -1,6 +0,0 @@ -\documentclass{minimal} -\begin{document} - -Hello World! - -\end{document} diff --git a/test/test-options/test.vim b/test/test-options/test.vim deleted file mode 100644 index 4eb3603e86..0000000000 --- a/test/test-options/test.vim +++ /dev/null @@ -1,18 +0,0 @@ -set nocompatible -let &rtp = '../..,' . &rtp -filetype plugin on - -nnoremap q :qall! - -silent edit main.tex - -if empty($INMAKE) | finish | endif - -let s:progname = get(v:, 'progpath', get(v:, 'progname', '')) -if has('nvim') && executable('nvr') - let s:progname = 'nvr' -endif - -call assert_equal(g:vimtex_compiler_progname, s:progname) - -call vimtex#test#finished() diff --git a/test/test-view/Makefile b/test/test-view/Makefile new file mode 100644 index 0000000000..b35377eaf0 --- /dev/null +++ b/test/test-view/Makefile @@ -0,0 +1,14 @@ +MYVIM ?= nvim --headless + +INMAKE := 1 +export INMAKE + +TESTS := $(wildcard test*.vim) +TESTS := $(TESTS:.vim=) + +.PHONY: default $(TESTS) + +default: $(TESTS) + +$(TESTS): + @$(MYVIM) -u $@.vim diff --git a/test/test-view/included.tex b/test/test-view/included.tex new file mode 100644 index 0000000000..3169efc33d --- /dev/null +++ b/test/test-view/included.tex @@ -0,0 +1,4 @@ +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod +tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At +vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd +gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. diff --git a/test/test-view/main.tex b/test/test-view/main.tex new file mode 100644 index 0000000000..d9918e1f9d --- /dev/null +++ b/test/test-view/main.tex @@ -0,0 +1,19 @@ +\documentclass{article} +\usepackage[utf8]{inputenc} +\usepackage{graphicx} + +\begin{document} + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod +tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At +vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd +gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod +tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At +vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd +gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +\include{included} + +\end{document} diff --git a/test/test-view/test_inverse_search.vim b/test/test-view/test_inverse_search.vim new file mode 100644 index 0000000000..f71c4f1667 --- /dev/null +++ b/test/test-view/test_inverse_search.vim @@ -0,0 +1,42 @@ +set nocompatible +let &rtp = '../..,' . &rtp +filetype plugin on + +set hidden + +nnoremap q :qall! +call vimtex#log#set_silent() + +let s:result = vimtex#view#inverse_search(10, 'main.tex') +call assert_equal(-1, s:result) + +silent edit test.tex + +let s:result = vimtex#view#inverse_search(10, 'main.tex') +call assert_equal(-2, s:result) + +bwipeout! +let g:vimtex_view_reverse_search_edit_cmd = 'splitview' +silent edit main.tex +let s:result = vimtex#view#inverse_search(2, 'included.tex') +let s:log = vimtex#log#get() +call assert_equal(-3, s:result) +call assert_equal('Command error: splitview included.tex', s:log[0].msg[1]) + +bwipeout! +let g:vimtex_view_reverse_search_edit_cmd = 'edit' +silent edit main.tex +call add(b:vimtex.sources, 'new.tex') +let s:result = vimtex#view#inverse_search(2, 'new.tex') +let s:log = vimtex#log#get() +call assert_equal(-4, s:result) +call assert_equal('File not readable: "new.tex"', s:log[1].msg[1]) + +bwipeout! +silent edit main.tex +call assert_equal('main.tex', expand('%:t')) +call vimtex#view#inverse_search(3, 'included.tex') +call assert_equal('included.tex', expand('%:t')) +call assert_equal(3, line('.')) + +call vimtex#test#finished()