diff --git a/pylspclient/lsp_endpoint.py b/pylspclient/lsp_endpoint.py index 7de605a..b811b3a 100644 --- a/pylspclient/lsp_endpoint.py +++ b/pylspclient/lsp_endpoint.py @@ -1,12 +1,20 @@ from __future__ import print_function import threading +import collections +from pylspclient import lsp_structs + + +class MethodNotFound(object): + def __call__(self, jsonrpc_message): + raise lsp_structs.ResponseError("Method not found: {method}".format(method=jsonrpc_message["method"]), lsp_structs.ErrorCodes.MethodNotFound) + class LspEndpoint(threading.Thread): - def __init__(self, json_rpc_endpoint, default_callback=print, callbacks={}): + def __init__(self, json_rpc_endpoint, default_method_callback=MethodNotFound(), method_callbacks={}, default_notify_callback=print, notify_callbacks={}): threading.Thread.__init__(self) self.json_rpc_endpoint = json_rpc_endpoint - self.callbacks = callbacks - self.default_callback = default_callback + self.notify_callbacks = collections.defaultdict(lambda : default_notify_callback, notify_callbacks) + self.method_callbacks = collections.defaultdict(lambda : default_method_callback, method_callbacks) self.event_dict = {} self.response_dict = {} self.next_id = 0 @@ -36,14 +44,31 @@ class LspEndpoint(threading.Thread): if "result" in jsonrpc_message or "error" in jsonrpc_message: self.handle_result(jsonrpc_message) elif "method" in jsonrpc_message: - if jsonrpc_message["method"] in self.callbacks: - self.callbacks[jsonrpc_message["method"]](jsonrpc_message) + if "id" in jsonrpc_message: + # a call for method + try: + result = self.method_callbacks[jsonrpc_message["method"]](jsonrpc_message) + self.send_response(jsonrpc_message["id"], result, None) + except lsp_structs.ResponseError as e: + self.send_response(jsonrpc_message["id"], None, e) else: - self.default_callback(jsonrpc_message) + # a call for notify + self.notify_callbacks[jsonrpc_message["method"]](jsonrpc_message) else: print("unknown jsonrpc message") - - + + + def send_response(self, id, result, error): + message_dict = {} + message_dict["jsonrpc"] = "2.0" + message_dict["id"] = id + if result: + message_dict["result"] = result + if error: + message_dict["error"] = error + self.json_rpc_endpoint.send_request(message_dict) + + def send_message(self, method_name, params, id = None): message_dict = {} message_dict["jsonrpc"] = "2.0" @@ -63,8 +88,10 @@ class LspEndpoint(threading.Thread): self.send_message(method_name, kwargs, current_id) cond.wait() cond.release() - # TODO: check if error, and throw an exception response = self.response_dict[current_id] + if "error" in response: + error = response["error"] + raise lsp_structs.ResponseError(error.get("code"), error.get("message"), error.get("data")) return response["result"] diff --git a/pylspclient/lsp_structs.py b/pylspclient/lsp_structs.py index 6c8e938..04ebaa3 100644 --- a/pylspclient/lsp_structs.py +++ b/pylspclient/lsp_structs.py @@ -425,3 +425,26 @@ class CompletionList(object): """ self.isIncomplete = isIncomplete self.items = [to_type(i, CompletionItem) for i in items] + +class ErrorCodes(object): + # Defined by JSON RPC + ParseError = -32700 + InvalidRequest = -32600 + MethodNotFound = -32601 + InvalidParams = -32602 + InternalError = -32603 + serverErrorStart = -32099 + serverErrorEnd = -32000 + ServerNotInitialized = -32002 + UnknownErrorCode = -32001 + + # Defined by the protocol. + RequestCancelled = -32800 + ContentModified = -32801 + +class ResponseError(Exception): + def __init__(self, code, message, data = None): + self.code = code + self.message = message + if data: + self.data = data \ No newline at end of file