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
20 changes: 20 additions & 0 deletions plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from .core.protocol import ServerNotification
from .core.protocol import ServerRequest
from .core.protocol import ServerResponse
from .core.protocol import TextPosition
from .core.registry import LspTextCommand
from .core.registry import LspWindowCommand
from .core.sessions import Session
Expand All @@ -46,8 +47,17 @@
from .core.url import parse_uri
from .core.url import uri_to_filename # deprecated
from .core.version import __version__
from .core.views import first_selection_region
from .core.views import offset_to_text_position
from .core.views import point_to_offset
from .core.views import position_to_offset
from .core.views import region_to_range
from .core.views import text_document_identifier
from .core.views import text_document_position_params
from .core.views import uri_from_view
from .core.workspace import WorkspaceFolder
from .execute_command import LspExecuteCommand
from .locationpicker import LocationPicker

# This is the public API for LSP-* packages
__all__ = [
Expand All @@ -65,6 +75,8 @@
'FileWatcherEventType',
'FileWatcherProtocol',
'IsApplicableContext',
'LocationPicker',
'LspExecuteCommand',
'LspPlugin',
'LspTextCommand',
'LspWindowCommand',
Expand All @@ -82,19 +94,27 @@
'Session',
'SessionBufferProtocol',
'SessionViewProtocol',
'TextPosition',
'TransportWrapper',
'WorkspaceFolder',
'__version__',
'apply_text_edits',
'command_handler',
'css',
'filename_to_uri',
'first_selection_region',
'matches_pattern',
'notification_handler',
'offset_to_text_position',
'parse_uri',
'point_to_offset',
'position_to_offset',
'region_to_range',
'register_file_watcher_implementation',
'register_plugin',
'request_handler',
'text_document_identifier',
'text_document_position_params',
'unregister_plugin',
'uri_from_view',
'uri_handler',
Expand Down
34 changes: 13 additions & 21 deletions plugin/core/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from __future__ import annotations

from ...protocol import * # For backward compatibility with LSP packages. # noqa: F403
from functools import total_ordering
from dataclasses import dataclass
from typing import Any
from typing import Callable
from typing import Generic
Expand All @@ -12,6 +12,7 @@
from typing import TypedDict
from typing import TypeVar
from typing import Union
from typing_extensions import deprecated
from typing_extensions import NotRequired
from typing_extensions import TypeAlias

Expand Down Expand Up @@ -400,31 +401,17 @@ def to_payload(self) -> NotificationMessage:
return payload


@total_ordering
class Point:
def __init__(self, row: int, col: int) -> None:
self.row = int(row)
self.col = int(col) # in UTF-16
@dataclass(frozen=True, order=True)
class TextPosition:
row: int
col: int # in UTF-16

def __repr__(self) -> str:
return f"{self.row}:{self.col}"

def __eq__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return self.row == other.row and self.col == other.col

def __lt__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return (self.row, self.col) < (other.row, other.col)

def __hash__(self) -> int:
return hash(self.__repr__())

@classmethod
def from_lsp(cls, point: Position) -> Point:
return Point(point['line'], point['character'])
def from_lsp(cls, position: Position) -> TextPosition:
return cls(position['line'], position['character'])

def to_lsp(self) -> Position:
return {
Expand All @@ -433,6 +420,11 @@ def to_lsp(self) -> Position:
}


@deprecated('Use TextPosition instead')
class Point(TextPosition):
pass


class ResponseError(TypedDict):
code: int
message: str
Expand Down
22 changes: 14 additions & 8 deletions plugin/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
from .constants import SublimeKind
from .css import css as lsp_css
from .protocol import Notification
from .protocol import Point
from .protocol import Request
from .protocol import TextPosition
from .settings import userprefs
from .url import encode_code_action_uri
from .url import parse_uri
Expand All @@ -66,6 +66,7 @@
from typing import Iterable
from typing import Sequence
from typing import TYPE_CHECKING
from typing_extensions import deprecated
import html
import itertools
import linecache
Expand Down Expand Up @@ -170,22 +171,27 @@ def extract_variables(window: sublime.Window) -> dict[str, str]:
return variables


def point_to_offset(point: Point, view: sublime.View) -> int:
def point_to_offset(point: TextPosition, view: sublime.View) -> int:
# @see https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#position
# If the character value is greater than the line length it defaults back to the line length.
return view.text_point_utf16(point.row, point.col, clamp_column=True)


def offset_to_point(view: sublime.View, offset: int) -> Point:
return Point(*view.rowcol_utf16(offset))
def offset_to_point(view: sublime.View, offset: int) -> TextPosition:
return TextPosition(*view.rowcol_utf16(offset))


def position(view: sublime.View, offset: int) -> Position:
def offset_to_text_position(view: sublime.View, offset: int) -> Position:
return offset_to_point(view, offset).to_lsp()


@deprecated('Use offset_to_text_position() instead')
def position(view: sublime.View, offset: int) -> Position:
return offset_to_text_position(view, offset)


def position_to_offset(position: Position, view: sublime.View) -> int:
return point_to_offset(Point.from_lsp(position), view)
return point_to_offset(TextPosition.from_lsp(position), view)


def get_symbol_kind_from_scope(scope_name: str) -> SublimeKind:
Expand Down Expand Up @@ -306,7 +312,7 @@ def versioned_text_document_identifier(view: sublime.View, version: int) -> Vers


def text_document_position_params(view: sublime.View, location: int) -> TextDocumentPositionParams:
return {"textDocument": text_document_identifier(view), "position": position(view, location)}
return {"textDocument": text_document_identifier(view), "position": offset_to_text_position(view, location)}


def did_open_text_document_params(view: sublime.View, language_id: str) -> DidOpenTextDocumentParams:
Expand Down Expand Up @@ -439,7 +445,7 @@ def text_document_ranges_formatting(
def selection_range_params(view: sublime.View) -> SelectionRangeParams:
return {
"textDocument": text_document_identifier(view),
"positions": [position(view, r.b) for r in view.sel()]
"positions": [offset_to_text_position(view, r.b) for r in view.sel()]
}


Expand Down
10 changes: 5 additions & 5 deletions plugin/references.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations

from .core.constants import RegionKey
from .core.protocol import Point
from .core.protocol import Request
from .core.protocol import TextPosition
from .core.registry import get_position
from .core.registry import LspTextCommand
from .core.registry import windows
Expand Down Expand Up @@ -181,7 +181,7 @@ def _show_references_in_quick_panel(
placeholder = "References to " + word
kind = get_symbol_kind_from_scope(self.view.scope_name(position))
index = 0
locations.sort(key=lambda location: (location['uri'], Point.from_lsp(location['range']['start'])))
locations.sort(key=lambda location: (location['uri'], TextPosition.from_lsp(location['range']['start'])))
if len(selection):
pt = selection[0].b
view_filename = self.view.file_name()
Expand Down Expand Up @@ -244,13 +244,13 @@ def _group_locations_by_uri(
window: sublime.Window,
config: ClientConfig,
locations: list[Location]
) -> dict[str, list[tuple[Point, str]]]:
) -> dict[str, list[tuple[TextPosition, str]]]:
"""Return a dictionary that groups locations by the URI it belongs."""
grouped_locations: dict[str, list[tuple[Point, str]]] = {}
grouped_locations: dict[str, list[tuple[TextPosition, str]]] = {}
for location in locations:
uri, position = get_uri_and_position_from_location(location)
file_path = config.map_server_uri_to_client_path(uri)
point = Point.from_lsp(position)
point = TextPosition.from_lsp(position)
# get line of the reference, to showcase its use
reference_line = get_line(window, file_path, point.row)
if grouped_locations.get(file_path) is None:
Expand Down
Loading