The Spectre of Math

January 13, 2011

Vim, Evince and forward and backward LaTeX synctex search

Filed under: Hacking,LaTeX — jlebl @ 11:35 pm

I was finally fed up with not having forward and backward search in vim so I hacked up the python script that was in the gedit synctex package to do what I needed. The result is evince_vim_dbus.py (GNOME 2.32 version) or evince_vim_dbus.py (GNOME 3 version old LaTeX) or evince_vim_dbus.py (GNOME 3 version that works with TexLive 2011). Copy it somewhere into your PATH (say ~/bin or /usr/local/bin). The first argument is EVINCE or GVIM. If it is EVINCE then it works just like the evince_dbus.py from the gedit synctex package. So to do forward search you add something like the following to your .vimrc file. This uses the LatexBox set of vim macros, which is pretty unobtrusive and kind of useful

function! LatexEvinceSearch()
execute "!cd " . LatexBox_GetTexRoot() . '; evince_vim_dbus.py EVINCE "`basename ' . LatexBox_GetOutputFile(). '`" ' . line('.') . ' "%:p"'
endfun
command! LatexEvinceSearch call LatexEvinceSearch()
au FileType tex map ls :silent LatexEvinceSearch

Make sure to compile your latex file with pdflatex –synctex=1 thefile. Now to jump to the right place in evince just type \ls in vim at the right spot. For vim-latex I assume something like the following would work though I have not tried so this may not actually work:

let g:Tex_ViewRule_pdf = 'evince_vim_dbus.py EVINCE'
let g:Tex_DefaultTargetFormat = 'pdf'
let g:Tex_CompileRule_pdf = 'pdflatex --synctex=1 -interaction=nonstopmode $*'

Now to do inverse search, what you want to do is open up evince with the .pdf file, open gvim with the file with something like: gvim –servername foo thefile.tex. The –servername argument will let us communicate with that instance of gvim. Now run

evince_vim_dbus.py GVIM foo thefile.pdf thefile.tex

This will keep running and will talk to evince and when you control-click somewhere the script will call the “foo” instance of gvim and tell it to go to the right line. You have to kill this script once you are done. Yeah I know this is kind of ugly, but the way synctex is done in evince is kind of moronic. The idea is I think to make the thing as complicated as possible to satisfy someone’s CS design fetish rather than to make the thing simple and easily usable (such as doing it by calling evince with the right arguments and giving evince a command to execute) … but then no script like this would be needed.

I also have a modified whaw: whaw-jiri-0.1.2.tar.gz. When you run whaw –htile you will get a different cursor, you can left click bunch of windows and then right click and whaw will put the windows side by side. The standard whaw works as well, but the –htile is usable from scripts.

