Skip to content
Draft
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
2 changes: 1 addition & 1 deletion docs/src/client_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Below is an example of the `LSP.sublime-settings` file with configurations for t
| settings | per-project settings (equivalent to VS Code's Workspace Settings) |
| initializationOptions | options to send to the server at startup (rarely used) |
| selector | This is _the_ connection between your files and language servers. It's a selector that is matched against the current view's base scope. If the selector matches with the base scope of the the file, the associated language server is started. For more information, see https://www.sublimetext.com/docs/3/selectors.html |
| priority_selector | Used to prioritize a certain language server when choosing which one to query on views with multiple servers active. Certain LSP actions have to pick which server to query and this setting can be used to decide which one to pick based on the current scopes at the cursor location. For example when having both HTML and PHP servers running on a PHP file, this can be used to give priority to the HTML one in HTML blocks and to PHP one otherwise. That would be done by setting "priority_selector" to `text.html` for HTML server and `source.php` to PHP server. Note: when the "priority_selector" is missing, it will be the same as the "document_selector".
| priority_selector | Used to prioritize a certain language server when choosing which one to query on views with multiple servers active. Certain LSP actions have to pick which server to query and this setting can be used to decide which one to pick based on the current scopes at the cursor location. For example when having both HTML and PHP servers running on a PHP file, this can be used to give priority to the HTML one in HTML blocks and to PHP one otherwise. That would be done by setting "priority_selector" to `text.html` for HTML server and `source.php` to PHP server. Note: when the "priority_selector" is missing, it will be the same as the "document_selector". This setting also accepts an object where the key is the name of the provider (for example `renameProvider`) and the value is the selector to use for this provider. In that case a `*` key can also be used which will act as a fallback for providers that are not explicitly specified.
| diagnostics_mode | Set to `"workspace"` (default is `"open_files"`) to ignore diagnostics for files that are not within the project (window) folders. If project has no folders then this option has no effect and diagnostics are shown for all files. If the server supports _pull diagnostics_ (`diagnosticProvider`), this setting also controls whether diagnostics are requested only for open files (`"open_files"`), or for all files in the project folders (`"workspace"`). |
| tcp_port | see instructions below |
| experimental_capabilities | Turn on experimental capabilities of a language server. This is a dictionary and differs per language server |
Expand Down
7 changes: 5 additions & 2 deletions plugin/core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@
windows = WindowRegistry()


def best_session(view: sublime.View, sessions: Iterable[Session], point: int | None = None) -> Session | None:
def best_session(
view: sublime.View, sessions: Iterable[Session], capability_path: str | None = None, point: int | None = None
) -> Session | None:
if point is None:
try:
point = view.sel()[0].b
except IndexError:
return None
try:
return max(sessions, key=lambda s: view.score_selector(point, s.config.priority_selector))
return max(sessions,
key=lambda s: view.score_selector(point, s.config.priority_selector_for_capability(capability_path)))
except ValueError:
return None

Expand Down
17 changes: 14 additions & 3 deletions plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ class ClientConfig:
def __init__(self,
name: str,
selector: str,
priority_selector: str | None = None,
priority_selector: str | dict[str, str] | None = None,
schemes: list[str] | None = None,
command: list[str] | None = None,
binary_args: list[str] | None = None, # DEPRECATED
Expand Down Expand Up @@ -910,6 +910,17 @@ def filter_out_disabled_capabilities(self, capability_path: str, options: dict[s
result[k] = v
return result

def priority_selector_for_capability(self, capability_path: str | None = None) -> str:
if isinstance(self.priority_selector, str):
return self.priority_selector
if capability_path:
capability = capability_path.split('.')[0]
if capability in self.priority_selector:
return self.priority_selector[capability]
if '*' in self.priority_selector:
return self.priority_selector['*']
return self.selector

def __repr__(self) -> str:
items: list[str] = []
for k, v in self.__dict__.items():
Expand Down Expand Up @@ -973,10 +984,10 @@ def _read_selector(config: sublime.Settings | dict[str, Any]) -> str:
return ""


def _read_priority_selector(config: sublime.Settings | dict[str, Any]) -> str:
def _read_priority_selector(config: sublime.Settings | dict[str, Any]) -> str | dict[str, str]:
# Best case scenario
selector = config.get("priority_selector")
if isinstance(selector, str):
if isinstance(selector, (str, dict)):
return selector
# Otherwise, look for "languages": [...]
languages = config.get("languages")
Expand Down
2 changes: 1 addition & 1 deletion plugin/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ def _on_initial_folding_ranges(self, kinds: list[str], response: list[FoldingRan
# --- Public utility methods ---------------------------------------------------------------------------------------

def session_async(self, capability: str, point: int | None = None) -> Session | None:
return best_session(self.view, self.sessions_async(capability), point)
return best_session(self.view, self.sessions_async(capability), capability, point)

def sessions_async(self, capability: str | None = None) -> list[Session]:
return [
Expand Down
5 changes: 4 additions & 1 deletion plugin/tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,10 @@ def line(s: str) -> None:
line(f' - command\n{self.json_dump(config.command)}')
line(' - shell command\n{}'.format(self.code_block(list2cmdline(resolved_command), 'sh')))
line(f' - selector\n{self.code_block(config.selector)}')
line(f' - priority_selector\n{self.code_block(config.priority_selector)}')
priority_selector = self.code_block(config.priority_selector) \
if isinstance(config.priority_selector, str) \
else self.json_dump(config.priority_selector)
line(f' - priority_selector\n{priority_selector}')
line(' - init_options')
line(self.json_dump(config.init_options.get()))
line(' - settings')
Expand Down
103 changes: 103 additions & 0 deletions sublime-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,109 @@
"default": "open_files"
},
"ClientPrioritySelector": {
"oneOf": [
{
"type": "object",
"properties": {
"*": {
"type": "string"
},
"callHierarchyProvider": {
"type": "string"
},
"codeActionProvider": {
"type": "string"
},
"codeLensProvider": {
"type": "string"
},
"colorProvider": {
"type": "string"
},
"completionProvider": {
"type": "string"
},
"declarationProvider": {
"type": "string"
},
"definitionProvider": {
"type": "string"
},
"diagnosticProvider": {
"type": "string"
},
"documentFormattingProvider": {
"type": "string"
},
"documentHighlightProvider": {
"type": "string"
},
"documentLinkProvider": {
"type": "string"
},
"documentOnTypeFormattingProvider": {
"type": "string"
},
"documentRangeFormattingProvider": {
"type": "string"
},
"documentSymbolProvider": {
"type": "string"
},
"executeCommandProvider": {
"type": "string"
},
"foldingRangeProvider": {
"type": "string"
},
"hoverProvider": {
"type": "string"
},
"implementationProvider": {
"type": "string"
},
"inlayHintProvider": {
"type": "string"
},
"inlineValueProvider": {
"type": "string"
},
"linkedEditingRangeProvider": {
"type": "string"
},
"monikerProvider": {
"type": "string"
},
"referencesProvider": {
"type": "string"
},
"renameProvider": {
"type": "string"
},
"selectionRangeProvider": {
"type": "string"
},
"semanticTokensProvider": {
"type": "string"
},
"signatureHelpProvider": {
"type": "string"
},
"typeDefinitionProvider": {
"type": "string"
},
"typeHierarchyProvider": {
"type": "string"
},
"workspaceSymbolProvider": {
"type": "string"
},
}
},
{
"type": "string",
}
],
"markdownDescription": "While the `\"selector\"` is used to determine which views belong to which language server configuration, the `\"priority_selector\"` is used to determine which language server wins at the caret position in case there are multiple language servers attached to a view. For instance, there can only be one signature help popup visible at any given time. This selector is use to decide which one to use for such capabilities. This setting is optional and you won't need to set it if you're planning on using a single language server for a particular type of view."
},
// The ClientConfig class
Expand Down