-
Notifications
You must be signed in to change notification settings - Fork 1
/
plugin.py
122 lines (102 loc) · 4.05 KB
/
plugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from LSP.plugin import AbstractPlugin, register_plugin, unregister_plugin
from LSP.plugin.core.protocol import Location
from LSP.plugin.core.typing import Any, Callable, Dict, Optional, List, Mapping
from LSP.plugin.locationpicker import LocationPicker
from shutil import which
import os
import sublime
import urllib.request
MARKSMAN_TAG = '2024-12-18'
MARKSMAN_RELEASES_BASE = 'https://github.com/artempyanykh/marksman/releases/download/{tag}/{platform}'
USER_AGENT = 'Sublime Text LSP'
def marksman_binary() -> Optional[str]:
platform_arch = '{}_{}'.format(sublime.platform(), sublime.arch())
if platform_arch in {'osx_x64', 'osx_arm64'}:
return 'marksman-macos'
if platform_arch == 'windows_x64':
return 'marksman.exe'
if platform_arch == 'linux_arm64':
return 'marksman-linux-arm64'
if platform_arch == 'linux_x64':
return 'marksman-linux-x64'
return None
class Marksman(AbstractPlugin):
@classmethod
def name(cls) -> str:
return 'marksman'
@classmethod
def basedir(cls) -> str:
return os.path.join(cls.storage_path(), __package__)
@classmethod
def marksman_path(cls) -> str:
return os.path.join(cls.basedir(), 'bin', marksman_binary() or 'unsupported_platform')
@classmethod
def additional_variables(cls) -> Optional[Dict[str, str]]:
return {
'marksman_bin': marksman_binary() or 'unsupported_platform'
}
@classmethod
def server_version(cls) -> str:
return MARKSMAN_TAG
@classmethod
def current_server_version(cls) -> Optional[str]:
try:
with open(os.path.join(cls.basedir(), 'VERSION'), 'r') as fp:
return fp.read()
except Exception:
return None
@classmethod
def needs_update_or_installation(cls) -> bool:
if marksman_binary() is None:
raise ValueError('Platform "{} ({})" is not supported'.format(sublime.platform(), sublime.arch()))
return which(cls.marksman_path()) is None or cls.current_server_version() != cls.server_version()
@classmethod
def install_or_update(cls) -> None:
marksman_path = cls.marksman_path()
os.makedirs(os.path.dirname(marksman_path), exist_ok=True)
bin_url = MARKSMAN_RELEASES_BASE.format(tag=cls.server_version(), platform=marksman_binary())
req = urllib.request.Request(
bin_url,
data=None,
headers={
'User-Agent': USER_AGENT
}
)
with urllib.request.urlopen(req) as fp:
with open(marksman_path, 'wb') as f:
f.write(fp.read())
os.chmod(marksman_path, 0o700)
with open(os.path.join(cls.basedir(), 'VERSION'), 'w') as fp:
fp.write(cls.server_version())
def on_pre_server_command(self, command: Mapping[str, Any], done_callback: Callable[[], None]) -> bool:
command_name = command['command']
if command_name == 'marksman.findReferences':
command_arguments = command['arguments']
if command_arguments and 'locations' in command_arguments[0]:
self._handle_show_references(command_arguments[0]['locations'])
done_callback()
return True
return False
def _handle_show_references(self, references: List[Location]) -> None:
session = self.weaksession()
if not session:
return
view = sublime.active_window().active_view()
if not view:
return
if len(references) == 1:
args = {
'location': references[0],
'session_name': session.config.name,
}
window = view.window()
if window:
window.run_command('lsp_open_location', args)
elif references:
LocationPicker(view, session, references, side_by_side=False)
else:
sublime.status_message('No references found')
def plugin_loaded() -> None:
register_plugin(Marksman)
def plugin_unloaded() -> None:
unregister_plugin(Marksman)