feat: complete BLOCK_LIST/ADDR_LIST keywords and space comments
Add keyword-driven completions for BLOCK_LIST and ADDR_LIST in the LSP server. - While typing a prefix of these keywords the server returns the keyword(s) as incomplete snippet suggestions that trigger a re-request. - Once the keyword is typed the server replaces it with a full list of the corresponding loaded block templates or addresses (quoted), and sets each item's filter_text to include the keyword so further typing narrows results. - Integrate this flow into on_completion and factor the symbol-list logic into a helper that returns either incomplete keyword suggestions or the completed symbol list. Also implement NxFormatter.format_comment to ensure a single space after a leading '#' for comments that don't already start with whitespace, while leaving sequences of '#' (separators), shebangs, and already-spaced comments unchanged. This affects both standalone and inline comments. Add/rename tests to cover the new completions and comment-spacing behavior.
This commit is contained in:
@@ -198,3 +198,63 @@ def test_typed_quotes_are_replaced_not_doubled(tmp_path, monkeypatch):
|
||||
)
|
||||
).items
|
||||
assert _edit(items, "SPOS") == ('"SPOS"', (22, 26))
|
||||
|
||||
|
||||
def test_block_list_prefix_offers_keyword_and_stays_incomplete(tmp_path, monkeypatch):
|
||||
server, _ = _project(tmp_path, monkeypatch)
|
||||
uri = (tmp_path / "caller.tcl").as_uri()
|
||||
source = "MOM_do_template BLOCK_L"
|
||||
server.workspace.put_text_document(
|
||||
lsp.TextDocumentItem(uri=uri, language_id="tcl", version=next(_versions), text=source)
|
||||
)
|
||||
result = lsp_server.on_completion(
|
||||
lsp.CompletionParams(
|
||||
text_document=lsp.TextDocumentIdentifier(uri=uri),
|
||||
position=lsp.Position(line=0, character=len(source)),
|
||||
)
|
||||
)
|
||||
assert result.is_incomplete
|
||||
keyword = result.items[0]
|
||||
assert keyword.label == "BLOCK_LIST"
|
||||
assert keyword.command.command == "editor.action.triggerSuggest"
|
||||
|
||||
|
||||
def test_block_list_shows_all_templates_quoted(tmp_path, monkeypatch):
|
||||
server, _ = _project(tmp_path, monkeypatch)
|
||||
items = _complete(server, tmp_path, "set a 1\n BLOCK_LIST")
|
||||
assert [item.label for item in items] == ["external_subprogram", "steady_rest"]
|
||||
assert _edit(items, "steady_rest") == ('"steady_rest"', (4, 14))
|
||||
assert all(item.filter_text.startswith("BLOCK_LIST") for item in items)
|
||||
|
||||
|
||||
def test_block_list_ignores_variables_and_other_words(tmp_path, monkeypatch):
|
||||
server, _ = _project(tmp_path, monkeypatch)
|
||||
for source in ("set x $BLOCK_LIST", "set x MY_BLOCK_LIST", "set x steady"):
|
||||
labels = [item.label for item in _complete(server, tmp_path, source)]
|
||||
assert "BLOCK_LIST" not in labels
|
||||
|
||||
|
||||
def test_addr_list_shows_all_addresses_quoted(tmp_path, monkeypatch):
|
||||
server, _ = _project(tmp_path, monkeypatch)
|
||||
items = _complete(server, tmp_path, "MOM_force Once ADDR_LIST")
|
||||
assert [item.label for item in items] == ["SPOS", "X"]
|
||||
assert _edit(items, "SPOS") == ('"SPOS"', (15, 24))
|
||||
assert all(item.filter_text.startswith("ADDR_LIST") for item in items)
|
||||
|
||||
|
||||
def test_addr_list_prefix_offers_keyword(tmp_path, monkeypatch):
|
||||
server, _ = _project(tmp_path, monkeypatch)
|
||||
uri = (tmp_path / "caller.tcl").as_uri()
|
||||
source = "ADDR"
|
||||
server.workspace.put_text_document(
|
||||
lsp.TextDocumentItem(uri=uri, language_id="tcl", version=next(_versions), text=source)
|
||||
)
|
||||
result = lsp_server.on_completion(
|
||||
lsp.CompletionParams(
|
||||
text_document=lsp.TextDocumentIdentifier(uri=uri),
|
||||
position=lsp.Position(line=0, character=len(source)),
|
||||
)
|
||||
)
|
||||
assert result.is_incomplete
|
||||
assert result.items[0].label == "ADDR_LIST"
|
||||
assert "BLOCK_LIST" not in {item.label for item in result.items}
|
||||
|
||||
+26
-1
@@ -1,4 +1,4 @@
|
||||
"""Formatting of uplevel bodies."""
|
||||
"""Formatting with NxFormatter."""
|
||||
|
||||
from tclint.format import FormatterOpts
|
||||
from tools.formatter import NxFormatter
|
||||
@@ -31,3 +31,28 @@ def test_uplevel_without_level_and_with_variable_level():
|
||||
assert _format(source) == (
|
||||
"uplevel {\n\tset x 1\n}\nuplevel $lvl {\n\tset y 2\n}\nuplevel set z 3\n"
|
||||
)
|
||||
|
||||
|
||||
def test_comment_gets_space_after_hash():
|
||||
source = (
|
||||
"#Comment\n"
|
||||
"# already spaced\n"
|
||||
"#\tTabbed\n"
|
||||
"#\n"
|
||||
"##########\n"
|
||||
"set x 1 ;#inline\n"
|
||||
"proc a {} {\n"
|
||||
"\t#nested\n"
|
||||
"}\n"
|
||||
)
|
||||
assert _format(source) == (
|
||||
"# Comment\n"
|
||||
"# already spaced\n"
|
||||
"#\tTabbed\n"
|
||||
"#\n"
|
||||
"##########\n"
|
||||
"set x 1 ;# inline\n"
|
||||
"proc a {} {\n"
|
||||
"\t# nested\n"
|
||||
"}\n"
|
||||
)
|
||||
Reference in New Issue
Block a user