Skip to content

(view) b:vimtex.viewer.xwin_id corresponds to unexpected window when multiple PDFs are open #2415

@ejmastnak

Description

@ejmastnak

Description

In an admittedly unusual scenario (described below in the steps to reproduce) the variable b:vimtex.viewer.xwin_id is set to a window that is different from the window holding the PDF corresponding to the LaTeX file edited with VimTeX.

Not a big issue, but it is inconvenient when automatically closing windows using the VimtexEventQuit autocommand and CloseViewers() function workflow given as an example in :help vimtex-events---in certain cases the CloseViewers() function, which uses b:vimtex.viewer.xwin_id, will close the "wrong" PDF, i.e. not the PDF associated with the edited LaTeX file.

This workflow arises when I first open a third-party PDF (e.g. a paper, textbook, etc...), then open a LaTeX file in which I take notes about the content of the third-party PDF. Exiting VimTeX will then close the third-party PDF, instead of the PDF associated with my notes.

Files

minimal.tex

\documentclass{minimal}
\begin{document}
Hello world!
\end{document}

minimal.vim

set nocompatible
let &runtimepath  = './vimtex,' . &runtimepath
let &runtimepath .= ',./vimtex/after'
filetype plugin indent on
syntax enable

" Relevant options and VimTeX configuration below.
let g:vimtex_view_method = 'zathura'

" Close viewers when VimTeX buffers are closed (see :help vimtex-events)
function! CloseViewers()
  if executable('xdotool')
        \ && exists('b:vimtex.viewer.xwin_id')
        \ && b:vimtex.viewer.xwin_id > 0
    call system('xdotool windowclose '. b:vimtex.viewer.xwin_id)
  endif
endfunction

augroup vimtex_event_close
  au!
  au User VimtexEventQuit call CloseViewers()
augroup END

" Only for personal convenience when testing
let mapleader = " "
nmap <leader>i <plug>(vimtex-info)
nmap <leader>v <plug>(vimtex-view)
nmap <leader>c <plug>(vimtex-compile)

Possible change

(I thought I would get your opinion before diving headfirst into PRs, since you know the codebase much better and will probably have a better idea than I would.)

First, it seems the problem is only relevant to mupdf and zathura, since only those viewers have a xwin_id property.

The problematic code seems to be the following block in the s:viewer.xdo_get_id() function in autoload/vimtex/view/_template.vim:

let l:xwin_ids = vimtex#jobs#capture('xdotool search --class ' . self.name)
if len(l:xwin_ids) == 0
  call vimtex#log#warning('Viewer cannot find ' . self.name . ' window ID!')
  let self.xwin_id = 0
else
  " Taking the last ID returned by e.g. `xdotool search --class Zathura` can give unexpected results
  let self.xwin_id = l:xwin_ids[-1]
endif

If the viewer template had access to the viewer's PID in an e.g. self.pid property, my idea would be to first try...

let l:xwin_ids = vimtex#jobs#capture('xdotool search --pid ' . self.pid)

...and only then use the existing...

let l:xwin_ids = vimtex#jobs#capture('xdotool search --class ' . self.name)

...as a fallback, e.g. if self.pid is undefined. That is, first try to get window ID from viewer PID before searching by window class---I imagine searching by PID would be more robust.
It seems that the zathura.vim file does have some knowledge of the Zathura viewer's PID (e.g. the s:viewer.get_pid() function), but I am unsure of the best way to get this information from zathura.vim to _template.vim. (Perhaps you have already considered this and it is more nontrivial than I imagine.)

And of course this is admittedly an edge case/weird workflow, so if you deem it more bother than it's worth, no problem.
It's certainly not a dealbreaker to using VimTeX :)

Steps to reproduce

  1. Relevant files:
    $ ls
    minimal.vim
    minimal.tex
    other.pdf       # an arbitrary non-empty PDF file
    vimtex/         # a clean copy of VimTeX for the purposes of testing this issue
  2. Open other.pdf in Zathura: zathura other.pdf & (from the same shell that will then run NeoVim, hence opening in the background). Note that opening other.pdf in a separate shell from the one subsequently used to open NeoVim does not reproduce the issue.
  3. Open NeoVim nvim --clean -u minimal.vim minimal.tex (I also use --clean to avoid loading my own ftplugin)
  4. :VimtexCompile
  5. :VimtexView (Zathura successfully opens and displays minimal.pdf)
  6. :echo b:vimtex.viewer.xwin_id (or call :VimtexInfo)
  7. Use e.g. xdotool selectwindow from a separate shell to confirm that the echoed window ID corresponds to the window containing other.pdf, and not to the window containing minimal.pdf
  8. Exit Vim (e.g. :wq)

Expected behavior

b:vimtex.viewer.xwin_id from the previous step is the window ID of the window containing minimal.pdf.
(And minimal.pdf is closed by the CloseViewers() function in minimal.vim).

Actual behavior

b:vimtex.viewer.xwin_id is the window ID of the window containing other.pdf.
(And other.pdf is closed by the CloseViewers() function in minimal.vim).

Do you use a latexmkrc file?

No

VimtexInfo

System info:
  OS: Linux 5.16.11-arch1-1
  Vim version: NVIM v0.7.0
  Has clientserver: true
  Servername: /tmp/nvimzxz3Eo/0

VimTeX project: minimal
  base: minimal.tex
  root: /home/ej/tmp/vimtex-xdo-bug
  tex: /home/ej/tmp/vimtex-xdo-bug/minimal.tex
  main parser: current file verified
  document class: minimal
  compiler: latexmk
    engine: -pdf
    options:
      -verbose
      -file-line-error
      -synctex=1
      -interaction=nonstopmode
    callback: 1
    continuous: 1
    executable: latexmk
  viewer: Zathura
    xwin id: 44040195
    cmd_start: zathura  -x "/usr/bin/nvim --headless -c \"VimtexInverseSearch %{line} '%{i
  qf method: LaTeX logfile

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions