From 3c171b9e25d3de75129f37716601bcf7b1efea3a Mon Sep 17 00:00:00 2001 From: Regen Date: Wed, 29 Apr 2020 17:56:09 +0900 Subject: [PATCH 1/4] Fix CompletionItem for vim-lsp --- src/cmake_language_server/server.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cmake_language_server/server.py b/src/cmake_language_server/server.py index 989c191..b588541 100644 --- a/src/cmake_language_server/server.py +++ b/src/cmake_language_server/server.py @@ -59,21 +59,21 @@ def completions(params: CompletionParams): items.extend( CompletionItem(x, CompletionItemKind.Function, - documentation=self._api.get_command_doc(x)) - for x in commands) + documentation=self._api.get_command_doc(x), + insert_text=x) for x in commands) if trigger is None or trigger == '{': variables = self._api.search_variable(token) items.extend( CompletionItem(x, CompletionItemKind.Variable, - documentation=self._api.get_variable_doc(x)) - for x in variables) + documentation=self._api.get_variable_doc(x), + insert_text=x) for x in variables) if trigger is None: targets = self._api.search_target(token) items.extend( - CompletionItem(x, CompletionItemKind.Class) + CompletionItem(x, CompletionItemKind.Class, insert_text=x) for x in targets) if trigger == '(': @@ -87,16 +87,16 @@ def completions(params: CompletionParams): CompletionItem(x, CompletionItemKind.Module, documentation=self._api. - get_module_doc(x, False)) - for x in modules) + get_module_doc(x, False), + insert_text=x) for x in modules) elif func == 'find_package': modules = self._api.search_module(token, True) items.extend( CompletionItem(x, CompletionItemKind.Module, documentation=self._api. - get_module_doc(x, True)) - for x in modules) + get_module_doc(x, True), + insert_text=x) for x in modules) return CompletionList(False, items) From 67aced6544f92f709d2a86f501585bfdd8de3759 Mon Sep 17 00:00:00 2001 From: Regen Date: Wed, 29 Apr 2020 18:04:23 +0900 Subject: [PATCH 2/4] Add encoding --- src/cmake_language_server/api.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cmake_language_server/api.py b/src/cmake_language_server/api.py index cf4659c..73ea390 100644 --- a/src/cmake_language_server/api.py +++ b/src/cmake_language_server/api.py @@ -60,9 +60,10 @@ def query(self) -> bool: }''') proc = subprocess.run([self._cmake, str(self._build)], - universal_newlines=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + encoding='utf-8', + universal_newlines=True) self.query_json.unlink() self.query_json.parent.rmdir() if proc.returncode != 0: @@ -144,10 +145,11 @@ def _read_cmake_files(self, jsonpath: Path): ''') p = subprocess.run( [self._cmake, '-P', str(tmplist)], - cwd=cmake_files['paths']['source'], - universal_newlines=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + cwd=cmake_files['paths']['source'], + encoding='utf-8', + universal_newlines=True) if p.returncode != 0: return @@ -190,6 +192,7 @@ def parse_doc(self) -> None: def _parse_commands(self) -> None: p = subprocess.run([self._cmake, '--help-commands'], stdout=subprocess.PIPE, + encoding='utf-8', universal_newlines=True) if p.returncode != 0: @@ -213,6 +216,7 @@ def _parse_commands(self) -> None: def _parse_variables(self) -> None: p = subprocess.run([self._cmake, '--help-variables'], stdout=subprocess.PIPE, + encoding='utf-8', universal_newlines=True) if p.returncode != 0: @@ -241,6 +245,7 @@ def _parse_variables(self) -> None: def _parse_modules(self) -> None: p = subprocess.run([self._cmake, '--help-modules'], stdout=subprocess.PIPE, + encoding='utf-8', universal_newlines=True) if p.returncode != 0: From 2d36887b2670b0d46e4dddbed6b4c35af74af02b Mon Sep 17 00:00:00 2001 From: Regen Date: Wed, 29 Apr 2020 19:25:51 +0900 Subject: [PATCH 3/4] Support no TriggerCharacter --- src/cmake_language_server/server.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/cmake_language_server/server.py b/src/cmake_language_server/server.py index b588541..e8b6309 100644 --- a/src/cmake_language_server/server.py +++ b/src/cmake_language_server/server.py @@ -40,17 +40,26 @@ def initialize(params: InitializeParams): self._api = API(cmake, Path(builddir)) self._api.parse_doc() - @self.feature(COMPLETION, trigger_characters=['{', '(']) + trigger_characters = ['{', '('] + + @self.feature(COMPLETION, trigger_characters=trigger_characters) def completions(params: CompletionParams): if (hasattr(params, 'context') and params.context.triggerKind == CompletionTriggerKind.TriggerCharacter): token = '' trigger = params.context.triggerCharacter else: - word = self._cursor_word(params.textDocument.uri, - params.position, False) - token = '' if word is None else word[0] - trigger = None + line = self._cursor_line(params.textDocument.uri, + params.position) + idx = params.position.character - 1 + if 0 <= idx < len(line) and line[idx] in trigger_characters: + token = '' + trigger = line[idx] + else: + word = self._cursor_word(params.textDocument.uri, + params.position, False) + token = '' if word is None else word[0] + trigger = None items: List[CompletionItem] = [] From e07b3242c8e99d285f3cfe12c314c87be8405f99 Mon Sep 17 00:00:00 2001 From: Regen Date: Wed, 29 Apr 2020 22:57:43 +0900 Subject: [PATCH 4/4] Add test --- tests/test_server.py | 91 +++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/tests/test_server.py b/tests/test_server.py index fb91545..c0777f5 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -40,6 +40,21 @@ def _open(client: LanguageServer, path: Path, text: Optional[str] = None): TextDocumentItem(path.as_uri(), 'cmake', 1, text))) +def _test_completion(client_server, datadir, content: str, + context: Optional[CompletionContext]): + client, server = client_server + _init(client, datadir) + path = datadir / 'CMakeLists.txt' + _open(client, path, content) + params = CompletionParams(TextDocumentIdentifier(path.as_uri()), + Position(0, len(content)), context) + if context is None: + # some clients do not send context + del params.context + return client.lsp.send_request(COMPLETION, + params).result(timeout=CALL_TIMEOUT) + + def test_initialize(client_server, datadir): client, server = client_server @@ -49,78 +64,52 @@ def test_initialize(client_server, datadir): def test_completions_invoked(client_server, datadir): - client, server = client_server - _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'projec') - response = client.lsp.send_request( - COMPLETION, - CompletionParams(TextDocumentIdentifier(path.as_uri()), Position( - 0, 6), CompletionContext( - CompletionTriggerKind.Invoked))).result(timeout=CALL_TIMEOUT) + response = _test_completion( + client_server, datadir, 'projec', + CompletionContext(CompletionTriggerKind.Invoked)) item = next(filter(lambda x: x.label == 'project', response.items), None) assert item is not None assert '' in item.documentation -def test_completions_no_context(client_server, datadir): - client, server = client_server - _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'projec') - params = CompletionParams(TextDocumentIdentifier(path.as_uri()), - Position(0, 6), - CompletionContext(CompletionTriggerKind.Invoked)) - # some clients do not send context - del params.context - response = client.lsp.send_request(COMPLETION, - params).result(timeout=CALL_TIMEOUT) +def test_completions_nocontext(client_server, datadir): + response = _test_completion(client_server, datadir, 'projec', None) item = next(filter(lambda x: x.label == 'project', response.items), None) assert item is not None assert '' in item.documentation def test_completions_triggercharacter_variable(client_server, datadir): - client, server = client_server - _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, '${') - response = client.lsp.send_request( - COMPLETION, - CompletionParams( - TextDocumentIdentifier(path.as_uri()), Position(0, 2), - CompletionContext(CompletionTriggerKind.TriggerCharacter, - '{'))).result(timeout=CALL_TIMEOUT) + response = _test_completion( + client_server, datadir, '${', + CompletionContext(CompletionTriggerKind.TriggerCharacter, '{')) assert 'PROJECT_VERSION' in [x.label for x in response.items] + response_nocontext = _test_completion(client_server, datadir, '${', None) + assert response == response_nocontext + def test_completions_triggercharacter_module(client_server, datadir): - client, server = client_server - _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'include(') - response = client.lsp.send_request( - COMPLETION, - CompletionParams( - TextDocumentIdentifier(path.as_uri()), Position(0, 8), - CompletionContext(CompletionTriggerKind.TriggerCharacter, - '('))).result(timeout=CALL_TIMEOUT) + response = _test_completion( + client_server, datadir, 'include(', + CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) assert 'GoogleTest' in [x.label for x in response.items] + response_nocontext = _test_completion(client_server, datadir, 'include(', + None) + assert response == response_nocontext + def test_completions_triggercharacter_package(client_server, datadir): - client, server = client_server - _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'find_package(') - response = client.lsp.send_request( - COMPLETION, - CompletionParams( - TextDocumentIdentifier(path.as_uri()), Position(0, 13), - CompletionContext(CompletionTriggerKind.TriggerCharacter, - '('))).result(timeout=CALL_TIMEOUT) + response = _test_completion( + client_server, datadir, 'find_package(', + CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) assert 'Boost' in [x.label for x in response.items] + response_nocontext = _test_completion(client_server, datadir, + 'find_package(', None) + assert response == response_nocontext + def test_formatting(client_server, datadir): client, server = client_server