mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 10:00:33 +00:00
Scripts for connecting LyX with evince for backward/forward search
The scripts have been initially developed by Benjamin Kellermann (2011) as a derivation of gedit-synctex-plugin by José Aliste (https://github.com/jaliste/gedit-synctex-plugin, 2010) and published on https://ubuntuforums.org/showthread.php?t=1716268. The work here is based on a further derivation of this work for Sublime Text LaTeX Tools (https://github.com/SublimeText/LaTeXTools/tree/master/evince). Adaptations for the use with LyX as well as the initial translation of the evince_sync bash script to python have been done by myself. The python code (particularly evince_sync_lyx) needs audit!
This commit is contained in:
parent
5078448111
commit
e79782c4cc
49
3rdparty/evince_sync/README
vendored
Normal file
49
3rdparty/evince_sync/README
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
===============================================
|
||||
FORWARD AND BACKWARD SEARCH WITH LYX AND EVINCE
|
||||
===============================================
|
||||
|
||||
For the forward and backwards (reverse) search feature in general, please refer to
|
||||
Help > Additional Features, sec. 5.6 and 5.7 in LyX.
|
||||
|
||||
|
||||
SETUP
|
||||
=====
|
||||
|
||||
* Install the files evince_sync_lyx, evince_forward_search and evince_backward_search
|
||||
in your binary directory (e.g., ~/bin).
|
||||
|
||||
* Assure all three files are executable.
|
||||
|
||||
* In LyX, go to Tools > Preferences ... > File Handling > File Formats > Format, select
|
||||
the appropriate output format [e.g., PDF (pdflatex)], set "Viewer" to "Custom" and
|
||||
enter evince_sync_lyx as custom viewer (in the field right to the combo box).
|
||||
Hit "Apply" and "Save".
|
||||
|
||||
* Go to Tools > Preferences ... > Output > General and enter the following PDF command
|
||||
to Forward Search: evince_forward_search "$$o" $$n "$$f"
|
||||
Again, hit "Apply" and "Save".
|
||||
|
||||
Forward and Backward search should work now (backward search from within evince is triggered
|
||||
by <Shift> + <Left Click>).
|
||||
|
||||
|
||||
HISTORY
|
||||
=======
|
||||
|
||||
The scripts have been initially developed by Benjamin Kellermann (2011) as a derivation
|
||||
of gedit-synctex-plugin by José Aliste (https://github.com/jaliste/gedit-synctex-plugin,
|
||||
2010) and published on https://ubuntuforums.org/showthread.php?t=1716268.
|
||||
|
||||
The work is based on a further derivation of this work for Sublime Text LaTeX Tools
|
||||
(https://github.com/SublimeText/LaTeXTools/tree/master/evince).
|
||||
|
||||
Adaptations for the use with LyX have been done by Jürgen Spitzmüller <spitz@lyx.org>
|
||||
in 2017.
|
||||
|
||||
|
||||
CONTACT
|
||||
=======
|
||||
|
||||
Please send bug reports and suggestions (related to LyX-evince synchronization) to
|
||||
lyx-devel@lists.lyx.org.
|
||||
Usage questions should be addressed at lyx-users@lists.lyx.org.
|
212
3rdparty/evince_sync/evince_backward_search
vendored
Executable file
212
3rdparty/evince_sync/evince_backward_search
vendored
Executable file
@ -0,0 +1,212 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010 Jose Aliste <jose.aliste@gmail.com>
|
||||
# 2011 Benjamin Kellermann <Benjamin.Kellermann@tu-dresden.de>
|
||||
#
|
||||
# Modified for the use with LyX by Juergen Spitzmueller <spitz@lyx.org> 2017.
|
||||
#
|
||||
# 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
|
||||
|
||||
# Incorporates fixes from http://ubuntuforums.org/showthread.php?t=1716268
|
||||
from __future__ import print_function
|
||||
|
||||
import dbus
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
if sys.version_info < (3,):
|
||||
from urllib import unquote as urllib_unquote
|
||||
from urllib import quote
|
||||
|
||||
def unquote(s):
|
||||
# This is to deal with source files with non-ascii names
|
||||
# We get url-quoted UTF-8 from dbus; convert to url-quoted ascii
|
||||
# and then unquote. If you don't first convert ot ascii, it fails.
|
||||
# It's a bit magical, but it seems to work
|
||||
return urllib_unquote(s.encode('ascii'))
|
||||
else:
|
||||
from urllib.parse import unquote
|
||||
from urllib.parse import quote
|
||||
|
||||
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.uri_unquoted = unquote(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:
|
||||
traceback.print_exc()
|
||||
if self._log:
|
||||
self._log.debug("Could not connect to the Evince Daemon")
|
||||
|
||||
def _on_doc_loaded(self, uri, **keyargs):
|
||||
if (
|
||||
unquote(uri) == self.uri_unquoted 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:
|
||||
# This should never happen.
|
||||
if self._log:
|
||||
self._log.debug("GetWindowList returned empty list")
|
||||
|
||||
def on_sync_source(self, input_file, source_link, _):
|
||||
input_file = unquote(input_file)
|
||||
# Remove the "file://" prefix
|
||||
input_file = input_file[7:]
|
||||
#print("File: " + input_file + ":" + str(source_link[0]))
|
||||
cmd = self.editor.replace('%f', input_file)
|
||||
cmd = cmd.replace('%l', str(source_link[0]))
|
||||
#print(cmd)
|
||||
subprocess.call(cmd, shell=True)
|
||||
if self.source_handler is not None:
|
||||
self.source_handler(input_file, source_link, time)
|
||||
|
||||
|
||||
# This file offers backward search in any editor.
|
||||
# evince_dbus pdf_file line_source input_file
|
||||
if __name__ == '__main__':
|
||||
import dbus.mainloop.glib
|
||||
import sys
|
||||
import 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)
|
||||
EvinceWindowProxy(
|
||||
# The PDF file name MUST be URI-encoded
|
||||
# RFC 1738: unreserved = alpha | digit | safe | extra
|
||||
# safe = "$" | "-" | "_" | "." | "+"
|
||||
# extra = "!" | "*" | "'" | "(" | ")" | ","
|
||||
'file://' + quote(pdf_file, "/$+!*'(),@=~"),
|
||||
sys.argv[2],
|
||||
True
|
||||
)
|
||||
|
||||
try:
|
||||
import gobject
|
||||
loop = gobject.MainLoop()
|
||||
except ImportError:
|
||||
from gi.repository import GLib
|
||||
loop = GLib.MainLoop()
|
||||
loop.run()
|
||||
# ex:ts=4:et:
|
72
3rdparty/evince_sync/evince_forward_search
vendored
Executable file
72
3rdparty/evince_sync/evince_forward_search
vendored
Executable file
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010 Jose Aliste <jose.aliste@gmail.com>
|
||||
# 2011 Benjamin Kellermann <Benjamin.Kellermann@tu-dresden.de>
|
||||
#
|
||||
# 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
|
||||
|
||||
# This file offers forward search for evince.
|
||||
from __future__ import print_function
|
||||
|
||||
import dbus
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
if sys.version_info < (3,):
|
||||
from urllib import quote
|
||||
else:
|
||||
from urllib.parse import quote
|
||||
|
||||
if __name__ == '__main__':
|
||||
def print_usage():
|
||||
print('Usage: evince_forward_search pdf_file line_number tex_file')
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print_usage()
|
||||
try:
|
||||
line_number = int(sys.argv[2])
|
||||
except ValueError:
|
||||
print_usage()
|
||||
|
||||
pdf_file = os.path.abspath(sys.argv[1])
|
||||
line = int(sys.argv[2])
|
||||
tex_file = os.path.abspath(sys.argv[3])
|
||||
|
||||
try:
|
||||
bus = dbus.SessionBus()
|
||||
daemon = bus.get_object(
|
||||
'org.gnome.evince.Daemon', '/org/gnome/evince/Daemon'
|
||||
)
|
||||
dbus_name = daemon.FindDocument(
|
||||
# The PDF file name MUST be URI-encoded
|
||||
# RFC 1738: unreserved = alpha | digit | safe | extra
|
||||
# safe = "$" | "-" | "_" | "." | "+"
|
||||
# extra = "!" | "*" | "'" | "(" | ")" | ","
|
||||
'file://' + quote(pdf_file, "/$+!*'(),@=~"),
|
||||
True,
|
||||
dbus_interface="org.gnome.evince.Daemon"
|
||||
)
|
||||
window = bus.get_object(dbus_name, '/org/gnome/evince/Window/0')
|
||||
window.SyncView(
|
||||
tex_file,
|
||||
(line_number, 1),
|
||||
0, # GDK_CURRENT_TIME constant
|
||||
dbus_interface="org.gnome.evince.Window"
|
||||
)
|
||||
except dbus.DBusException:
|
||||
traceback.print_exc()
|
54
3rdparty/evince_sync/evince_sync_lyx
vendored
Executable file
54
3rdparty/evince_sync/evince_sync_lyx
vendored
Executable file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2010 Jose Aliste <jose.aliste@gmail.com>
|
||||
# 2011 Benjamin Kellermann <Benjamin.Kellermann@tu-dresden.de>
|
||||
#
|
||||
# Translated from Bash to Python by Juergen Spitzmueller <spitz@lyx.org> 2017.
|
||||
#
|
||||
# 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 sys, os.path
|
||||
from subprocess import Popen, call
|
||||
|
||||
editor_cmd = "lyxclient -g %f %l"
|
||||
|
||||
def print_usage():
|
||||
print("Usage: evince_sync_lyx pdf_file")
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print_usage()
|
||||
|
||||
pdf_file = os.path.abspath(sys.argv[1])
|
||||
|
||||
if not os.path.isfile(pdf_file):
|
||||
print_usage()
|
||||
|
||||
synctex_file, ext = os.path.splitext(pdf_file)
|
||||
|
||||
synctex_file += ".synctex.gz"
|
||||
|
||||
SyncTeX = False
|
||||
|
||||
if os.path.isfile(synctex_file):
|
||||
bsproc = Popen(["evince_backward_search", pdf_file, editor_cmd])
|
||||
SyncTeX = True
|
||||
|
||||
vproc = Popen(['evince', pdf_file])
|
||||
vproc.wait()
|
||||
|
||||
if SyncTeX:
|
||||
bsproc.terminate()
|
||||
|
Loading…
Reference in New Issue
Block a user