Skip to content

Commit

Permalink
Merge bd265ed into 1e09409
Browse files Browse the repository at this point in the history
  • Loading branch information
rwols committed Jul 20, 2019
2 parents 1e09409 + bd265ed commit 0a09c1f
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 34 deletions.
12 changes: 12 additions & 0 deletions Keymaps/Default (Linux).sublime-keymap
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
// Go To Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_definition"},

// Go To Type Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_type_definition"},

// Go To Declaration
// {"keys": ["UNBOUND"], "command": "lsp_symbol_declaration"},

// Go To Implementation
// {"keys": ["UNBOUND"], "command": "lsp_symbol_implementation"},

// Rename Symbol
// { "keys": ["UNBOUND"], "command": "lsp_symbol_rename" },

Expand All @@ -43,4 +52,7 @@

// Document Symbols
// {"keys": ["UNBOUND"], "command": "lsp_document_symbols"},

// Symbol Hover
// {"keys": ["UNBOUND"], "command": "lsp_hover"},
]
10 changes: 9 additions & 1 deletion Keymaps/Default (OSX).sublime-keymap
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
// Go To Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_definition"},

// Go To Type Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_type_definition"},

// Go To Declaration
// {"keys": ["UNBOUND"], "command": "lsp_symbol_declaration"},

// Go To Implementation
// {"keys": ["UNBOUND"], "command": "lsp_symbol_implementation"},

// Rename Symbol
// { "keys": ["UNBOUND"], "command": "lsp_symbol_rename" },

Expand All @@ -46,5 +55,4 @@

// Symbol Hover
// {"keys": ["UNBOUND"], "command": "lsp_hover"},

]
12 changes: 12 additions & 0 deletions Keymaps/Default (Windows).sublime-keymap
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
// Go To Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_definition"},

// Go To Type Definition
// {"keys": ["UNBOUND"], "command": "lsp_symbol_type_definition"},

// Go To Declaration
// {"keys": ["UNBOUND"], "command": "lsp_symbol_declaration"},

// Go To Implementation
// {"keys": ["UNBOUND"], "command": "lsp_symbol_implementation"},

// Rename Symbol
// { "keys": ["UNBOUND"], "command": "lsp_symbol_rename" },

Expand All @@ -43,4 +52,7 @@

// Document Symbols
// {"keys": ["UNBOUND"], "command": "lsp_document_symbols"},

// Symbol Hover
// {"keys": ["UNBOUND"], "command": "lsp_hover"},
]
12 changes: 12 additions & 0 deletions Menus/Context.sublime-menu
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@
"command": "lsp_symbol_definition",
"caption": "Go To Symbol Definition"
},
{
"command": "lsp_symbol_type_definition",
"caption": "Go To Symbol Type Definition"
},
{
"command": "lsp_symbol_declaration",
"caption": "Go To Symbol Declaration"
},
{
"command": "lsp_symbol_implementation",
"caption": "Go To Symbol Implementation"
},
{
"command": "lsp_symbol_rename",
"caption": "Rename Symbol"
Expand Down
2 changes: 1 addition & 1 deletion boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .plugin.configuration import *
from .plugin.formatting import *
from .plugin.highlights import *
from .plugin.definition import *
from .plugin.goto import *
from .plugin.hover import *
from .plugin.references import *
from .plugin.signature_help import *
Expand Down
2 changes: 1 addition & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Symbol References: `shift+f12`
* Rename Symbol: UNBOUND
* Recommendation: Override `F2` (next bookmark)
* Go to definition: UNBOUND
* Go to definition / type definition / declaration / implementation: UNBOUND
* Recommendation: Override `f12` (built-in goto definition),
* LSP falls back to ST3's built-in goto definition command in case LSP fails.
* Format Document: UNBOUND
Expand Down
12 changes: 12 additions & 0 deletions plugin/core/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ def references(cls, params: dict) -> 'Request':
def definition(cls, params: dict) -> 'Request':
return Request("textDocument/definition", params)

@classmethod
def typeDefinition(cls, params: dict) -> 'Request':
return Request("textDocument/typeDefinition", params)

@classmethod
def declaration(cls, params: dict) -> 'Request':
return Request("textDocument/declaration", params)

@classmethod
def implementation(cls, params: dict) -> 'Request':
return Request("textDocument/implementation", params)

@classmethod
def rename(cls, params: dict) -> 'Request':
return Request("textDocument/rename", params)
Expand Down
24 changes: 17 additions & 7 deletions plugin/core/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,28 @@
pass


completion_provider = {
'triggerCharacters': ['.'],
'resolveProvider': False
basic_responses = {
'initialize': {
'capabilities': {
'testing': True,
'hoverProvider': True,
'completionProvider': {
'triggerCharacters': ['.'],
'resolveProvider': False
},
'textDocumentSync': True,
'definitionProvider': True,
'typeDefinitionProvider': True,
'declarationProvider': True,
'implementationProvider': True
}
}
}


class MockClient():
def __init__(self, async_response=None) -> None:
self.responses = {
'initialize': {"capabilities": dict(testing=True, hoverProvider=True,
completionProvider=completion_provider, textDocumentSync=True)},
} # type: dict
self.responses = basic_responses
self._notifications = [] # type: List[Notification]
self._async_response_callback = async_response

Expand Down
51 changes: 44 additions & 7 deletions plugin/definition.py → plugin/goto.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .core.documents import get_document_position, get_position, is_at_word
from .core.url import uri_to_filename
from .core.logging import debug
from .core.types import ViewLike
from Default.history_list import get_jump_history_for_view

try:
Expand All @@ -14,31 +15,37 @@
pass


class LspSymbolDefinitionCommand(LspTextCommand):
def __init__(self, view):
class LspGotoCommand(LspTextCommand):

def __init__(self, view: ViewLike) -> None:
super().__init__(view)
self.goto_kind = "definition"

def is_enabled(self, event=None):
if self.has_client_with_capability('definitionProvider'):
if self.has_client_with_capability(self.goto_kind + "Provider"):
return is_at_word(self.view, event)
return False

def run(self, edit, event=None) -> None:
def run(self, _, event=None) -> None:
client = client_for_view(self.view)
if client:
pos = get_position(self.view, event)
document_position = get_document_position(self.view, pos)
if document_position:
request = Request.definition(document_position)
request_type = getattr(Request, self.goto_kind)
if not request_type:
debug("unrecognized goto kind:", self.goto_kind)
return
request = request_type(document_position)
client.send_request(
request, lambda response: self.handle_response(response, pos))

def handle_response(self, response: 'Optional[Any]', position) -> None:
window = sublime.active_window()
if response:
# save to jump back history
# Save to jump back history.
get_jump_history_for_view(self.view).push_selection(self.view)

# TODO: DocumentLink support.
location = response if isinstance(response, dict) else response[0]
file_path = uri_to_filename(location.get("uri"))
start = Point.from_lsp(location['range']['start'])
Expand All @@ -47,7 +54,37 @@ def handle_response(self, response: 'Optional[Any]', position) -> None:
window.open_file(file_location, sublime.ENCODED_POSITION)
# TODO: can add region here.
else:
sublime.status_message("Empty response from language server, "
"reverting to Sublime's built-in Goto Definition")
window.run_command("goto_definition")

def want_event(self):
return True


class LspSymbolDefinitionCommand(LspGotoCommand):

def __init__(self, view: ViewLike) -> None:
super().__init__(view)
self.goto_kind = "definition"


class LspSymbolTypeDefinitionCommand(LspGotoCommand):

def __init__(self, view: ViewLike) -> None:
super().__init__(view)
self.goto_kind = "typeDefinition"


class LspSymbolDeclarationCommand(LspGotoCommand):

def __init__(self, view: ViewLike) -> None:
super().__init__(view)
self.goto_kind = "declaration"


class LspSymbolImplementationCommand(LspGotoCommand):

def __init__(self, view: ViewLike) -> None:
super().__init__(view)
self.goto_kind = "implementation"
36 changes: 26 additions & 10 deletions plugin/hover.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ def on_hover(self, point, hover_zone):
}


class GotoKind:

__slots__ = ("lsp_name", "label", "subl_cmd_name")

def __init__(self, lsp_name: str, label: str, subl_cmd_name: str) -> None:
self.lsp_name = lsp_name
self.label = label
self.subl_cmd_name = subl_cmd_name


goto_kinds = [
GotoKind("definition", "Definition", "definition"),
GotoKind("typeDefinition", "Type Definition", "type_definition"),
GotoKind("declaration", "Declaration", "declaration"),
GotoKind("implementation", "Implemenation", "implementation")
]


class LspHoverCommand(LspTextCommand):
def __init__(self, view):
super().__init__(view)
Expand Down Expand Up @@ -91,11 +109,9 @@ def handle_response(self, response: 'Optional[Any]', point) -> None:

def symbol_actions_content(self):
actions = []
if self.has_client_with_capability('definitionProvider'):
actions.append("<a href='{}'>{}</a>".format('definition', 'Definition'))

if self.has_client_with_capability('referencesProvider'):
actions.append("<a href='{}'>{}</a>".format('references', 'References'))
for goto_kind in goto_kinds:
if self.has_client_with_capability(goto_kind.lsp_name + "Provider"):
actions.append("<a href='{}'>{}</a>".format(goto_kind.lsp_name, goto_kind.label))

if self.has_client_with_capability('renameProvider'):
actions.append("<a href='{}'>{}</a>".format('rename', 'Rename'))
Expand Down Expand Up @@ -163,11 +179,11 @@ def show_hover(self, point, contents):
on_navigate=lambda href: self.on_hover_navigate(href, point))

def on_hover_navigate(self, href, point):
if href == 'definition':
self.run_command_from_point(point, "lsp_symbol_definition")
elif href == 'references':
self.run_command_from_point(point, "lsp_symbol_references")
elif href == 'rename':
for goto_kind in goto_kinds:
if href == goto_kind.lsp_name:
self.run_command_from_point(point, "lsp_symbol_" + goto_kind.subl_cmd_name)
return
if href == 'rename':
self.run_command_from_point(point, "lsp_symbol_rename")
elif href == 'code-actions':
self.run_command_from_point(point, "lsp_code_actions")
Expand Down
17 changes: 10 additions & 7 deletions tests/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ def remove_session(wm, config_name):
wm._handle_session_ended(config_name)


def close_test_view(view):
if view:
view.set_scratch(True)
view.window().focus_view(view)
view.window().run_command("close_file")


class TextDocumentTestCase(DeferrableTestCase):

def setUp(self):
def setUp(self) -> None:
self.view = sublime.active_window().open_file(test_file_path)
self.wm = windows.lookup(self.view.window())
self.client = MockClient(async_response=sublime_delayer(100))
Expand All @@ -59,11 +66,7 @@ def get_view_event_listener(self, unique_attribute: str):
if unique_attribute in dir(listener):
return listener

def tearDown(self):
def tearDown(self) -> None:
remove_session(self.wm, text_config.name)
remove_config(text_config)

if self.view:
self.view.set_scratch(True)
self.view.window().focus_view(self.view)
self.view.window().run_command("close_file")
close_test_view(self.view)

0 comments on commit 0a09c1f

Please sign in to comment.