diff --git a/plugins/lsp_client/lsp_controller.py b/plugins/lsp_client/lsp_controller.py index d967ae9..141bb25 100644 --- a/plugins/lsp_client/lsp_controller.py +++ b/plugins/lsp_client/lsp_controller.py @@ -55,7 +55,13 @@ class LSPController: if not language or not server_proc: return False json_rpc_endpoint = pylspclient.JsonRpcEndpoint(server_proc.stdin, server_proc.stdout) - lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint) + + callbacks = { + "textDocument/symbolStatus": print, + "textDocument/publishDiagnostics": self.blame, + } + + lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint, notify_callbacks = callbacks) lsp_client = pylspclient.LspClient(lsp_endpoint) self.lsp_clients[language] = lsp_client @@ -70,11 +76,19 @@ class LSPController: read_pipe.start() return server_proc + + + def blame(self, response): + for d in response['diagnostics']: + if d['severity'] == 1: + print(f"An error occurs in {response['uri']} at {d['range']}:") + print(f"\t[{d['source']}] {d['message']}") + + def _shutting_down(self): keys = self.lsp_clients.keys() for key in keys: print(f"LSP Server: ( {key} ) Shutting Down...") self.lsp_clients[key].shutdown() - self.lsp_clients[key].exit() - + self.lsp_clients[key].exit() \ No newline at end of file diff --git a/plugins/lsp_client/plugin.py b/plugins/lsp_client/plugin.py index d92dccd..4743c96 100644 --- a/plugins/lsp_client/plugin.py +++ b/plugins/lsp_client/plugin.py @@ -12,6 +12,12 @@ from .lsp_controller import LSPController + +class LSPPliginException(Exception): + ... + + + class Plugin(PluginBase): def __init__(self): super().__init__() @@ -90,6 +96,12 @@ class Plugin(PluginBase): else: self.lsp_client = self.load_lsp_server() + if self.lsp_client: + # Note: textDocument/didClose is actually called from the open api beforehand + # to insure no more than one instanmce of a file is opened + uri = self._active_src_view.get_current_filepath().get_uri() + self.register_opened_file(self._file_type, uri) + def load_lsp_server(self): command = self.lsp_servers_config[self._file_type]["command"] if command: @@ -98,13 +110,11 @@ class Plugin(PluginBase): if client_created: return self.lsp_controller.lsp_clients[self._file_type] - else: - text = f"LSP could not be created for file type: {self._file_type} ..." - self._event_system.emit("bubble_message", ("warning", self.name, text,)) + text = f"LSP could not be created for file type: {self._file_type} ..." + self._event_system.emit("bubble_message", ("warning", self.name, text,)) return None - def _buffer_changed_first_load(self, buffer): if self.lsp_disabled: return @@ -112,18 +122,73 @@ class Plugin(PluginBase): def _buffer_changed(self, buffer): if self.lsp_disabled: return + self._do_completion() + + + def _do_completion(self, is_invoked = False): + if self.lsp_disabled: return + + uri = self._active_src_view.get_current_filepath().get_uri() + iter = self._buffer.get_iter_at_mark( self._buffer.get_insert() ) + line = iter.get_line() + offset = iter.get_line_offset() + trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter + _char = iter.get_char() + trigger = None + + if _char in [".", " "]: + trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerCharacter + elif is_invoked: + trigger = pylspclient.lsp_structs.CompletionTriggerKind.Invoked + else: + trigger = pylspclient.lsp_structs.CompletionTriggerKind.TriggerForIncompleteCompletions + + result = self.lsp_client.completion( + pylspclient.lsp_structs.TextDocumentIdentifier(uri), + pylspclient.lsp_structs.Position(line, offset), + pylspclient.lsp_structs.CompletionContext(trigger, _char) + ) + + if result.items: + for item in result.items: + print(item.label) + else: + print(result.label) def _do_goto(self): if self.lsp_disabled: return - iter = self._buffer.get_iter_at_mark( self._buffer.get_insert() ) - line = iter.get_line() + 1 - offset = iter.get_line_offset() + 1 - uri = self._active_src_view.get_current_filepath().get_uri() - result = self.lsp_client.declaration(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(line, offset)) - - print(result) + iter = self._buffer.get_iter_at_mark( self._buffer.get_insert() ) + line = iter.get_line() + offset = iter.get_line_offset() + uri = self._active_src_view.get_current_filepath().get_uri() + results = self.lsp_client.definition( + pylspclient.lsp_structs.TextDocumentIdentifier(uri), + pylspclient.lsp_structs.Position(line, offset) + ) + results = [] + if len(results) == 1: + result = results[0] + file = result.uri[7:] + line = result.range.end.line + message = f"FILE|{file}:{line}" + self._event_system.emit("post_file_to_ipc", message) def _do_get_implementation(self): - if self.lsp_disabled: return \ No newline at end of file + if self.lsp_disabled: return + results = self.lsp_client.declaration(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(line, offset)) + + def register_opened_file(self, language_id = "", uri = ""): + if not language_id or not uri: return + + text = open(uri[7:], "r").read() + version = 1 + + self.lsp_client.didClose( + pylspclient.lsp_structs.TextDocumentItem(uri, language_id, version, text) + ) + + self.lsp_client.didOpen( + pylspclient.lsp_structs.TextDocumentItem(uri, language_id, version, text) + ) \ No newline at end of file diff --git a/plugins/lsp_client/pylspclient/lsp_client.py b/plugins/lsp_client/pylspclient/lsp_client.py index 1fe9126..1485abd 100644 --- a/plugins/lsp_client/pylspclient/lsp_client.py +++ b/plugins/lsp_client/pylspclient/lsp_client.py @@ -95,8 +95,12 @@ class LspClient(object): :param TextDocumentItem textDocument: The document that was opened. """ + self.lsp_endpoint.send_notification("textDocument/didClose", textDocument = textDocument) return self.lsp_endpoint.send_notification("textDocument/didOpen", textDocument = textDocument) + def didClose(self, textDocument): + return self.lsp_endpoint.send_notification("textDocument/didClose", textDocument = textDocument) + def didChange(self, textDocument, contentChanges): """ The document change notification is sent from the client to the server to signal changes to a text document. @@ -121,6 +125,7 @@ class LspClient(object): """ result_dict = self.lsp_endpoint.call_method( "textDocument/documentSymbol", textDocument=textDocument ) + if not result_dict: return [] return [lsp_structs.SymbolInformation(**sym) for sym in result_dict] def declaration(self, textDocument, position): @@ -142,6 +147,8 @@ class LspClient(object): position = position ) + if not result_dict: return [] + if "uri" in result_dict: return lsp_structs.Location(**result_dict) @@ -162,6 +169,7 @@ class LspClient(object): position = position ) + if not result_dict: return [] return [lsp_structs.Location(**loc) for loc in result_dict] def typeDefinition(self, textDocument, position): @@ -179,6 +187,7 @@ class LspClient(object): position = position ) + if not result_dict: return [] return [lsp_structs.Location(**loc) for loc in result_dict] def signatureHelp(self, textDocument, position): @@ -195,6 +204,7 @@ class LspClient(object): position = position ) + if not result_dict: return [] return lsp_structs.SignatureHelp(**result_dict) def completion(self, textDocument, position, context): @@ -214,35 +224,13 @@ class LspClient(object): position = position, context = context ) + if not result_dict: return [] + if "isIncomplete" in result_dict: return lsp_structs.CompletionList(**result_dict) return [lsp_structs.CompletionItem(**loc) for loc in result_dict] - def definition(self, textDocument, position): - """ - The go to definition request is sent from the client to the server to - resolve the declaration location of a symbol at a given text document - position. - - The result type LocationLink[] got introduce with version 3.14.0 and - depends in the corresponding client capability - `clientCapabilities.textDocument.declaration.linkSupport`. - - :param TextDocumentItem textDocument: The text document. - :param Position position: The position inside the text document. - """ - - result_dict = self.lsp_endpoint.call_method("textDocument/definition", - textDocument = textDocument, - position = position) - - if "uri" in result_dict: - return lsp_structs.Location(**result_dict) - - return [lsp_structs.Location(**l) - if "uri" in l else lsp_structs.LinkLocation(**l) for l in result_dict] - def references(self, textDocument, position): """ The references request is sent from the client to the server to resolve @@ -257,4 +245,5 @@ class LspClient(object): textDocument = textDocument, position = position) + if not result_dict: return [] return [lsp_structs.Location(**loc) for loc in result_dict] \ No newline at end of file