Hello,
I have adapted ben's Python code to Emacs lisp for forward search using AUCTeX.
The following code in .emacs does the job if the D-bus support of Emacs is available. Pressing C-c C-v will jump to the output line corresponding to the current line in the source buffer. A new Evince window is started if the document is not yet opened.
Note: the inverse search code is by Tassilo Horn and I included it for completeness.Code:;; Forward/inverse search with evince using D-bus. (if (require 'dbus "dbus" t) (progn ;; Forward search. ;; Adapted from http://dud.inf.tu-dresden.de/~ben/evince_synctex.tar.gz (defun auctex-evince-forward-sync (pdffile texfile line) (let ((dbus-name (dbus-call-method :session "org.gnome.evince.Daemon" ; service "/org/gnome/evince/Daemon" ; path "org.gnome.evince.Daemon" ; interface "FindDocument" (concat "file://" pdffile) t ; Open a new window if the file is not opened. ))) (dbus-call-method :session dbus-name "/org/gnome/evince/Window/0" "org.gnome.evince.Window" "SyncView" texfile (list :struct :int32 line :int32 1)))) (defun auctex-evince-view () (let ((pdf (file-truename (concat default-directory (TeX-master-file (TeX-output-extension))))) (tex (buffer-file-name)) (line (line-number-at-pos))) (auctex-evince-forward-sync pdf tex line))) ;; New view entry: Evince via D-bus. (add-to-list 'TeX-view-program-list '("EvinceDbus" auctex-evince-view)) ;; Prepend Evince via D-bus to program selection list ;; overriding other settings for PDF viewing. (add-to-list 'TeX-view-program-selection '(output-pdf "EvinceDbus")) ;; Inverse search. ;; Adapted from: http://www.mail-archive.com/auctex@gnu.org/msg04175.html (defun auctex-evince-inverse-sync (file linecol) (let ((buf (get-buffer (file-name-nondirectory file))) (line (car linecol)) (col (cadr linecol))) (if (null buf) (message "Sorry, %s is not opened..." file) (switch-to-buffer buf) (goto-line (car linecol)) (unless (= col -1) (move-to-column col))))) (dbus-register-signal :session nil "/org/gnome/evince/Window/0" "org.gnome.evince.Window" "SyncSource" 'auctex-evince-inverse-sync)))
Regards,
Florian
The backward search script works great for me, if I call instead of evince our evince script (let call it evince-sync). However if I start it like
evince-sync -p 10 file.pdf
backward search doesn't work (it just does nothing). Any idea how to fix this? I guess it should be a minor change in your code...
Using the -p option is the standard forward search method from emacs. I tried to use your method for forward search, but it didn't work.
The new Evince in Ubuntu 11.10 requires two slight changes in the Emacs Lisp code to work properly. Here is the patch:
Regards,Code:--- emacs (revision 10195) +++ emacs (local) @@ -272,22 +272,27 @@ ;; Forward search. ;; Adapted from http://dud.inf.tu-dresden.de/~ben/evince_synctex.tar.gz (defun auctex-evince-forward-sync (pdffile texfile line) - (let ((dbus-name - (dbus-call-method :session - "org.gnome.evince.Daemon" ; service - "/org/gnome/evince/Daemon" ; path - "org.gnome.evince.Daemon" ; interface - "FindDocument" - (concat "file://" pdffile) - t ; Open a new window if the file is not opened. - ))) + (let* ((dbus-name + (dbus-call-method :session + "org.gnome.evince.Daemon" ; service + "/org/gnome/evince/Daemon" ; path + "org.gnome.evince.Daemon" ; interface + "FindDocument" + (concat "file://" pdffile) + t ; Open a new window if the file is not opened. + )) + (time (current-time)) + (high (car time)) + (low (cadr time)) + (timestamp (+ (* high (expt 2 16)) low))) (dbus-call-method :session dbus-name "/org/gnome/evince/Window/0" "org.gnome.evince.Window" "SyncView" texfile - (list :struct :int32 line :int32 1)))) + (list :struct :int32 line :int32 1) + timestamp))) (defun auctex-evince-view () (let ((pdf (file-truename (concat default-directory @@ -307,7 +312,7 @@ ;; Inverse search. ;; Adapted from: http://www.mail-archive.com/auctex@gnu.org/msg04175.html - (defun auctex-evince-inverse-sync (file linecol) + (defun auctex-evince-inverse-sync (file linecol timestamp) (let ((buf (get-buffer (file-name-nondirectory file))) (line (car linecol)) (col (cadr linecol)))
Florian
Thanks. That works on smaller files. But when I try it on larger files Emacs freezes after I do C-c C-v or Ctrl+click.
In *Messages*:
let*: D-Bus error: "Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken." [2 times]
I incorporated your patch into the above code; it's now at https://gist.github.com/2297447. I also fixed a problem with symlinks; SyncTeX follows them and uses that for the filenames in the synctex.gz file (see http://tex.stackexchange.com/questio...bout-filenames), but buffer-file-name in Emacs may not. So I added a "file-truename" to fix that. You'll need to use the TEXINPUTS trick from the tex.SE question, though.
I just want to share my experience with getting the whole thing running using kile with evince. I also would be very pleased if anyone could help me to get forward search working.
My distro: Ubuntu 11.10 "Oneiric"
My dbus version: 1.4.14-1ubuntu1
My kile version: 2.1.0
My evince version: 3.2.1
First I got the backward search running by using the file "evince_backward search", modified as shown below:
And calling it via "ViewPDF" in kile using the command: /usr/local/bin/evince '%target', where the Editor command in the script "evince" has to look like this:Code:import dbus, subprocess, time, re RUNNING, CLOSED = range(2) EV_DAEMON_PATH = "/org/gnome/evince/Daemon" EV_DAEMON_NAME = "org.gnome.evince.Daemon" EV_DAEMON_IFACE = "org.gnome.evince.Daemon" EVINCE_PATH = "/org/gnome/evince/Evince" EVINCE_IFACE = "org.gnome.evince.Application" EV_WINDOW_IFACE = "org.gnome.evince.Window" class EvinceWindowProxy: """A DBUS proxy for an Evince Window.""" daemon = None bus = None def __init__(self, uri, editor, spawn = False, logger = None): self._log = logger self.uri = uri self.editor = editor self.status = CLOSED self.source_handler = None self.dbus_name = '' self._handler = None try: if EvinceWindowProxy.bus is None: EvinceWindowProxy.bus = dbus.SessionBus() if EvinceWindowProxy.daemon is None: EvinceWindowProxy.daemon = EvinceWindowProxy.bus.get_object(EV_DAEMON_NAME, EV_DAEMON_PATH, follow_name_owner_changes=True) EvinceWindowProxy.bus.add_signal_receiver(self._on_doc_loaded, signal_name="DocumentLoaded", dbus_interface = EV_WINDOW_IFACE, sender_keyword='sender') self._get_dbus_name(False) except dbus.DBusException: if self._log: self._log.debug("Could not connect to the Evince Daemon") def _on_doc_loaded(self, uri, **keyargs): if uri == self.uri and self._handler is None: self.handle_find_document_reply(keyargs['sender']) def _get_dbus_name(self, spawn): EvinceWindowProxy.daemon.FindDocument(self.uri,spawn, reply_handler=self.handle_find_document_reply, error_handler=self.handle_find_document_error, dbus_interface = EV_DAEMON_IFACE) def handle_find_document_error(self, error): if self._log: self._log.debug("FindDocument DBus call has failed") def handle_find_document_reply(self, evince_name): if self._handler is not None: handler = self._handler else: handler = self.handle_get_window_list_reply if evince_name != '': self.dbus_name = evince_name self.status = RUNNING self.evince = EvinceWindowProxy.bus.get_object(self.dbus_name, EVINCE_PATH) self.evince.GetWindowList(dbus_interface = EVINCE_IFACE, reply_handler = handler, error_handler = self.handle_get_window_list_error) def handle_get_window_list_error (self, e): if self._log: self._log.debug("GetWindowList DBus call has failed") def handle_get_window_list_reply (self, window_list): if len(window_list) > 0: window_obj = EvinceWindowProxy.bus.get_object(self.dbus_name, window_list[0]) self.window = dbus.Interface(window_obj,EV_WINDOW_IFACE) self.window.connect_to_signal("SyncSource", self.on_sync_source) else: #That should never happen. if self._log: self._log.debug("GetWindowList returned empty list") def on_sync_source(self,input_file,source_link,time): fake_input = re.sub("file://",'',input_file) cmd = re.sub("%f",fake_input,self.editor) cmd = re.sub("%l",str(source_link[0]), cmd) print cmd subprocess.call(cmd, shell=True) if self.source_handler is not None: self.source_handler(input_file, source_link) ## This file offers backward search in any editor. ## evince_dbus pdf_file line_source input_file if __name__ == '__main__': import dbus.mainloop.glib, gobject, glib, sys, os def print_usage(): print """Usage: evince_backward_search pdf_file "editorcmd %f %l"' %f ... TeX-file to load %l ... line to jump to E.g.: evince_backward_search somepdf.pdf "gvim --servername somepdf --remote-silent '+%l<Enter>' %f" evince_backward_search somepdf.pdf "emacsclient -a emacs --no-wait +%l %f" evince_backward_search somepdf.pdf "scite %f '-goto:%l'" evince_backward_search somepdf.pdf "lyxclient -g %f %l" evince_backward_search somepdf.pdf "kate --use --line %l" evince_backward_search somepdf.pdf "kile --line %l" """ sys.exit(1) if len(sys.argv)!=3: print_usage() pdf_file = os.path.abspath(sys.argv[1]) if not os.path.isfile(pdf_file): print_usage() dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) a = EvinceWindowProxy('file://' + pdf_file, sys.argv[2] ,True) loop = gobject.MainLoop() loop.run()
That works very well.Code:EDITORCMD="kile --line %l %f"
Secondly I had to find a way to call the script "evince_forward_search" with the parameters described in the first post from kile.
I did that by writing that script below:
When invoked from kile using the commandCode:#!/bin/bash #this is 'forwardsearch.sh' #line LINE=$(echo $1 | cut -d : -f 3 | cut -d / -f 1) #echo $LINE #pdf PDFFILE=$(echo $1 | cut -d : -f 2 | cut -d \# -f 1) #texfile TEXFILE=$(echo $1 | cut -d : -f 3 | cut -d / -f 2-8 | sed -e 's/home/\/home/g') echo "evince_forward_search" $PDFFILE $LINE $TEXFILE evince_forward_search $PDFFILE $LINE $TEXFILE
that script calls the programm "evince_forward_search" with the described parameters.Code:forwardsearch.sh '%absolute_target'
Due to upcoming dbus errors I had to change the script "evince_backward_search" slightly as described before in this thread:
After that change, the script runs without any error but does not highlight anything in the pdf. The pdf just gets opened. Maybe someone can help me out.Code:-window.SyncView(tex_file, (line_number,1), dbus_interface="org.gnome.evince.Window") +window.SyncView(tex_file, (line_number,1), 0, dbus_interface="org.gnome.evince.Window")
Thx
Hi Guys.
I just wanted to tell the world out there how I got the synctex-script working with evince and geany, because your posts were very helpful for me and I hope my experiences can help other people.
My configuration is
evince 3.4.0
geany 0.21
Ubuntu 12.04 64Bit with Unity
Tex Live 2009
First, I downloaded the script and deflated the files to ~/bin.
Secondly, I modified the script files as suggested by jorges00 in Post #5 to get them working with the newer dbus interface (what ever that is).
Thirdly, I told geany to compile my document with the the synctex option by defining the following custom build command:
Then, to get backward search (Evince → Editor) running, I modified the second line of evince.sh as follows:Code:pdflatex %f && bibtex %e && pdflatex %f && pdflatex -synctex=1 %f
Please note that I added a "&" at the end. Without that I had the following problem: When I CTRL+clicked in the pdf, geany opened the correct file at the correct line. But when I clicked for the second time, nothing happened and geany was somehow frozen until I closed it. Then a new instance popped up and showed the line where I had clicked the second time.Code:EDITORCMD="geany -l %l %f &"
I do not know if that extra "&" is an appropriate solution, but it works for me.
I have not managed to get forward search (Editor → Evince) running with geany. You could tell geany to execute commands or run scripts. But as far as i understand the internet, there is no possibility of handing over the current line number from geany to a script. The reason is that a wildcard for the linenumber has not been implemented in geany yet.
However, I find backward search much more important than forward search, so I am really happy now with my setup. In Fact, the synctex-evince script and the advice from this forum to get it working enhanced the magnificence of my workflow by approximately 200%. Thank your for that.
Though, if anybody knows how to make forward search possible with geany, please let me know.
Last edited by Ottokraftstoff; June 29th, 2012 at 04:50 PM.
Hi all,
I'm trying to have backward search in Lyx using evince and the scripts of this forum.
My configuration is:
Ubuntu 12.04 64bit with Unity
evince 3.4.0
Lyx 2.02
Forward search (Lyx -> evince) works great from Lyx 2.0 on, so my only problem is backward search using evince.
I followed the steps suggested by Ottokraftstoff:
First, I downloaded the script and deflated the files to ~/bin.
Secondly, I modified the script files as suggested by jorges00 in Post #5 to get them working with the newer dbus interface (what ever that is).
Third, to get backward search (Evince → Lyx) running, I modified the second line of evince.sh as suggested in evince_backward_search, i.e.:
I tried with and without the & at the end, but nothing change.Code:EDITORCMD="lyxclient -g %f %l &"
Using Ctrl+click on evince nothing happen.
Please, can someone help me in some way?
Many thanks in advance!
Bookmarks