From 12b5b81b132529aa0af84516e8faf5be84c201e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Sat, 22 Jun 2024 06:09:27 +0000 Subject: [PATCH] Complete existing sections within [ --- profiles/completions/sections.cfg | 2 ++ server/CHANGELOG.md | 10 ++++-- server/README.md | 2 +- server/buildoutls/buildout.py | 15 +++++++++ server/buildoutls/server.py | 12 ++++++- server/buildoutls/tests/test_completion.py | 39 +++++++++++++++++++++- 6 files changed, 74 insertions(+), 6 deletions(-) diff --git a/profiles/completions/sections.cfg b/profiles/completions/sections.cfg index 9e6cc27..b7cd502 100644 --- a/profiles/completions/sections.cfg +++ b/profiles/completions/sections.cfg @@ -12,3 +12,5 @@ option4 = value4 [xsection4] option5 = value5 option6 = ${s + +[] diff --git a/server/CHANGELOG.md b/server/CHANGELOG.md index 1c0d760..59075db 100644 --- a/server/CHANGELOG.md +++ b/server/CHANGELOG.md @@ -7,23 +7,27 @@ and this project adheres to [Semantic Versioning][semver]. ## Unreleased +### Added + + - completions: complete existing sections within `[` to override existing sections. + ## [0.12.0] - 2023-10-08 - support python 3.12 - version up dependencies -## Fixed +### Fixed - hover: fix crash when opening instance.cfg.in without opening a folder (by updating pygls) ## [0.11.0] - 2023-10-04 -## Added +### Added - code actions: support cancellation of md5sum command -## Fixed +### Fixed - hover: fix crash when opening instance.cfg.in outside of workspace folder diff --git a/server/README.md b/server/README.md index e328ed8..e6eeb8e 100644 --- a/server/README.md +++ b/server/README.md @@ -24,7 +24,7 @@ The automatic installation does not seem to work with theia and the python egg h ## Completions -- `${` complete sections. +- `${` or `[` complete sections. - `${section:` complete `section`'s options. If `section` uses a known recipe, dynamic options from the recipe are also completed. - `${buildout:extends}` completes filenames. - `${buildout:parts}` and `<=` option completes parts. diff --git a/server/buildoutls/buildout.py b/server/buildoutls/buildout.py index 8daa4d3..3bcc581 100644 --- a/server/buildoutls/buildout.py +++ b/server/buildoutls/buildout.py @@ -79,6 +79,12 @@ # Matches a comment comment_re = re.compile(r".*[#;].*") +# Matches a partial section definition like +# [s +# or +# [] +partial_section_header_re = re.compile(r"^\[(?P
[^\]]*)") + # Filenames of slapos instances, that might be a buildout profile as a buildout template slapos_instance_profile_filename_re = re.compile(r".*\/instance[^\/]*\.cfg[^\/]*") @@ -672,6 +678,7 @@ async def getSymbolAtPosition(self, position: Position) -> Optional[Symbol]: # have a leading space. # > value section_header_match = section_header(line) # reuse buildout's regexp + partial_section_header_match = partial_section_header_re.match(line) if section_header_match: return Symbol( kind=SymbolKind.SectionDefinition, @@ -679,6 +686,14 @@ async def getSymbolAtPosition(self, position: Position) -> Optional[Symbol]: value=section_header_match.group("name"), current_section_name=section_header_match.group("name"), ) + elif partial_section_header_match: + return Symbol( + kind=SymbolKind.SectionDefinition, + buildout=self, + value=partial_section_header_match.group("section"), + current_section_name=partial_section_header_match.group("section"), + ) + if option_value_definition_match: # Single line option and value. The position might be on option # or value diff --git a/server/buildoutls/server.py b/server/buildoutls/server.py index aee65c3..11e062e 100644 --- a/server/buildoutls/server.py +++ b/server/buildoutls/server.py @@ -346,7 +346,7 @@ def getDefaultTextEdit( if parsed is None: return None symbol = await parsed.getSymbolAtPosition(params.position) - logger.debug("getting completions on %s", symbol) + logger.debug("getting completions at %s => %s", params.position, symbol) if symbol: if symbol.kind == buildout.SymbolKind.Comment: return None @@ -594,6 +594,16 @@ def getDefaultTextEdit( ) ) + elif symbol.kind == buildout.SymbolKind.SectionDefinition: + for section_name in symbol._buildout: + items.append( + CompletionItem( + label=section_name, + text_edit=getDefaultTextEdit(doc, params.position, section_name), + kind=CompletionItemKind.Function, + ) + ) + return items diff --git a/server/buildoutls/tests/test_completion.py b/server/buildoutls/tests/test_completion.py index 2df19e6..976f19e 100644 --- a/server/buildoutls/tests/test_completion.py +++ b/server/buildoutls/tests/test_completion.py @@ -21,7 +21,7 @@ async def test_complete_section_reference(server: LanguageServer): context = CompletionContext( trigger_kind=CompletionTriggerKind.Invoked, ) - # complete section names + # complete section names in ${se|} params = CompletionParams( text_document=TextDocumentIdentifier(uri="file:///completions/sections.cfg"), position=Position(line=13, character=13), @@ -119,6 +119,43 @@ async def test_complete_section_reference(server: LanguageServer): option4 = value4 ```""") + # complete section names in [se|] + params = CompletionParams( + text_document=TextDocumentIdentifier(uri="file:///completions/sections.cfg"), + position=Position(line=15, character=1), + context=context, + ) + completions = await lsp_completion(server, params) + assert completions is not None + assert sorted( + [ + (c.text_edit.range, c.text_edit.new_text) + for c in completions + if isinstance(c.text_edit, TextEdit) + ] + ) == [ + ( + Range(start=Position(line=15, character=1), end=Position(line=15, character=1)), + "buildout", + ), + ( + Range(start=Position(line=15, character=1), end=Position(line=15, character=1)), + "section1", + ), + ( + Range(start=Position(line=15, character=1), end=Position(line=15, character=1)), + "section2", + ), + ( + Range(start=Position(line=15, character=1), end=Position(line=15, character=1)), + "section3", + ), + ( + Range(start=Position(line=15, character=1), end=Position(line=15, character=1)), + "xsection4", + ), + ] + # test completions from various positions where all sections are suggested for completion_position, textEditRange in ( (