Skip to content

Commit 20f8fc8

Browse files
Merge branch 'main' into feat/py38
2 parents 1bb3bc6 + d4538fa commit 20f8fc8

15 files changed

+276
-37
lines changed

boot.py

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from .plugin.documents import DocumentSyncListener
4343
from .plugin.documents import TextChangeListener
4444
from .plugin.edit import LspApplyDocumentEditCommand
45+
from .plugin.edit import LspApplyWorkspaceEditCommand
4546
from .plugin.execute_command import LspExecuteCommand
4647
from .plugin.folding_range import LspFoldAllCommand
4748
from .plugin.folding_range import LspFoldCommand
@@ -68,6 +69,7 @@
6869
from .plugin.panels import LspUpdateLogPanelCommand
6970
from .plugin.panels import LspUpdatePanelCommand
7071
from .plugin.references import LspSymbolReferencesCommand
72+
from .plugin.rename import LspHideRenameButtonsCommand
7173
from .plugin.rename import LspSymbolRenameCommand
7274
from .plugin.save_command import LspSaveAllCommand
7375
from .plugin.save_command import LspSaveCommand

docs/src/language_servers.md

+18
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,24 @@ Follow installation instructions on [LSP-tailwindcss](https://github.com/sublime
717717

718718
Follow installation instructions on [LSP-terraform](https://github.com/sublimelsp/LSP-terraform).
719719

720+
## Toit
721+
722+
1. Install the [Toit](https://packagecontrol.io/packages/Toit) package from Package Control for syntax highlighting.
723+
2. Install the [Jaguar Language Server](https://github.com/toitlang/jaguar).
724+
3. Open `Preferences > Package Settings > LSP > Settings` and add the `"jag"` client configuration to the `"clients"`:
725+
726+
```jsonc
727+
{
728+
"clients": {
729+
"jag": {
730+
"enabled": true,
731+
"command": ["jag" "lsp"],
732+
"selector": "source.toit"
733+
}
734+
}
735+
}
736+
```
737+
720738
## TypeScript
721739

722740
See [Javascript/TypeScript](#javascripttypescript).

plugin/core/panels.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .types import PANEL_FILE_REGEX
22
from .types import PANEL_LINE_REGEX
3-
from .typing import Optional
3+
from .typing import Iterable, Optional
44
import sublime
55

66

@@ -38,6 +38,7 @@ class PanelName:
3838
class PanelManager:
3939
def __init__(self, window: sublime.Window) -> None:
4040
self._window = window
41+
self._rename_panel_buttons = None # type: Optional[sublime.PhantomSet]
4142

4243
def destroy_output_panels(self) -> None:
4344
for field in filter(lambda a: not a.startswith('__'), PanelName.__dict__.keys()):
@@ -46,6 +47,7 @@ def destroy_output_panels(self) -> None:
4647
if panel and panel.is_valid():
4748
panel.settings().set("syntax", "Packages/Text/Plain text.tmLanguage")
4849
self._window.destroy_output_panel(panel_name)
50+
self._rename_panel_buttons = None
4951

5052
def toggle_output_panel(self, panel_type: str) -> None:
5153
panel_name = "output.{}".format(panel_type)
@@ -91,6 +93,8 @@ def _create_panel(self, name: str, result_file_regex: str, result_line_regex: st
9193
panel = self.create_output_panel(name)
9294
if not panel:
9395
return None
96+
if name == PanelName.Rename:
97+
self._rename_panel_buttons = sublime.PhantomSet(panel, "lsp_rename_buttons")
9498
settings = panel.settings()
9599
if result_file_regex:
96100
settings.set("result_file_regex", result_file_regex)
@@ -121,3 +125,7 @@ def show_diagnostics_panel_async(self) -> None:
121125
def hide_diagnostics_panel_async(self) -> None:
122126
if self.is_panel_open(PanelName.Diagnostics):
123127
self.toggle_output_panel(PanelName.Diagnostics)
128+
129+
def update_rename_panel_buttons(self, phantoms: Iterable[sublime.Phantom]) -> None:
130+
if self._rename_panel_buttons:
131+
self._rename_panel_buttons.update(phantoms)

plugin/core/sessions.py

+28-5
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,15 @@ def on_post_start(cls, window: sublime.Window, initiating_view: sublime.View,
937937
"""
938938
pass
939939

940+
@classmethod
941+
def should_ignore(cls, view: sublime.View) -> bool:
942+
"""
943+
Exclude a view from being handled by the language server, even if it matches the URI scheme(s) and selector from
944+
the configuration. This can be used to, for example, ignore certain file patterns which are listed in a
945+
configuration file (e.g. .gitignore).
946+
"""
947+
return False
948+
940949
@classmethod
941950
def markdown_language_id_to_st_syntax_map(cls) -> Optional[MarkdownLangMap]:
942951
"""
@@ -1383,6 +1392,9 @@ def compare_by_string(sb: Optional[SessionBufferProtocol]) -> bool:
13831392
def can_handle(self, view: sublime.View, scheme: str, capability: Optional[str], inside_workspace: bool) -> bool:
13841393
if not self.state == ClientStates.READY:
13851394
return False
1395+
if self._plugin and self._plugin.should_ignore(view):
1396+
debug(view, "ignored by plugin", self._plugin.__class__.__name__)
1397+
return False
13861398
if scheme == "file":
13871399
file_name = view.file_name()
13881400
if not file_name:
@@ -1759,8 +1771,7 @@ def _apply_code_action_async(
17591771
arguments = command.get("arguments")
17601772
if arguments is not None:
17611773
execute_command['arguments'] = arguments
1762-
return promise.then(
1763-
lambda _: self.execute_command(execute_command, progress=False, view=view))
1774+
return promise.then(lambda _: self.execute_command(execute_command, progress=False, view=view))
17641775
return promise
17651776

17661777
def apply_workspace_edit_async(self, edit: WorkspaceEdit) -> Promise[None]:
@@ -1771,12 +1782,16 @@ def apply_workspace_edit_async(self, edit: WorkspaceEdit) -> Promise[None]:
17711782
return self.apply_parsed_workspace_edits(parse_workspace_edit(edit))
17721783

17731784
def apply_parsed_workspace_edits(self, changes: WorkspaceChanges) -> Promise[None]:
1785+
active_sheet = self.window.active_sheet()
1786+
selected_sheets = self.window.selected_sheets()
17741787
promises = [] # type: List[Promise[None]]
17751788
for uri, (edits, view_version) in changes.items():
17761789
promises.append(
17771790
self.open_uri_async(uri).then(functools.partial(self._apply_text_edits, edits, view_version, uri))
17781791
)
1779-
return Promise.all(promises).then(lambda _: None)
1792+
return Promise.all(promises) \
1793+
.then(lambda _: self._set_selected_sheets(selected_sheets)) \
1794+
.then(lambda _: self._set_focused_sheet(active_sheet))
17801795

17811796
def _apply_text_edits(
17821797
self, edits: List[TextEdit], view_version: Optional[int], uri: str, view: Optional[sublime.View]
@@ -1786,6 +1801,14 @@ def _apply_text_edits(
17861801
return
17871802
apply_text_edits(view, edits, required_view_version=view_version)
17881803

1804+
def _set_selected_sheets(self, sheets: List[sublime.Sheet]) -> None:
1805+
if len(sheets) > 1 and len(self.window.selected_sheets()) != len(sheets):
1806+
self.window.select_sheets(sheets)
1807+
1808+
def _set_focused_sheet(self, sheet: Optional[sublime.Sheet]) -> None:
1809+
if sheet and sheet != self.window.active_sheet():
1810+
self.window.focus_sheet(sheet)
1811+
17891812
def decode_semantic_token(
17901813
self, token_type_encoded: int, token_modifiers_encoded: int) -> Tuple[str, List[str], Optional[str]]:
17911814
types_legend = tuple(cast(List[str], self.get_capability('semanticTokensProvider.legend.tokenTypes')))
@@ -1914,8 +1937,8 @@ def m_workspace_configuration(self, params: Dict[str, Any], request_id: Any) ->
19141937

19151938
def m_workspace_applyEdit(self, params: Any, request_id: Any) -> None:
19161939
"""handles the workspace/applyEdit request"""
1917-
self.apply_workspace_edit_async(params.get('edit', {})).then(
1918-
lambda _: self.send_response(Response(request_id, {"applied": True})))
1940+
self.apply_workspace_edit_async(params.get('edit', {})) \
1941+
.then(lambda _: self.send_response(Response(request_id, {"applied": True})))
19191942

19201943
def m_workspace_codeLens_refresh(self, _: Any, request_id: Any) -> None:
19211944
"""handles the workspace/codeLens/refresh request"""

plugin/core/types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,7 @@ def map_client_path_to_server_uri(self, path: str) -> str:
855855

856856
def map_server_uri_to_client_path(self, uri: str) -> str:
857857
scheme, path = parse_uri(uri)
858-
if scheme != "file":
858+
if scheme not in ("file", "res"):
859859
raise ValueError("{}: {} URI scheme is unsupported".format(uri, scheme))
860860
if self.path_maps:
861861
for path_map in self.path_maps:

plugin/core/url.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def _to_resource_uri(path: str, prefix: str) -> str:
8080
8181
See: https://github.com/sublimehq/sublime_text/issues/3742
8282
"""
83-
return "res://Packages{}".format(pathname2url(path[len(prefix):]))
83+
return "res:/Packages{}".format(pathname2url(path[len(prefix):]))
8484

8585

8686
def _uppercase_driveletter(match: Any) -> str:

plugin/core/views.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def __str__(self) -> str:
8686
return "invalid URI scheme: {}".format(self.uri)
8787

8888

89-
def get_line(window: sublime.Window, file_name: str, row: int) -> str:
89+
def get_line(window: sublime.Window, file_name: str, row: int, strip: bool = True) -> str:
9090
'''
9191
Get the line from the buffer if the view is open, else get line from linecache.
9292
row - is 0 based. If you want to get the first line, you should pass 0.
@@ -95,11 +95,12 @@ def get_line(window: sublime.Window, file_name: str, row: int) -> str:
9595
if view:
9696
# get from buffer
9797
point = view.text_point(row, 0)
98-
return view.substr(view.line(point)).strip()
98+
line = view.substr(view.line(point))
9999
else:
100100
# get from linecache
101101
# linecache row is not 0 based, so we increment it by 1 to get the correct line.
102-
return linecache.getline(file_name, row + 1).strip()
102+
line = linecache.getline(file_name, row + 1)
103+
return line.strip() if strip else line
103104

104105

105106
def get_storage_path() -> str:

plugin/core/windows.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,11 @@ def _needed_config(self, view: sublime.View) -> Optional[ClientConfig]:
232232
handled = True
233233
break
234234
if not handled:
235-
return config
235+
plugin = get_plugin(config.name)
236+
if plugin and plugin.should_ignore(view):
237+
debug(view, "ignored by plugin", plugin.__name__)
238+
else:
239+
return config
236240
return None
237241

238242
def start_async(self, config: ClientConfig, initiating_view: sublime.View) -> None:

plugin/edit.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from .core.edit import parse_range
2+
from .core.logging import debug
23
from .core.protocol import TextEdit
4+
from .core.protocol import WorkspaceEdit
5+
from .core.registry import LspWindowCommand
36
from .core.typing import List, Optional, Any, Generator, Iterable, Tuple
47
from contextlib import contextmanager
58
import operator
@@ -24,6 +27,16 @@ def temporary_setting(settings: sublime.Settings, key: str, val: Any) -> Generat
2427
settings.set(key, prev_val)
2528

2629

30+
class LspApplyWorkspaceEditCommand(LspWindowCommand):
31+
32+
def run(self, session_name: str, edit: WorkspaceEdit) -> None:
33+
session = self.session_by_name(session_name)
34+
if not session:
35+
debug('Could not find session', session_name, 'required to apply WorkspaceEdit')
36+
return
37+
sublime.set_timeout_async(lambda: session.apply_workspace_edit_async(edit))
38+
39+
2740
class LspApplyDocumentEditCommand(sublime_plugin.TextCommand):
2841
re_placeholder = re.compile(r'\$(0|\{0:([^}]*)\})')
2942

plugin/hover.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,10 @@ def request_document_link_async(self, listener: AbstractViewListener, point: int
195195
if target:
196196
link_promises.append(Promise.resolve(link))
197197
elif sv.has_capability_async("documentLinkProvider.resolveProvider"):
198-
link_promises.append(sv.session.send_request_task(Request.resolveDocumentLink(link, sv.view)).then(
199-
lambda link: self._on_resolved_link(sv.session_buffer, link)))
198+
link_promises.append(
199+
sv.session.send_request_task(Request.resolveDocumentLink(link, sv.view))
200+
.then(lambda link: self._on_resolved_link(sv.session_buffer, link))
201+
)
200202
if link_promises:
201203
Promise.all(link_promises).then(partial(self._on_all_document_links_resolved, listener, point))
202204

plugin/locationpicker.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def open_basic_file(
4747
if uri.startswith("file:"):
4848
filename = session.config.map_server_uri_to_client_path(uri)
4949
else:
50-
prefix = 'res://Packages' # Note: keep in sync with core/url.py#_to_resource_uri
50+
prefix = 'res:/Packages' # Note: keep in sync with core/url.py#_to_resource_uri
5151
assert uri.startswith(prefix)
5252
filename = sublime.packages_path() + url2pathname(uri[len(prefix):])
5353
# Window.open_file can only focus and scroll to a location in a resource file if it is already opened

0 commit comments

Comments
 (0)