Forward-backward search with vim-latex and evince

Some of us enjoy having a single powerful tool for many applications. In my case I use vim to edit all sorts of documents. One downside of this is that it may lack some features that format-specific applications provide. For instance, when it comes to LaTeX editing the possibility of searching where the current text is in the compiled PDF and vice versa is quite useful.

This functionality is supported on vim by the well known plugin latex-vim-suite, but only for some viewers like Okular. Evince does not support this functionality out of the box and some extra configurations are required. This article explains how to do that.

The process is a bit involved and requires feeling comfortable using a terminal and configuring a couple of things, but if you use vim chances are that you are the kind of person that likes to tweak and customize the OS.

Storing compilation-generated files in a single folder

This thing is not strictly necessary, but since I use this configuration throughout the whole article and I’m lazy, I rather write this section than adapt the whole thing to a more standard setup.

I don’t like all those .aux, .log, .synctex files lying around with my .tex and .bib files, so I will configure latex-suite to create a folder called output where all the files generated by the compilation process, including the PDF, will be stored.

So, hands on work. I installed latex-suite using pathogen, so the base directory for my installation is .vim/bundle/vim-latex-suite-master/. First make sure that your default compilation format is PDF. Find the following lines in ftplugin/latex-suite/texrc

if has('macunix')
        TexLet g:Tex_DefaultTargetFormat = 'pdf'
else
        TexLet g:Tex_DefaultTargetFormat = 'dvi'
endif

And replace them with this single one:

TexLet g:Tex_DefaultTargetFormat = 'pdf'

Now we gonna change the compiler rules to customize the command that is executed to generate the PDF. In the same file ftplugin/latex-suite/texrc find the following line:

TexLet g:Tex_CompileRule_pdf =  ...

And change it into:

TexLet g:Tex_CompileRule_pdf = 'mkdir '.g:Tex_Outputdir.' & pdflatex -synctex=1 -interaction=nonstopmode -file-line-error-style -output-directory='.g:Tex_Outputdir.' $*'

Among other things, this command will put all the files generated by the compilation process in their own folder, the folder name is in Tex_Outputdir. Of course you can customize it at your own taste.

Ok, but what’s the name of this output folder you speak of?. Well, we have to define Tex_Outputdir somewhere, let’s do it in ftplugin/tex_latexSuite.vim. Add these lines at the top of the file, right below the copyright comments.

" Set the compilation output directory
let g:Tex_Outputdir = 'output'

Of course if you want to name the output folder other than output you can do it there.

Now we can test it with a simple document. Something like this:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}

\author{Geri}
\date{\today}
\title{Something unimportant}

\begin{document}
     Benjamín pidió una bebida de kiwi y fresa. Noé, sin vergüenza, la más
     exquisita champaña del menú.

The quick brown fox jumps over the lazy dog.
\end{document}

Save it and press \ll. In my case I’ve remapped my mapleader to , so I press ,ll and that will create the folder if it doesn’t exist and compile the document.

Now we are ready to actually configure forward and backward search.

Set up vim

For this to work we need to run vim in server mode. I prefer to use the alias vimtex to run vim on this particular mode, so just putting the following at the bottom of .bashrc does the trick:

alias vimtex='vim --servername LATEX $*'

So if I want to open a LaTeX file, say test.tex, I run vimtex test.tex.

Set up evince

You need to create 3 files inside your bin folder and make them executable. You will basically customize how evince is launched. One of the files is called evince and will overwrite the default command. In case you want to read the content of this particular file this is it:

#!/bin/sh

EDITORCMD="vim --servername 'LATEX' --remote-silent '+%l<Enter>:match Search /\%%ll/' %f"

PDFFILE="$1"
if [ -f "$PDFFILE" ];then
        if [ -f "${PDFFILE%%.pdf}.synctex.gz" ];then
                evince_backward_search "$PDFFILE" "$EDITORCMD"&
                BACKWARD_SEARCH_PID=$!
                echo $BACKWARD_SEARCH_PID
        fi
fi

/usr/bin/evince "$@"

if [ "$BACKWARD_SEARCH_PID" ];then
        echo "Killing $BACKWARD_SEARCH_PID"
        kill $BACKWARD_SEARCH_PID
fi

Notice that the name of the vim server, LATEX, is used here, so keep that in mind if you decide to use a different server name for the vimtex alias. If you decide to keep the same configurations I use just download the files from this repo, put them in your bin folder and make them executable.

chmod u+x evince evince_forward_search evince_backward_search

Configure latex-suite

Now we need to make a few more changes to latex-suite. Open the file ftplugin/latex-suite/texrc again (you are using vim, come on don’t close and reopen; use buffers, tabs, split screen) and look for these lines:

if executable('xdg-open')
        TexLet g:Tex_ViewRule_ps = 'xdg-open'
        TexLet g:Tex_ViewRule_pdf = 'xdg-open'
        TexLet g:Tex_ViewRule_dvi = 'xdg-open'

And replace them with these.

if executable('xdg-open')
        TexLet g:Tex_ViewRule_ps = 'evince'
        TexLet g:Tex_ViewRule_pdf = 'evince'
        TexLet g:Tex_ViewRule_dvi = 'evince'

We have to use explicitly evince instead of xdg-open for the search to work. Of course you can get rid of that if statement altogether if you want.

Now we need to configure LaTeX suite to add a simple command to automatically open the PDF once it’s compiled. We go and edit ftplugin/tex_latexSuite.vim and add the following line right below the one we added in the first section.

map <Leader>lo :call system('$HOME/bin/evince ./'.g:Tex_Outputdir.'/'.expand('%:r').'.pdf>/dev/null&')<Enter>

What this does is bind ,lo to open your PDF with evince from vim.

Now to enable forward search add the following at the bottom of that same file:

function! Tex_ForwardSearchLaTeX()
         let commandline = 'evince_forward_search ./'.g:Tex_Outputdir.'/'.expand('%:r').'.pdf '. line(".") .' '.expand("%:p")
         let output = system(commandline)
endfunction

Just for the sake of completeness this is how the file will end up looking after all the changes:

" LaTeX filetype
"         Language: LaTeX (ft=tex)
"       Maintainer: Srinath Avadhanula
"                Email: srinath@fastmail.fm

" Set the compilation output directory
let g:Tex_Outputdir = 'output'

map <Leader>lo :call system('$HOME/bin/evince ./'.g:Tex_Outputdir.'/'.expand('%:r').'.pdf>/dev/null&')<Enter>


if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
        finish
endif

if !exists('s:initLatexSuite')
        let s:initLatexSuite = 1
        exec 'so '.fnameescape(expand('<sfile>:p:h').'/latex-suite/main.vim')

        silent! do LatexSuite User LatexSuiteInitPost
endif

silent! do LatexSuite User LatexSuiteFileType

" Infect the current buffer with <buffer>-local imaps for the IMAPs
call IMAP_infect()

function! Tex_ForwardSearchLaTeX()
         let commandline = 'evince_forward_search ./'.g:Tex_Outputdir.'/'.expand('%:r').'.pdf '. line(".") .' '.expand("%:p")
         let output = system(commandline)
endfunction

Testing

Now everything should be working. Close vim and your terminal to make sure all the recent changes are picked by your system. Then create a new .tex file, compile it with ,ll, open it with ,lo. Move to a line in your file and press ,ls, the corresponding text should be highlighted in the PDF as shown in this screenshot:

R Studio

On the other hand, to do backward search use CTRL + click on evince and the corresponding line should be highlighted in you vim document.

R Studio

I have been using this for about 5 year now. I found the python files and ideas on a StackOverflow post but I’ve lost the link, so shout out to those anonymous nerds that inspired this.