Skip to content

Commit

Permalink
Merge branch 'main' into feat/py38
Browse files Browse the repository at this point in the history
  • Loading branch information
predragnikolic committed Mar 19, 2024
2 parents 1bb3bc6 + d4538fa commit 20f8fc8
Show file tree
Hide file tree
Showing 15 changed files with 276 additions and 37 deletions.
2 changes: 2 additions & 0 deletions boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from .plugin.documents import DocumentSyncListener
from .plugin.documents import TextChangeListener
from .plugin.edit import LspApplyDocumentEditCommand
from .plugin.edit import LspApplyWorkspaceEditCommand
from .plugin.execute_command import LspExecuteCommand
from .plugin.folding_range import LspFoldAllCommand
from .plugin.folding_range import LspFoldCommand
Expand All @@ -68,6 +69,7 @@
from .plugin.panels import LspUpdateLogPanelCommand
from .plugin.panels import LspUpdatePanelCommand
from .plugin.references import LspSymbolReferencesCommand
from .plugin.rename import LspHideRenameButtonsCommand
from .plugin.rename import LspSymbolRenameCommand
from .plugin.save_command import LspSaveAllCommand
from .plugin.save_command import LspSaveCommand
Expand Down
18 changes: 18 additions & 0 deletions docs/src/language_servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,24 @@ Follow installation instructions on [LSP-tailwindcss](https://github.com/sublime

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

## Toit

1. Install the [Toit](https://packagecontrol.io/packages/Toit) package from Package Control for syntax highlighting.
2. Install the [Jaguar Language Server](https://github.com/toitlang/jaguar).
3. Open `Preferences > Package Settings > LSP > Settings` and add the `"jag"` client configuration to the `"clients"`:

```jsonc
{
"clients": {
"jag": {
"enabled": true,
"command": ["jag" "lsp"],
"selector": "source.toit"
}
}
}
```

## TypeScript

See [Javascript/TypeScript](#javascripttypescript).
Expand Down
10 changes: 9 additions & 1 deletion plugin/core/panels.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .types import PANEL_FILE_REGEX
from .types import PANEL_LINE_REGEX
from .typing import Optional
from .typing import Iterable, Optional
import sublime


Expand Down Expand Up @@ -38,6 +38,7 @@ class PanelName:
class PanelManager:
def __init__(self, window: sublime.Window) -> None:
self._window = window
self._rename_panel_buttons = None # type: Optional[sublime.PhantomSet]

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

def toggle_output_panel(self, panel_type: str) -> None:
panel_name = "output.{}".format(panel_type)
Expand Down Expand Up @@ -91,6 +93,8 @@ def _create_panel(self, name: str, result_file_regex: str, result_line_regex: st
panel = self.create_output_panel(name)
if not panel:
return None
if name == PanelName.Rename:
self._rename_panel_buttons = sublime.PhantomSet(panel, "lsp_rename_buttons")
settings = panel.settings()
if result_file_regex:
settings.set("result_file_regex", result_file_regex)
Expand Down Expand Up @@ -121,3 +125,7 @@ def show_diagnostics_panel_async(self) -> None:
def hide_diagnostics_panel_async(self) -> None:
if self.is_panel_open(PanelName.Diagnostics):
self.toggle_output_panel(PanelName.Diagnostics)

def update_rename_panel_buttons(self, phantoms: Iterable[sublime.Phantom]) -> None:
if self._rename_panel_buttons:
self._rename_panel_buttons.update(phantoms)
33 changes: 28 additions & 5 deletions plugin/core/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,15 @@ def on_post_start(cls, window: sublime.Window, initiating_view: sublime.View,
"""
pass

@classmethod
def should_ignore(cls, view: sublime.View) -> bool:
"""
Exclude a view from being handled by the language server, even if it matches the URI scheme(s) and selector from
the configuration. This can be used to, for example, ignore certain file patterns which are listed in a
configuration file (e.g. .gitignore).
"""
return False

@classmethod
def markdown_language_id_to_st_syntax_map(cls) -> Optional[MarkdownLangMap]:
"""
Expand Down Expand Up @@ -1383,6 +1392,9 @@ def compare_by_string(sb: Optional[SessionBufferProtocol]) -> bool:
def can_handle(self, view: sublime.View, scheme: str, capability: Optional[str], inside_workspace: bool) -> bool:
if not self.state == ClientStates.READY:
return False
if self._plugin and self._plugin.should_ignore(view):
debug(view, "ignored by plugin", self._plugin.__class__.__name__)
return False
if scheme == "file":
file_name = view.file_name()
if not file_name:
Expand Down Expand Up @@ -1759,8 +1771,7 @@ def _apply_code_action_async(
arguments = command.get("arguments")
if arguments is not None:
execute_command['arguments'] = arguments
return promise.then(
lambda _: self.execute_command(execute_command, progress=False, view=view))
return promise.then(lambda _: self.execute_command(execute_command, progress=False, view=view))
return promise

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

def apply_parsed_workspace_edits(self, changes: WorkspaceChanges) -> Promise[None]:
active_sheet = self.window.active_sheet()
selected_sheets = self.window.selected_sheets()
promises = [] # type: List[Promise[None]]
for uri, (edits, view_version) in changes.items():
promises.append(
self.open_uri_async(uri).then(functools.partial(self._apply_text_edits, edits, view_version, uri))
)
return Promise.all(promises).then(lambda _: None)
return Promise.all(promises) \
.then(lambda _: self._set_selected_sheets(selected_sheets)) \
.then(lambda _: self._set_focused_sheet(active_sheet))

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

def _set_selected_sheets(self, sheets: List[sublime.Sheet]) -> None:
if len(sheets) > 1 and len(self.window.selected_sheets()) != len(sheets):
self.window.select_sheets(sheets)

def _set_focused_sheet(self, sheet: Optional[sublime.Sheet]) -> None:
if sheet and sheet != self.window.active_sheet():
self.window.focus_sheet(sheet)

def decode_semantic_token(
self, token_type_encoded: int, token_modifiers_encoded: int) -> Tuple[str, List[str], Optional[str]]:
types_legend = tuple(cast(List[str], self.get_capability('semanticTokensProvider.legend.tokenTypes')))
Expand Down Expand Up @@ -1914,8 +1937,8 @@ def m_workspace_configuration(self, params: Dict[str, Any], request_id: Any) ->

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

def m_workspace_codeLens_refresh(self, _: Any, request_id: Any) -> None:
"""handles the workspace/codeLens/refresh request"""
Expand Down
2 changes: 1 addition & 1 deletion plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ def map_client_path_to_server_uri(self, path: str) -> str:

def map_server_uri_to_client_path(self, uri: str) -> str:
scheme, path = parse_uri(uri)
if scheme != "file":
if scheme not in ("file", "res"):
raise ValueError("{}: {} URI scheme is unsupported".format(uri, scheme))
if self.path_maps:
for path_map in self.path_maps:
Expand Down
2 changes: 1 addition & 1 deletion plugin/core/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _to_resource_uri(path: str, prefix: str) -> str:
See: https://github.com/sublimehq/sublime_text/issues/3742
"""
return "res://Packages{}".format(pathname2url(path[len(prefix):]))
return "res:/Packages{}".format(pathname2url(path[len(prefix):]))


def _uppercase_driveletter(match: Any) -> str:
Expand Down
7 changes: 4 additions & 3 deletions plugin/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __str__(self) -> str:
return "invalid URI scheme: {}".format(self.uri)


def get_line(window: sublime.Window, file_name: str, row: int) -> str:
def get_line(window: sublime.Window, file_name: str, row: int, strip: bool = True) -> str:
'''
Get the line from the buffer if the view is open, else get line from linecache.
row - is 0 based. If you want to get the first line, you should pass 0.
Expand All @@ -95,11 +95,12 @@ def get_line(window: sublime.Window, file_name: str, row: int) -> str:
if view:
# get from buffer
point = view.text_point(row, 0)
return view.substr(view.line(point)).strip()
line = view.substr(view.line(point))
else:
# get from linecache
# linecache row is not 0 based, so we increment it by 1 to get the correct line.
return linecache.getline(file_name, row + 1).strip()
line = linecache.getline(file_name, row + 1)
return line.strip() if strip else line


def get_storage_path() -> str:
Expand Down
6 changes: 5 additions & 1 deletion plugin/core/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,11 @@ def _needed_config(self, view: sublime.View) -> Optional[ClientConfig]:
handled = True
break
if not handled:
return config
plugin = get_plugin(config.name)
if plugin and plugin.should_ignore(view):
debug(view, "ignored by plugin", plugin.__name__)
else:
return config
return None

def start_async(self, config: ClientConfig, initiating_view: sublime.View) -> None:
Expand Down
13 changes: 13 additions & 0 deletions plugin/edit.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from .core.edit import parse_range
from .core.logging import debug
from .core.protocol import TextEdit
from .core.protocol import WorkspaceEdit
from .core.registry import LspWindowCommand
from .core.typing import List, Optional, Any, Generator, Iterable, Tuple
from contextlib import contextmanager
import operator
Expand All @@ -24,6 +27,16 @@ def temporary_setting(settings: sublime.Settings, key: str, val: Any) -> Generat
settings.set(key, prev_val)


class LspApplyWorkspaceEditCommand(LspWindowCommand):

def run(self, session_name: str, edit: WorkspaceEdit) -> None:
session = self.session_by_name(session_name)
if not session:
debug('Could not find session', session_name, 'required to apply WorkspaceEdit')
return
sublime.set_timeout_async(lambda: session.apply_workspace_edit_async(edit))


class LspApplyDocumentEditCommand(sublime_plugin.TextCommand):
re_placeholder = re.compile(r'\$(0|\{0:([^}]*)\})')

Expand Down
6 changes: 4 additions & 2 deletions plugin/hover.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,10 @@ def request_document_link_async(self, listener: AbstractViewListener, point: int
if target:
link_promises.append(Promise.resolve(link))
elif sv.has_capability_async("documentLinkProvider.resolveProvider"):
link_promises.append(sv.session.send_request_task(Request.resolveDocumentLink(link, sv.view)).then(
lambda link: self._on_resolved_link(sv.session_buffer, link)))
link_promises.append(
sv.session.send_request_task(Request.resolveDocumentLink(link, sv.view))
.then(lambda link: self._on_resolved_link(sv.session_buffer, link))
)
if link_promises:
Promise.all(link_promises).then(partial(self._on_all_document_links_resolved, listener, point))

Expand Down
2 changes: 1 addition & 1 deletion plugin/locationpicker.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def open_basic_file(
if uri.startswith("file:"):
filename = session.config.map_server_uri_to_client_path(uri)
else:
prefix = 'res://Packages' # Note: keep in sync with core/url.py#_to_resource_uri
prefix = 'res:/Packages' # Note: keep in sync with core/url.py#_to_resource_uri
assert uri.startswith(prefix)
filename = sublime.packages_path() + url2pathname(uri[len(prefix):])
# Window.open_file can only focus and scroll to a location in a resource file if it is already opened
Expand Down
Loading

0 comments on commit 20f8fc8

Please sign in to comment.