-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathclient.py
More file actions
128 lines (105 loc) · 3.86 KB
/
client.py
File metadata and controls
128 lines (105 loc) · 3.86 KB
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
123
124
125
126
127
128
from __future__ import annotations
import sys
from pathlib import Path
from typing import Any
import sublime
from LSP.plugin import AbstractPlugin, ClientConfig, DottedDict, WorkspaceFolder
from typing_extensions import override
from .constants import PACKAGE_NAME
from .log import log_warning
from .template import load_string_template
from .version_manager import version_manager
class LspTyPlugin(AbstractPlugin):
@override
@classmethod
def name(cls) -> str:
return PACKAGE_NAME
@override
@classmethod
def configuration(cls) -> tuple[sublime.Settings, str]:
basename = f"{cls.name()}.sublime-settings"
filepath = f"Packages/{cls.name()}/{basename}"
return sublime.load_settings(basename), filepath
@override
@classmethod
def additional_variables(cls) -> dict[str, str] | None:
return {
"server_path": str(version_manager.server_path),
}
@override
@classmethod
def needs_update_or_installation(cls) -> bool:
return not version_manager.is_installed
@override
@classmethod
def install_or_update(cls) -> None:
version_manager.install_server()
@override
@classmethod
def is_applicable(cls, view: sublime.View, config: ClientConfig) -> bool:
return bool(
super().is_applicable(view, config)
# REPL views (https://github.com/sublimelsp/LSP-pyright/issues/343)
and not view.settings().get("repl")
)
@override
@classmethod
def on_pre_start(
cls,
window: sublime.Window,
initiating_view: sublime.View,
workspace_folders: list[WorkspaceFolder],
configuration: ClientConfig,
) -> str | None:
venv_dir = cls._find_venv_dir(workspace_folders, configuration)
if venv_dir:
configuration.env["VIRTUAL_ENV"] = str(venv_dir)
return None
# ----- #
# hooks #
# ----- #
@override
def on_settings_changed(self, settings: DottedDict) -> None:
super().on_settings_changed(settings)
# Remove our custom setting so it doesn't get sent to the ty server
settings.remove("ty.venvDir")
self.update_status_bar_text()
# -------------- #
# custom methods #
# -------------- #
@classmethod
def _find_venv_dir(
cls, workspace_folders: list[WorkspaceFolder], configuration: ClientConfig
) -> Path | None:
"""Find a virtual environment directory, checking the ty.venvDir setting first, then auto-detecting."""
if not workspace_folders:
return None
project_dir = Path(workspace_folders[0].path)
# 1. Check explicit setting
venv_dir_setting = configuration.settings.get("ty.venvDir") or ""
if venv_dir_setting:
path = Path(venv_dir_setting)
if not path.is_absolute():
path = project_dir / path
if cls._is_venv(path):
return path
return None
@staticmethod
def _is_venv(path: Path) -> bool:
"""Check if a directory looks like a Python virtual environment."""
return path.is_dir() and (path / "pyvenv.cfg").is_file()
def update_status_bar_text(self, extra_variables: dict[str, Any] | None = None) -> None:
if not (session := self.weaksession()):
return
variables: dict[str, Any] = {
"server_version": version_manager.server_version,
}
if extra_variables:
variables.update(extra_variables)
rendered_text = ""
if template_text := str(session.config.settings.get("statusText") or ""):
try:
rendered_text = load_string_template(template_text).render(variables)
except Exception as e:
log_warning(f'Invalid "statusText" template: {e}')
session.set_config_status_async(rendered_text)