From 2d04f03a4a464195fafb4ddc091bb8a836d429b6 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 30 Oct 2025 18:10:26 +0100 Subject: [PATCH 1/3] Handle "formattingOptions" workspace configuration request --- plugin.py | 30 ++++++++++++++++++++++++------ plugin_types.py | 16 ++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/plugin.py b/plugin.py index 432da70..153769a 100644 --- a/plugin.py +++ b/plugin.py @@ -9,8 +9,7 @@ from LSP.plugin import ClientConfig from LSP.plugin import parse_uri from LSP.plugin import WorkspaceFolder -from LSP.plugin.core.protocol import Error, Point, TextDocumentPositionParams, ExecuteCommandParams -from LSP.plugin.core.typing import cast, Callable, List, Optional, Tuple +from LSP.plugin.core.protocol import Error, Point from LSP.plugin.core.views import point_to_offset from LSP.plugin.locationpicker import LocationPicker from lsp_utils import notification_handler @@ -18,9 +17,14 @@ from lsp_utils import request_handler from pathlib import Path from sublime_lib import ResourcePath +from typing import TYPE_CHECKING, Any, cast, Callable +from typing_extensions import override import os import sublime +if TYPE_CHECKING: + from LSP.protocol import ConfigurationItem, ExecuteCommandParams, TextDocumentPositionParams + MOVE_TO_FILE_QUICK_PANEL_ITEMS: list[MoveToFileQuickPanelItem] = [ {'id': MoveToFileQuickPanelItemId.ExistingFile, 'title': 'Select existing file...'}, @@ -81,7 +85,7 @@ class LspTypescriptPlugin(NpmClientHandler): typescript_plugins: list[TypescriptPluginContribution] | None = None @classmethod - def minimum_node_version(cls) -> Tuple[int, int, int]: + def minimum_node_version(cls) -> tuple[int, int, int]: return (14, 16, 0) @classmethod @@ -95,10 +99,10 @@ def selector(cls, view: sublime.View, config: ClientConfig) -> str: @classmethod def on_pre_start(cls, window: sublime.Window, initiating_view: sublime.View, - workspace_folders: List[WorkspaceFolder], configuration: ClientConfig) -> Optional[str]: + workspace_folders: list[WorkspaceFolder], configuration: ClientConfig) -> str | None: plugins = configuration.init_options.get('plugins') or [] for ts_plugin in cls._get_typescript_plugins(): - plugin = { + plugin: TypescriptPluginContribution = { 'name': ts_plugin['name'], 'location': ts_plugin['location'], } @@ -140,10 +144,24 @@ def on_typescript_version_async(self, params: TypescriptVersionNotificationParam if status_text: session.set_config_status_async(status_text) + @override + def on_workspace_configuration(self, params: ConfigurationItem, configuration: Any) -> Any: + if params.get('section') == 'formattingOptions' and (scope_uri := params.get('scopeUri')) \ + and (session := self.weaksession()) \ + and (buf := session.get_session_buffer_for_uri_async(scope_uri)) \ + and (session_view := next(iter(buf.session_views), None)): + view_settings = session_view.view.settings() + return { + **(configuration if isinstance(configuration, dict) else {}), + 'tabSize': view_settings.get('tab_size'), + 'insertSpaces': view_settings.get('translate_tabs_to_spaces'), + } + return configuration + def on_pre_server_command(self, command: ExecuteCommandParams, done_callback: Callable[[], None]) -> bool: command_name = command['command'] if command_name == 'editor.action.showReferences': - references_command = cast(ShowReferencesCommand, command) + references_command = cast('ShowReferencesCommand', command) self._handle_show_references(references_command) done_callback() return True diff --git a/plugin_types.py b/plugin_types.py index 5fa5e0e..37eaaa9 100644 --- a/plugin_types.py +++ b/plugin_types.py @@ -1,16 +1,20 @@ from __future__ import annotations -from LSP.plugin.core.protocol import Location, Position -from LSP.plugin.core.typing import List, Literal, NotRequired, StrEnum, Tuple, TypedDict, Union +from LSP.plugin.core.typing import StrEnum +from typing import TYPE_CHECKING, Literal, TypedDict +from typing_extensions import NotRequired + +if TYPE_CHECKING: + from LSP.protocol import Location, Position class TypescriptVersionNotificationParams(TypedDict): version: str - source: Union[Literal['bundled'], Literal['user-setting'], Literal['workspace']] + source: Literal['bundled', 'user-setting', 'workspace'] class TypescriptPluginContribution(TypedDict): name: str - languages: NotRequired[List[str]] + languages: NotRequired[list[str]] location: str selector: NotRequired[str] @@ -27,7 +31,7 @@ class ApplyRefactoringArgument(TypedDict): class ApplyRefactoringCommand(TypedDict): command: str - arguments: Tuple[ApplyRefactoringArgument] + arguments: tuple[ApplyRefactoringArgument] class MoveToFileQuickPanelItemId(StrEnum): @@ -42,4 +46,4 @@ class MoveToFileQuickPanelItem(TypedDict): class ShowReferencesCommand(TypedDict): command: str - arguments: Tuple[str, Position, List[Location]] + arguments: tuple[str, Position, list[Location]] From d440492b9a6e81717c5d46bc91beb74bc27ef71b Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 30 Oct 2025 19:05:52 +0100 Subject: [PATCH 2/3] update minimum node version --- plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.py b/plugin.py index 153769a..cd43ef3 100644 --- a/plugin.py +++ b/plugin.py @@ -86,7 +86,7 @@ class LspTypescriptPlugin(NpmClientHandler): @classmethod def minimum_node_version(cls) -> tuple[int, int, int]: - return (14, 16, 0) + return (20, 0, 0) @classmethod def selector(cls, view: sublime.View, config: ClientConfig) -> str: From 82ecebee46748ca0ad7cff487dea9518881a3f97 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Fri, 31 Oct 2025 10:43:55 +0100 Subject: [PATCH 3/3] update readme --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 83a3f3b..ac7ecdd 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Open the configuration file using the Command Palette `Preferences: LSP-typescri To sort or remove unused imports you can trigger the `LSP-typescript: Organize Imports` command from the Command Palette or create a key binding. For example: ```json -{ "keys": ["ctrl+k"], "command": "lsp_execute", +{ + "keys": ["ctrl+k"], + "command": "lsp_execute", "args": { "session_name": "LSP-typescript", "command_name": "_typescript.organizeImports", @@ -27,6 +29,28 @@ To sort or remove unused imports you can trigger the `LSP-typescript: Organize I }, ``` +Optionally you can provide the "mode" option that specifies what type of organization should be performed: + +```jsonc +{ + "keys": ["ctrl+k"], + "command": "lsp_execute", + "args": { + "session_name": "LSP-typescript", + "command_name": "_typescript.organizeImports", + "command_args": [ + "${file}", + { + // 'All' - organizes imports including destructive actions (removing unused imports) + // 'SortAndCombine' - Doesn't perform destructive actions. + // 'RemoveUnused' - Only removes unused imports. + "mode": "RemoveUnused" + } + ] + } +}, +``` + ## Code Actions on Save The server supports the following code actions that can be specified in the global `lsp_code_actions_on_save` setting and run on saving files: