Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions LSP-ty.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
},
// @see https://docs.astral.sh/ty/reference/editor-settings/
"settings": {
// Path to a virtual environment directory. Can be absolute or relative to the workspace folder.
// When set, the Python interpreter from this venv is passed to the ty server.
"ty.venvDir": "",
Comment on lines +16 to +18
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really worth adding new setting which is just a proxy for a setting that can be set already? One can just set env.VIRTUAL_ENV directly.

Also the logic seems to be specific to one particular venv system and disregards other ones.

Probably better to just have a env section in default settings with commented out and documented VIRTUAL_ENV env.

// Whether to disable the language services that ty provides like code completion, hover, go to definition, etc.
// This is useful if you want to use ty exclusively for type checking in combination with another language server for features like code completion, hover, go to definition, etc.
"ty.disableLanguageServices": false,
Expand Down
45 changes: 44 additions & 1 deletion plugin/client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import sys
from pathlib import Path
from typing import Any

import sublime
from LSP.plugin import AbstractPlugin, ClientConfig, DottedDict
from LSP.plugin import AbstractPlugin, ClientConfig, DottedDict, WorkspaceFolder
from typing_extensions import override

from .constants import PACKAGE_NAME
Expand Down Expand Up @@ -51,6 +53,20 @@ def is_applicable(cls, view: sublime.View, config: ClientConfig) -> bool:
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 #
# ----- #
Expand All @@ -59,12 +75,39 @@ def is_applicable(cls, view: sublime.View, config: ClientConfig) -> bool:
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
Expand Down