diff --git a/testing/connection.py b/testing/connection.py deleted file mode 100644 index 289f122..0000000 --- a/testing/connection.py +++ /dev/null @@ -1,290 +0,0 @@ -import json -import os -import re -import subprocess -import threading -import time - -try: - from Queue import Queue, Empty -except ImportError: - from queue import Queue, Empty # python 3.x - -# Local config options -# import config - -my_json = """ -{"id": 0, -"jsonrpc": "2.0", -"method": "textDocument/didOpen", -"params": {"uri": "file://tests/test.go", - "version": 0, "languageId": "go", - "text": "// In Go, _variables_ are explicitly declared and used by - \n// the compiler to e.g. check type-correctness of function - \n// calls.\n - \npackage main\n - \nimport \"fmt\"\n - \nfunc main() {\n - \n // `var` declares 1 or more variables.\n var a string = \"initial\" - \n fmt.Println(a)\n\n // You can declare multiple variables at once. - \n var b, c int = 1, 2\n fmt.Println(b, c)\n - \n // Go will infer the type of initialized variables. - \n var d = true\n fmt.Println(d) - \n\n // Variables declared without a corresponding - \n // initialization are _zero-valued_. For example, the - \n // zero value for an `int` is `0`. - \n var e int\n fmt.Println(e)\n - \n // The `:=` syntax is shorthand for declaring and - \n // initializing a variable, - e.g. for\n // `var f string = \"short\"` in this case. - \n f := \"short\"\n fmt.Println(f)\n}"}}""" - - -class LangServer: - def __init__(self): - # self.server = subprocess.Popen( - # [config.cargo_path, "run", "-q"], - # env={ "RUST_BACKTRACE": "1", - # "SYS_ROOT": config.sys_root, - # "TMPDIR": config.tmpdir }, - # cwd=config.rustls_dir, - # bufsize=0, - # stdin=subprocess.PIPE, - # stdout=subprocess.PIPE, - # stderr=subprocess.DEVNULL, - # close_fds=True, # Possibly only useful on Posix - # universal_newlines=True) - self.server = subprocess.Popen(['/home/tj/go/bin/langserver-python', '-log', 'temp.log'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True, - universal_newlines=True) - - self.response_queue = Queue() - self.notification_queue = Queue() - self.io_thread = threading.Thread( - target=self.response_handler) - - # thread dies with the program - self.io_thread.daemon = True - self.io_thread.start() - - self.header_regex = re.compile("(?P
(\w|-)+): (?P\d+)") - # The first unused id. Incremented with every request. - self.next_id = 1 - - self.in_flight_ids = set() - - def response_handler(self): - while True: - response = self.read_response() - if response is None: - break - elif isinstance(response, str): - print(response) - elif response.get("id") is not None: - assert response["id"] in self.in_flight_ids - # We know this is a response to a request we sent - self.in_flight_ids.remove(response["id"]) - self.response_queue.put(response) - else: - # It's a notification - self.notification_queue.put(response) - - def read_headers(self): - """Reads in the headers for a response""" - result = {} - while True: - line = self.server.stdout.readline() - if line == "\n": - break - m = self.header_regex.match(line) - if m: - result[m.group("header")] = m.group("value") - else: - break - return result - - def read_response(self): - print('Reading response') - headers = self.read_headers() - if "Content-Length" not in headers: - return None - size = int(headers["Content-Length"]) - content = self.server.stdout.read(size) - try: - return json.loads(content) - except: - return content - - def _format_request(self, request): - """Converts the request into json and adds the Content-Length header""" - content = json.dumps(request, indent=2) - content_length = len(content) - - result = "Content-Length: {}\r\n\r\n{}".format(content_length, content) - return result - - def request(self, method, **params): - # TODO(tbelaire) more methods. - assert method in ["initialize", "shutdown", "exit", "textDocument/didOpen", "textDocument/definition"] - request = { - "jsonrpc": "2.0", - "id": self.next_id, - "method": method, - "params": params, - } - self.in_flight_ids.add(self.next_id) - self.next_id += 1 - formatted_req = self._format_request(request) - # TODO(tbelaire) log - self.server.stdin.write(formatted_req) - self.server.stdin.flush() - print(formatted_req) - - def initialize(self): - self.request("initialize", - processId=os.getpid(), - # rootPath=config.project_dir, - rootPath='file:///home/tj/.vim/plugged/nvim-langserver-shim/tests/', - capabilities={}) - # response = self.response_queue.get(True) - # return response - - def shutdown(self): - self.request("shutdown") - response = self.response_queue.get(True) - self.request("exit") - self.server.wait() - assert self.server.returncode == 0 - return response - - -rls = LangServer() - - -print("First thing") -print("Response:") -response = rls.initialize() -print(response) -print('After response') -# print(json.dumps(response, indent=2)) - -# print("Notification:") -# response = rls.notification_queue.get(True) -# print(response) -# print(json.dumps(response, indent=2)) - -time.sleep(1) -count = 0 -while True: - any_non_empty = False - - # my_choice = input('Choice') - - # if my_choice == 'y': - print('sending my json') - if count == -1: - rls.request('textDocument/didOpen', **{ - "uri": "file://tests/test.go", - "version": 1, - "languageId": "go", - "text": """ -// In Go, _variables_ are explicitly declared and used by -// the compiler to e.g. check type-correctness of function -// calls. - -package main - -import "fmt" - -func main() { - - // `var` declares 1 or more variables. - var a string = "initial" - fmt.Println(a) - - // You can declare multiple variables at once. - var b, c int = 1, 2 - fmt.Println(b, c) - - // Go will infer the type of initialized variables. - var d = true - fmt.Println(d) - - // Variables declared without a corresponding - // initialization are _zero-valued_. For example, the - // zero value for an `int` is `0`. - var e int - fmt.Println(e) - - // The `:=` syntax is shorthand for declaring and - // initializing a variable, e.g. for - // `var f string = "short"` in this case. - f := "short" - fmt.Println(f) -} -} -"""}) - - count += 1 - elif count == -1: - rls.request('textDocument/definition', - **{ - 'textDocument': { - # "uri": "file://tests/test.go", - "uri": "file:///home/tj/.vim/plugged/nvim-langserver-shim/tests/test.go", - }, - 'position': {'character': 16, 'line': 12}, - 'includeDeclaration': True - } - ) - elif count == 0: - rls.request('textDocument/didOpen', **{ - "uri": "file://tests/test.go", - "version": 1, - "languageId": "python", - "text": """ -hello = 'world' - -print(hello) -"""}) - count += 1 - elif count == 1: - rls.request('textDocument/definition', - **{ - 'textDocument': { - # "uri": "file://tests/test.go", - "uri": "file:///home/tj/.vim/plugged/nvim-langserver-shim/tests/test.py", - }, - 'position': {'character': 6, 'line': 2}, - 'includeDeclaration': True - } - ) - - # rls.server.stdin.write(my_json) - # rls.server.stdin.flush() - - try: - response = rls.response_queue.get_nowait() - print("Response:") - print(json.dumps(response, indent=2)) - any_non_empty = True - except Empty: - pass - - try: - notification = rls.notification_queue.get_nowait() - print("Notification:") - print(json.dumps(notification, indent=2)) - any_non_empty = True - except Empty: - pass - - my_val = input() - - if my_val == 'q': - break - -print("Done") diff --git a/testing/idea.py b/testing/idea.py deleted file mode 100644 index 97f6005..0000000 --- a/testing/idea.py +++ /dev/null @@ -1,106 +0,0 @@ - - -""" -I was actually thinking we might even be able to find an easier way for people to implement lsp clients, -at least if python is a valid plugin language for the editor. - -Steps: - - Create a LSP client in Python (A lot of that is done). - - Register known callbacks for the editor -""" - -import time -from queue import Empty - -import neovim - -from LSP import util - - -def nvim_get_position(nvim): - return { - 'line': nvim.line, - 'character': nvim.col - } - - -@neovim.plugin -class NeovimLSP: - # Not sure exactly what args you would pass into this yet - def __init__(self, client, others): - self.nvim = neovim.attach() - self.client = client - - # Create a mapping in Vim for the client - self.nvim.command('nnoremap lh :LSPHover ') - - self.supported_topics = [ - 'textDocument/hover', - ] - - @neovim.command("LSPHover", nargs='*') - def textDocument_hover_request(self, args): - callback_args = {'TODO': 'TODO'} - self.client.hover( - callback_args, - 'textDocument/hover', - text_document=self.nvim.command('expand("%")'), - position=nvim_get_position(self.nvim) - ) - - def get_textDocument_hover_args(self): - return {'client': 'neovim'} - - def textDocument_hover_callback(self, lsp_message: dict, callback_data: dict): - self.nvim.command('call langserver#goto#response({0}, {1}, {2})'.format( - util.uri_to_path(lsp_message['result'][0]['uri']), - lsp_message['result'][0]['range']['start']['line'], - lsp_message['result'][0]['range']['start']['character'], - )) - - # Could also implement common helper functions - # ... which could be used in the client manager - def get_file_name(self): - return self.nvim.command('expand("%")') - - -class LspClientManager(): - def __init__(self): - # Initializing code ... - pass - - def get_plugin(self, plugin_class, **kwargs): - # Register the plugin, or create it here as well - return plugin_class(**kwargs) - - # Other code here - - def response_handler(self, plugin, response_queue): - while True: - try: - response, callback_args = response_queue.get_nowait() - - method = callback_args['request']['method'] - if method in plugin.supported_topics: - # Run the corresponding callback - getattr(plugin, method.rplace('/', '_') + '_callback')(response, callback_args) - else: - print(callback_args['request']['method']) - - except Empty: - pass - except Exception as err: - print("Error handling reponse %s with callback args %s, err: %s" % - (response, callback_args, err)) - print(err) - - time.sleep(.05) - - # More code here - - def textDocument_hover_request(self, plugin, client): - client.hover( - plugin.get_textDocument_hover_args(), - plugin.get_textDocumentPositionParams(), - plugin.get_position(), - ) diff --git a/testing/new_connection.py b/testing/new_connection.py deleted file mode 100644 index f23b5b2..0000000 --- a/testing/new_connection.py +++ /dev/null @@ -1,281 +0,0 @@ -#!/usr/bin/env python3 -# Modified source code @tbelair -# https://github.com/tbelaire/lang-server-client - -import json -import os -import re -import subprocess -import threading - -import time - - -try: - from Queue import Queue, Empty -except ImportError: - from queue import Queue, Empty # python 3.x - - -class LspClient: - - def __init__(self, binary_name, args, env, root_path, response_queue): - args.insert(0, binary_name) - self.server = subprocess.Popen( - args, - env=env, - cwd=root_path, - bufsize=0, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - close_fds=True, # Possibly only useful on Posix - universal_newlines=True) - - self.response_queue = response_queue - self.notification_queue = Queue() - self.io_thread = threading.Thread( - target=self.response_handler) - - self.io_thread.daemon = True # thread dies with the program - self.io_thread.start() - - self.header_regex = re.compile("(?P
(\w|-)+): (?P\d+)") - # The first unused id. Incremented with every request. - self.next_id = 1 - - # id -> callback_args map - self.in_flight_ids = {} - - def response_handler(self): - while True: - response = self.read_response() - if response is None: - break - elif response.get("id") is not None: - assert response["id"] in self.in_flight_ids - callback_args = self.in_flight_ids[response["id"]] - # We know this is a response to a request we sent - del self.in_flight_ids[response["id"]] - self.response_queue.put((response, callback_args)) - else: - # It's a notification - self.notification_queue.put(response) - - def read_headers(self): - """Reads in the headers for a response""" - result = {} - while True: - line = self.server.stdout.readline() - if line == "\n": - break - m = self.header_regex.match(line) - if m: - result[m.group("header")] = m.group("value") - else: - break - return result - - def read_response(self): - headers = self.read_headers() - if "Content-Length" not in headers: - return None - size = int(headers["Content-Length"]) - # TODO(uforic) figure out why this is off by one - # I think a \n is being left from the previous line - content = self.server.stdout.read(size + 1) - # content = content + "}" - return json.loads(content) - - def _format_request(self, request): - """Converts the request into json and adds the Content-Length header""" - content = json.dumps(request, indent=2) - content_length = len(content) - - result = "Content-Length: {}\r\n\r\n{}".format(content_length, content) - return result - - def request(self, callback_args, method, **params): - # TODO(tbelaire) more methods. - assert method in [ - "initialize", - "textDocument/hover", - "textDocument/definition", - "textDocument/documentSymbol", - "textDocument/references", - "shutdown", - "exit"] - request = { - "jsonrpc": "2.0", - "id": self.next_id, - "method": method, - "params": params, - } - callback_args['request'] = request - self.in_flight_ids[self.next_id] = callback_args - self.next_id += 1 - formatted_req = self._format_request(request) - # TODO(tbelaire) log - self.server.stdin.write(formatted_req) - self.server.stdin.flush() - - def initialize(self, callback_args, root_path): - self.request(callback_args, - "initialize", - processId=os.getpid(), - rootPath=root_path, - capabilities={}) - response = self.response_queue.get(True) - return response - - def hover(self, callback_args, text_document, position): - self.request(callback_args, - "textDocument/hover", - textDocument=text_document, - position=position) - return - - def definition(self, callback_args, text_document, position): - self.request(callback_args, - "textDocument/definition", - textDocument=text_document, - position=position) - return - - def documentSymbol(self, callback_args, text_document): - self.request(callback_args, - "textDocument/documentSymbol", - textDocument=text_document) - return - - def references( - self, - callback_args, - text_document, - position, - include_declaration): - self.request(callback_args, - "textDocument/references", - textDocument=text_document, - position=position, - includeDeclaration=include_declaration) - - def shutdown(self): - self.request("shutdown") - response = self.response_queue.get(True) - self.request("exit") - self.server.wait() - assert self.server.returncode == 0 - return response - - -# def __init__(self, binary_name, args, env, root_path, response_queue): -rls = LspClient( - '/home/tj/bin/langserver-go', - ['-trace', '-logfile', 'temp.log'], - None, - os.getcwd(), - Queue()) - - -print("First thing") -print("Response:") -response = rls.initialize() -print(response) -print('After response') -# print(json.dumps(response, indent=2)) - -# print("Notification:") -# response = rls.notification_queue.get(True) -# print(response) -# print(json.dumps(response, indent=2)) - -time.sleep(1) -count = 0 -while True: - any_non_empty = False - - # my_choice = input('Choice') - - # if my_choice == 'y': - print('sending my json') - if count == 0: - rls.request('textDocument/didOpen', **{ - "uri": "file://tests/test.go", - "version": 1, - "languageId": "go", - "text": """ -// In Go, _variables_ are explicitly declared and used by -// the compiler to e.g. check type-correctness of function -// calls. - -package main - -import "fmt" - -func main() { - - // `var` declares 1 or more variables. - var a string = "initial" - fmt.Println(a) - - // You can declare multiple variables at once. - var b, c int = 1, 2 - fmt.Println(b, c) - - // Go will infer the type of initialized variables. - var d = true - fmt.Println(d) - - // Variables declared without a corresponding - // initialization are _zero-valued_. For example, the - // zero value for an `int` is `0`. - var e int - fmt.Println(e) - - // The `:=` syntax is shorthand for declaring and - // initializing a variable, e.g. for - // `var f string = "short"` in this case. - f := "short" - fmt.Println(f) -} -} -"""}) - - count += 1 - elif count == 1: - rls.request('textDocument/definition', - **{'textDocument': - { - # "uri": "file://tests/test.go", - "uri": "file:///home/tj/.vim/plugged/nvim-langserver-shim/tests/test.go", - }, - 'position': - {'character': 16, 'line': 12}} - ) - - # rls.server.stdin.write(my_json) - # rls.server.stdin.flush() - - try: - response = rls.response_queue.get_nowait() - print("Response:") - print(json.dumps(response, indent=2)) - any_non_empty = True - except Empty: - pass - - try: - notification = rls.notification_queue.get_nowait() - print("Notification:") - print(json.dumps(notification, indent=2)) - any_non_empty = True - except Empty: - pass - - my_val = input() - - if my_val == 'q': - break - -print("Done")