Finally to put it all together I have a script that runs everything for me called buildpdftexwatch (slightly modified version of the script from my homepage) which works as follows (by the way you need zsh installed for the script). You run buildpdftexwatch thefile where thefile doesn’t have any extension. The script will open thefile.tex in gvim and thefile.pdf in evince. If you have the modified whaw it will run it with –htile (otherwise it won’t run whaw). The script watches the .tex file and whenever you save in vim it will rerun pdflatex. (it also runs pdflatex in interactive mode when first invoked before it runs evince actually). It runs pdflatex in noninteractive mode afterwards so that it doesn’t hang. It will notify you of errors by barking (that is if you have ogg123 and the default gnome sound /usr/share/sounds/gnome/default/alerts/bark.ogg installed.

This setup is not perfect. Yeah I know I should probably rewrite the shell script to work in python so that the dbus thing can be done from the script itself. However, evince also sucks so I’d rather just use xpdf, but that does not yet have synctex support. At some point I may be enough annoyed with evince that I will hack xpdf to do synctex (and do it in the simple nondbusy way that will make it easy to work with all kinds of editors). For now … this works good enough.

Update: Make sure to use the latest evince (at least 2.32.0) as older versions do not have synctex support.

Update: GNOME 3 evince breaks the dbus interface and the above python code. (So what’s the advantage of using dbus here? It is total overkill, isn’t documented well (as far as I can find), and breaks from release to release anyway). The least that evince could do is to have command line options so that one does not need to do dbus black magic to make it work. Anyway I had to fix it up and now there are two versions, one for GNOME 3 and one for GNOME 2.32. I also integrated the below comment from Simon.

Update: New braindamage coming (this time) from TexLive 2011 synctex. Apparently we must now insert /./ into the path or synctex will refuse to work. This is wrong on so many levels it is not even funny. That means there are 3 distinct versions of this code with just slightly different semantics. Somebody somewhere should get a smack over the head when a new feature that most people likely won’t ever use will break all existing usage. Certain people should not be allowed to design public facing APIs. Also there might be some change in the way vim does the current filename thing because the script was now getting full path name for the input file, so I had to fix that too. I am not quite sure what happened there though so I am not ready to blame vim. I can’t understand however how else could have the old version have worked before.

Update: New changes in GNOME.  So apparently the API changed again.  Where we got a filename before apparently we now get a uri (which I suppose is more consistent but a break in the API again).  So I updated the code to strip “file://” if it finds it.  Should still work with older evinces, and with new.  I have now tested it with evince 3.8 and TexLive 2012.

11 Comments »

  1. This is great work, thank you

    Comment by Yigal Weinstein — March 18, 2011 @ 8:56 pm | Reply

  2. Adding the following two lines to the script buildpdftexwatch (e.g. after export REMOTE_VIM_ID) allows to run the script (a) from any directory and (b) with .tex suffix:

    cd $(dirname $1)
    1=$(basename $1 .tex)

    Comment by Simon — March 22, 2011 @ 7:54 pm | Reply

  3. I changed the gVim call to the follwing. I could remove the corresponding lines from the .vimrc and this allows to use Vim w/o SyncTex as well.


    gvim \
    --servername $REMOTE_VIM_ID \
    "+let g:Tex_ViewRule_pdf = 'evince_vim_dbus.py EVINCE'" \
    "+let g:Tex_DefaultTargetFormat = 'pdf'" \
    "+let g:Tex_CompileRule_pdf = 'pdflatex --synctex=1 -interaction=nonstopmode $*'" \
    "$1.tex"

    Btw: have you considered setting up a githup project for your scripts? That would ease updating the scripts and contributing to your work.

    Simon

    Comment by Simon — May 14, 2011 @ 8:56 am | Reply

  4. Hi, I am sorry I had to break the DBUS API for the synctex support, The API should be stable by now (meaning I’ll try hard not to break it) If you only worry about vim then yes DBUS is overkill, but if you worry about other apps like Gedit (and I do) then DBus is the “natural” way of communicating between apps, the main reason is not to have to spawn new processes each time you perform a forward or backward search.

    José

    Comment by José Aliste — May 24, 2011 @ 7:12 pm | Reply

    • But dbus should be an implementation detail here IMO. evince could still provide the command line support so that dbus is not needed. (not to mention that I could not easily find any docs on the API to begin with)

      dbus is nice and all but it has the disadvantage of being hard to use. Especially from a script.

      Jiri

      Comment by jlebl — May 24, 2011 @ 8:34 pm | Reply

      • Yeah, it should be an implementation detail… My original idea was to write a Vim plugin and a Emacs plugin using the DBUS interface so using the evince synctex support would be configuration free, but got sidetracked… Anyway, feel free to hang around irc.gimp.net #evince to get this to a better state for (at least) vim users instead of just guessing and assuming what my motivations are 🙂

        Comment by jose — May 26, 2011 @ 2:05 am

  5. I’ve created a similar solution as a vim plugin. It only works in gVim (because it hooks into the glib main loop) and must have python support.
    You can try it from https://github.com/peder2tm/sved if you want. Note that it has not been heavily tested yet.

    Comment by Peter B Jørgensen — July 10, 2011 @ 9:17 pm | Reply

  6. Thank you, it works perfectly with pdflatex !

    While, can we adapt it to xelatex ? (replace pdflatex with xelatex ?)
    I’ve noticed the the cursor miss the corresponding line in the “backward LaTeX synctex search”.
    (Does it need to modify the following ?
    “os.system(‘gvim –servername “‘ + gvim_server_name + ‘” –remote +’ + str(source_link[0]-7) + ‘ ‘ + input_file) ” )

    Comment by hli — February 24, 2012 @ 8:28 pm | Reply

    • Not sure, I’ve never tried it with xelatex. Ill try it out.

      Comment by jlebl — February 25, 2012 @ 12:38 am | Reply

  7. As for inserting /./ in the file path: this is indeed annoying and it is fixed in the latest version of synctex. It will have quite elastic file path searching algorithm. You can read about it directly in the project sources (see changes for version 1.17):
    http://ftp.tug.org/svn/texlive/trunk/Build/source/texk/web2c/synctexdir/synctex_parser_readme.txt?view=markup

    Comment by Marcin — March 30, 2012 @ 3:43 pm | Reply

  8. I’ve just found that post, three years late! This is so simple and so useful! Thank you so much for sharing.

    Comment by D. Munger — February 28, 2014 @ 6:21 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.