Merge branch 'lsp-widget-goto' into 'main'

Draft: LSP: created command for goto widget definition. Is incomplete

See merge request jwestman/blueprint-compiler!78
This commit is contained in:
Megadash452 2022-11-27 00:56:02 +00:00
commit 41fb14a60e

View file

@ -166,6 +166,7 @@ class LanguageServer:
"completionProvider": {}, "completionProvider": {},
"codeActionProvider": {}, "codeActionProvider": {},
"hoverProvider": True, "hoverProvider": True,
"declarationProvider": True,
}, },
"serverInfo": { "serverInfo": {
"name": "Blueprint", "name": "Blueprint",
@ -209,6 +210,57 @@ class LanguageServer:
else: else:
self._send_response(id, None) self._send_response(id, None)
@command("textDocument/declaration")
def gotoDeclaration(self, id, params):
"""Triggered when `Ctrl+LClick` over anything that references a widget
object by ID (e.g. the param in signal handler, the value token of a
property with type Widget, the id of the source widget in a property
binding, ...)"""
open_file = self._open_files[params["textDocument"]["uri"]]
span_start = utils.pos_to_idx(params["position"]["line"], params["position"]["character"], open_file.text)
obj_id = str(tokenizer._tokenize(open_file.text[span_start:]))
full_range = {
"start": { "line": 0, "character": 0 },
"end": { "line": 0, "character": 0 },
}
id_range = None # {
# "start": { "line": 0, "character": 0 },
# "end": { "line": 0, "character": 0 },
# }
for obj in open_file.ast.objects_by_id():
if str(obj.tokens["id"]) == obj_id:
tokens = list(obj.get_semantic_tokens())
# Full range starts at the position of the first token of the widget
position = utils.idx_to_pos(tokens[0].start, open_file.text)
full_range["start"]["line"] = position[0]
full_range["start"]["character"] = position[1]
# Goes through all the tokens (starting from the 2nd) of the widget object until ID token
for token in tokens[1:]:
if str(token) == obj_id:
position = utils.idx_to_pos(token.start, open_file.text)
id_range = {
"start": { "line": position[0], "character": position[1] },
"end": { "line": position[0], "character": position[1] + len(obj_id) },
}
full_range["end"] = id_range["end"]
break
break
if id_range:
# result: LocationLink array
self._send_response(id, [{
"targetUri": params["textDocument"]["uri"],
# contains from widget class to the closing curly bracket `}`
"targetRange": full_range,
# only contains widget's id
"targetSelectionRange": id_range
}])
else:
self._send_response(id, None)
@command("textDocument/completion") @command("textDocument/completion")
def completion(self, id, params): def completion(self, id, params):
open_file = self._open_files[params["textDocument"]["uri"]] open_file = self._open_files[params["textDocument"]["uri"]]