Skip to content

Instantly share code, notes, and snippets.

@gerw
Created December 27, 2016 18:28
Show Gist options
  • Save gerw/05143c9a6d94ef6ee354fd708af5a1ce to your computer and use it in GitHub Desktop.
Save gerw/05143c9a6d94ef6ee354fd708af5a1ce to your computer and use it in GitHub Desktop.
Inverse search with evince and vim.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file was part of the Gedit Synctex plugin.
# Slightly modified by _vicious_ ...
#
# Copyright (C) 2010 Jose Aliste <jose.aliste@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public Licence as published by the Free Software
# Foundation; either version 2 of the Licence, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public Licence for more
# details.
#
# You should have received a copy of the GNU General Public Licence along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301, USA
import dbus, subprocess, time
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"
import urllib
def filename_to_uri( filename ):
uri = urllib.quote( filename )
return uri
MyGObjectMainLoop = None
class EvinceWindowProxy:
"""A DBUS proxy for an Evince Window."""
daemon = None
bus = None
def __init__(self, uri, spawn = False, logger = None):
# print "__init__"
self._log = logger
self.uri = uri
self.spawn = spawn
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)
self._get_dbus_name(False)
except dbus.DBusException:
if self._log:
self._log.debug("Could not connect to the Evince Daemon")
def _get_dbus_name(self, spawn):
# print "_get_dbus_name"
# print "URI: " + self.uri
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):
# print "handle_find_document_error"
if self._log:
self._log.debug("FindDocument DBus call has failed")
def handle_find_document_reply(self, evince_name):
# print "handle_find_document_reply"
if self._handler is not None:
handler = self._handler
else:
handler = self.handle_get_window_list_reply
# print "'" + evince_name + "'"
if evince_name != '':
print "Found evince instance."
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)
else: #ADDED
MyGObjectMainLoop.quit()
print "No evince found!" #ADDED
def handle_get_window_list_error (self, e):
# print "handle_get_window_list_error"
if self._log:
self._log.debug("GetWindowList DBus call has failed")
def handle_get_window_list_reply (self, window_list):
# print "handle_get_window_list_reply"
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("Closed", self.on_window_close)
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 set_source_handler (self, source_handler):
# print "set_source_handler"
self.source_handler = source_handler
def on_window_close(self):
# print "on_window_close"
self.window = None
self.status = CLOSED
MyGObjectMainLoop.quit()
def on_sync_source(self, input_file, source_link, timestamp):
# print "on_sync_source"
if self.source_handler is not None:
self.source_handler(input_file, source_link, timestamp)
def SyncView(self, input_file, data, timestamp):
# print "SyncView"
if self.status == CLOSED:
if self.spawn:
self._tmp_syncview = [input_file, data, timestamp];
self._handler = self._syncview_handler
self._get_dbus_name(True)
else:
self.window.SyncView(input_file, data, timestamp, dbus_interface = "org.gnome.evince.Window")
def _syncview_handler(self, window_list):
# print "_syncview_handler"
self.handle_get_window_list_reply(window_list)
if self.status == CLOSED:
return False
self.window.SyncView(self._tmp_syncview[0],
self._tmp_syncview[1],
self._tmp_syncview[2],
dbus_interface="org.gnome.evince.Window")
del self._tmp_syncview
self._handler = None
return True
## This file can be used as a script to support forward search and backward search in vim.
## It should be easy to adapt to other editors.
## evince_dbus pdf_file line_source input_file
if __name__ == '__main__':
import dbus.mainloop.glib, gobject, glib, sys, os
def print_usage():
print '''
The usage (to make evince sync ... will exit when sync done) is evince_vim_dbus EVINCE output_file line_number input_file from the directory of output_file.
'''
print '''
The usage (to make gvim sync in response to evince clicks, keeps running till killed) is evince_vim_dbus GVIM gvim_server_name output_file input_file from the directory of output_file.
'''
sys.exit(1)
if len(sys.argv)!=5:
print_usage()
if sys.argv[1] == 'EVINCE':
try:
line_number = int(sys.argv[3])
except ValueError:
print_usage()
output_file = sys.argv[2]
input_file = sys.argv[4]
if output_file[0] == '/':
path_output = os.path.dirname(output_file) + '/' + os.path.basename(output_file)
else:
path_output = os.getcwd() + '/' + os.path.basename(output_file)
if input_file[0] == '/':
path_input = os.path.dirname(input_file) + '/./' + os.path.basename(input_file)
else:
path_input = os.getcwd() + '/./' + os.path.basename(input_file)
if not os.path.isfile(path_output):
print_usage()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
uri = filename_to_uri(path_output)
print uri
print path_output
a = EvinceWindowProxy('file://' + uri, True )
def sync_view(ev_window, path_input, line_number):
ev_window.SyncView (path_input, (line_number, 1), 0)
exit(0)
glib.timeout_add(400, sync_view, a, path_input, line_number)
MyGObjectMainLoop = gobject.MainLoop()
MyGObjectMainLoop.run()
elif sys.argv[1] == 'GVIM':
gvim_server_name = sys.argv[2]
output_file = sys.argv[3]
input_file = sys.argv[4]
if output_file[0] == '/':
path_output = output_file
else:
path_output = os.getcwd() + '/' + output_file
if input_file[0] == '/':
path_input = input_file
else:
path_input = os.getcwd() + '/' + input_file
if not os.path.isfile(path_input):
print "File not found: " + path_input # ADDED
print_usage()
if not os.path.isfile(path_output): #ADDED
print "File not found: " + path_output # ADDED
print_usage() #ADDED
def source_view_handler(input_file, source_link, timestamp):
if input_file[0:7] == "file://": #ADDED
input_file = input_file[7:] #ADDED
print 'gvim --servername "' + gvim_server_name + '" --remote +' + str(source_link[0]) + ' ' + input_file
os.system('gvim --servername "' + gvim_server_name + '" --remote +' + str(source_link[0]) + ' ' + input_file)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
while True: #ADDED
uri = filename_to_uri(path_output)
print uri
print path_output
a = EvinceWindowProxy('file://' + uri, True )
a.set_source_handler(source_view_handler)
MyGObjectMainLoop = gobject.MainLoop()
MyGObjectMainLoop.run()
print "No evince found!?" #ADDED
time.sleep(1) #ADDED
else:
print_usage()
# ex:ts=4:et:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment