Skip to content

Commit 6dc254a

Browse files
committed
Refactor evince viewer plugin
1. use pathlib 2. re-arrange methods to avoid duplicate expensive calls 3. fix scripts as `__spec__.name` actually doesn't work, even in py3.13
1 parent 163f980 commit 6dc254a

File tree

4 files changed

+94
-92
lines changed

4 files changed

+94
-92
lines changed

plugins/viewer/evince/backward_search

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/python3
22
# -*- coding: utf-8 -*-
33

44
# Copyright (C) 2010 Jose Aliste <[email protected]>
@@ -147,7 +147,7 @@ class EvinceWindowProxy:
147147

148148
# This file offers backward search in any editor.
149149
# evince_dbus pdf_file line_source input_file
150-
if __spec__.name == '__main__':
150+
if __name__ == '__main__':
151151
import dbus.mainloop.glib
152152
import sys
153153
import os

plugins/viewer/evince/forward_search

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/python3
22
# -*- coding: utf-8 -*-
33

44
# Copyright (C) 2010 Jose Aliste <[email protected]>
@@ -26,7 +26,7 @@ import traceback
2626

2727
from urllib.parse import quote
2828

29-
if __spec__.name == '__main__':
29+
if __name__ == '__main__':
3030
def print_usage():
3131
print('Usage: forward_search pdf_file line_number tex_file')
3232
sys.exit(1)

plugins/viewer/evince/sync

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SUBLIME="$2"
1010
# f=%f; sublime-text "${f#file://}:%l"
1111
#
1212
# where sublime-text is the name of the sublime-text binary
13-
EDITORCMD="f=\"%f\"; $SUBLIME \"\${f#file://}:%l\""
13+
EDITORCMD="f=\"%f\"; \"$SUBLIME\" \"\${f#file://}:%l\""
1414

1515
PDFFILE="$3"
1616

@@ -26,7 +26,7 @@ if [ -f "$PDFFILE" ];then
2626
fi
2727
fi
2828

29-
/usr/bin/evince "$3"
29+
/usr/bin/evince "$PDFFILE"
3030

3131
if [ "$BACKWARD_SEARCH_PID" ];then
3232
echo "Killing $BACKWARD_SEARCH_PID"

plugins/viewer/evince_viewer.py

Lines changed: 88 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import os
1+
from __future__ import annotations
2+
import stat
23
import sublime
3-
import time
4+
5+
from pathlib import Path
6+
from typing import cast
47

58
from ...latextools.utils.external_command import check_call
69
from ...latextools.utils.external_command import check_output
@@ -15,114 +18,113 @@
1518

1619
class EvinceViewer(BaseViewer):
1720

18-
PYTHON = None
21+
_cached_python = None
1922

20-
def _get_evince_folder(self):
21-
script_dir = os.path.join(sublime.cache_path(), "LaTeXTools", "viewer", "evince")
22-
os.makedirs(script_dir, exist_ok=True)
23+
@property
24+
def _evince_folder(self) -> Path:
25+
script_dir = Path(sublime.cache_path()) / "LaTeXTools" / "viewer" / "evince"
26+
script_dir.mkdir(parents=True, exist_ok=True)
2327

2428
# extract scripts to cache dir and run them from there
2529
for script_name in ("backward_search", "forward_search", "sync"):
26-
script_file = os.path.join(script_dir, script_name)
27-
if os.path.exists(script_file):
28-
continue
29-
try:
30-
data = sublime.load_binary_resource(
31-
f"Packages/LaTeXTools/plugins/viewer/evince/{script_name}"
32-
)
33-
except FileNotFoundError:
34-
sublime.error_message(
35-
f"Cannot find required script '{script_name}'\n"
36-
"for 'evince' viewer in LaTeXTools package."
37-
)
38-
else:
39-
with open(script_file, "wb") as fobj:
40-
fobj.write(data)
30+
script_file = script_dir / script_name
31+
if not script_file.exists():
32+
try:
33+
data = (
34+
sublime.load_binary_resource(
35+
f"Packages/LaTeXTools/plugins/viewer/evince/{script_name}"
36+
)
37+
.replace(b"\r\n", b"\n")
38+
.replace(b"\r", b"\n")
39+
)
40+
except FileNotFoundError:
41+
sublime.error_message(
42+
f"Cannot find required script '{script_name}'\n"
43+
"for 'evince' viewer in LaTeXTools package."
44+
)
45+
continue
46+
47+
script_file.write_bytes(data)
48+
script_file.chmod(script_file.stat().st_mode | stat.S_IXUSR)
4149

4250
return script_dir
4351

44-
def _is_evince_running(self, pdf_file):
52+
def _is_evince_running(self, pdf_file: str) -> bool:
4553
try:
4654
return f"evince {pdf_file}" in check_output(["ps", "xv"], use_texpath=False)
4755
except Exception:
4856
return False
4957

50-
def _get_settings(self):
51-
"""
52-
returns evince-related settings as a tuple
53-
(python, sync_wait)
54-
"""
55-
linux_settings = get_setting("linux", {})
58+
@property
59+
def _python_binary(self) -> str:
60+
linux_settings = cast(dict, get_setting("linux", {}))
5661
python = linux_settings.get("python")
57-
if python is None or python == "":
58-
if self.PYTHON is not None:
59-
python = self.PYTHON
60-
else:
62+
if python and isinstance(python, str):
63+
return python
64+
65+
if self._cached_python is None:
66+
try:
67+
check_call(["python3", "-c", "import dbus"], use_texpath=False)
68+
self._cached_python = "python3"
69+
except Exception:
6170
try:
6271
check_call(["python", "-c", "import dbus"], use_texpath=False)
63-
python = "python"
72+
self._cached_python = "python"
6473
except Exception:
65-
try:
66-
check_call(["python3", "-c", "import dbus"], use_texpath=False)
67-
python = "python3"
68-
except Exception:
69-
sublime.error_message(
70-
"""Cannot find a valid Python interpreter.
71-
Please set the python setting in your LaTeXTools
72-
settings.""".strip()
73-
)
74-
# exit the viewer process
75-
raise Exception("Cannot find a valid interpreter")
76-
self.PYTHON = python
77-
return (python, linux_settings.get("sync_wait") or 1.0)
78-
79-
def _launch_evince(self, pdf_file):
80-
ev_path = self._get_evince_folder()
81-
py_binary, _ = self._get_settings()
82-
st_binary = get_sublime_exe()
83-
84-
external_command(
85-
["sh", os.path.join(ev_path, "sync"), py_binary, st_binary, pdf_file],
86-
cwd=ev_path,
87-
use_texpath=False,
88-
)
89-
90-
def forward_sync(self, pdf_file, tex_file, line, col, **kwargs):
91-
keep_focus = kwargs.pop("keep_focus", True)
92-
bring_evince_forward = get_setting("viewer_settings", {}).get("bring_evince_forward", False)
93-
94-
ev_path = self._get_evince_folder()
95-
py_binary, sync_wait = self._get_settings()
96-
97-
evince_running = self._is_evince_running(pdf_file)
98-
if not keep_focus or not evince_running or bring_evince_forward:
99-
self._launch_evince(pdf_file)
74+
sublime.error_message(
75+
"Cannot find a valid Python interpreter.\n"
76+
"Please set the python setting in your LaTeXTools settings."
77+
)
78+
# exit the viewer process
79+
raise RuntimeError("Cannot find a valid python interpreter!")
80+
81+
return self._cached_python
82+
83+
def forward_sync(self, pdf_file: str, tex_file: str, line: int, col: int, **kwargs) -> None:
84+
viewer_settings = cast(dict, get_setting("viewer_settings", {}))
85+
bring_evince_forward = viewer_settings.get("bring_evince_forward", False)
86+
keep_focus = kwargs.get("keep_focus", True)
87+
evince_folder = self._evince_folder
88+
python_binary = self._python_binary
89+
90+
def forward_search():
91+
external_command(
92+
[python_binary, "./forward_search", pdf_file, str(line), tex_file],
93+
cwd=evince_folder,
94+
use_texpath=False,
95+
)
96+
97+
if bring_evince_forward or not keep_focus or not self._is_evince_running(pdf_file):
98+
external_command(
99+
["/bin/sh", "./sync", python_binary, get_sublime_exe(), pdf_file],
100+
cwd=evince_folder,
101+
use_texpath=False,
102+
)
100103
if keep_focus:
101104
self.focus_st()
102105

103-
time.sleep(sync_wait)
106+
linux_settings = cast(dict, get_setting("linux", {}))
107+
sync_wait = linux_settings.get("sync_wait", 1.0)
108+
sublime.set_timeout(forward_search, int(1000 * sync_wait))
109+
110+
else:
111+
forward_search()
112+
113+
def view_file(self, pdf_file: str, **kwargs) -> None:
114+
keep_focus = kwargs.get("keep_focus", True)
115+
if keep_focus and self._is_evince_running(pdf_file):
116+
return
104117

105118
external_command(
106-
[
107-
py_binary,
108-
os.path.join(ev_path, "forward_search"),
109-
pdf_file,
110-
str(line),
111-
tex_file,
112-
],
119+
["/bin/sh", "./sync", self._python_binary, get_sublime_exe(), pdf_file],
120+
cwd=self._evince_folder,
113121
use_texpath=False,
114122
)
123+
if keep_focus:
124+
self.focus_st()
115125

116-
def view_file(self, pdf_file, **kwargs):
117-
keep_focus = kwargs.pop("keep_focus", True)
118-
119-
if not keep_focus or not self._is_evince_running(pdf_file):
120-
self._launch_evince(pdf_file)
121-
if keep_focus:
122-
self.focus_st()
123-
124-
def supports_platform(self, platform):
126+
def supports_platform(self, platform: str) -> bool:
125127
return platform == "linux"
126128

127-
def supports_keep_focus(self):
129+
def supports_keep_focus(self) -> bool:
128130
return True

0 commit comments

Comments
 (0)