feat(lsp): support completion item resolve to show .def previews
Enable completion item resolution so selecting a completion can populate
documentation with a preview of the corresponding .def declaration.
- Turn on resolve_provider in the completion options.
- Implement on_completion_resolve to attach Markdown documentation
computed by def_hover_markdown when the completion item's data
contains a ("def" -> [kind, name]) payload.
- Include that "def" payload when generating def-related completion items.
- Add tests that verify block-template and address-list items resolve to
Markdown previews.
Before: def-related completion items had no documentation on resolve.
After: selecting such items will return a Markdown preview of the .def entry.
This commit is contained in:
@@ -287,7 +287,7 @@ def document_diagnostic(params: lsp.DocumentDiagnosticParams):
|
|||||||
|
|
||||||
@LSP_SERVER.feature(
|
@LSP_SERVER.feature(
|
||||||
lsp.TEXT_DOCUMENT_COMPLETION,
|
lsp.TEXT_DOCUMENT_COMPLETION,
|
||||||
lsp.CompletionOptions(trigger_characters=["$", " ", "-", "(", ","]),
|
lsp.CompletionOptions(trigger_characters=["$", " ", "-", "(", ","], resolve_provider=True),
|
||||||
)
|
)
|
||||||
def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
|
def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
|
||||||
result = _on_completion(params)
|
result = _on_completion(params)
|
||||||
@@ -300,6 +300,17 @@ def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@LSP_SERVER.feature(lsp.COMPLETION_ITEM_RESOLVE)
|
||||||
|
def on_completion_resolve(item: lsp.CompletionItem) -> lsp.CompletionItem:
|
||||||
|
"""Show the .def declaration of a selected block template/address, as on hover."""
|
||||||
|
target = item.data.get("def") if isinstance(item.data, dict) else None
|
||||||
|
if item.documentation is None and isinstance(target, list) and len(target) == 2:
|
||||||
|
markdown = def_hover_markdown(LSP_SERVER.def_documents_snapshot(), tuple(target))
|
||||||
|
if markdown:
|
||||||
|
item.documentation = lsp.MarkupContent(kind=lsp.MarkupKind.Markdown, value=markdown)
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
# Keywords that expand to all loaded .def names: keyword -> (items, description).
|
# Keywords that expand to all loaded .def names: keyword -> (items, description).
|
||||||
SYMBOL_LIST_KEYWORDS = {
|
SYMBOL_LIST_KEYWORDS = {
|
||||||
"BLOCK_LIST": (lambda: LSP_SERVER.block_template_items(), "block templates"),
|
"BLOCK_LIST": (lambda: LSP_SERVER.block_template_items(), "block templates"),
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ class TclLanguageServer(LanguageServer):
|
|||||||
label=name,
|
label=name,
|
||||||
kind=item_kind,
|
kind=item_kind,
|
||||||
detail=f"{description} ({pathlib.Path(path).name})",
|
detail=f"{description} ({pathlib.Path(path).name})",
|
||||||
|
data={"def": [kind, name]},
|
||||||
)
|
)
|
||||||
for path, document in self.def_documents_snapshot().items()
|
for path, document in self.def_documents_snapshot().items()
|
||||||
for name in document.names(kind)
|
for name in document.names(kind)
|
||||||
|
|||||||
@@ -227,6 +227,25 @@ def test_block_list_shows_all_templates_quoted(tmp_path, monkeypatch):
|
|||||||
assert all(item.filter_text.startswith("BLOCK_LIST") for item in items)
|
assert all(item.filter_text.startswith("BLOCK_LIST") for item in items)
|
||||||
|
|
||||||
|
|
||||||
|
def test_block_list_item_resolves_to_template_preview(tmp_path, monkeypatch):
|
||||||
|
server, _ = _project(tmp_path, monkeypatch)
|
||||||
|
items = _complete(server, tmp_path, "set a 1\n BLOCK_LIST")
|
||||||
|
assert all(item.documentation is None for item in items)
|
||||||
|
item = next(item for item in items if item.label == "steady_rest")
|
||||||
|
resolved = lsp_server.on_completion_resolve(item)
|
||||||
|
assert resolved.documentation.kind == lsp.MarkupKind.Markdown
|
||||||
|
assert "**Block template** `steady_rest`" in resolved.documentation.value
|
||||||
|
assert "Text[M60]" in resolved.documentation.value
|
||||||
|
|
||||||
|
|
||||||
|
def test_address_list_item_resolves_to_address_table(tmp_path, monkeypatch):
|
||||||
|
server, _ = _project(tmp_path, monkeypatch)
|
||||||
|
items = _complete(server, tmp_path, "set a 1\n ADDR_LIST")
|
||||||
|
item = next(item for item in items if item.label == "SPOS")
|
||||||
|
resolved = lsp_server.on_completion_resolve(item)
|
||||||
|
assert "| Format | `Coordinate` |" in resolved.documentation.value
|
||||||
|
|
||||||
|
|
||||||
def test_block_list_ignores_variables_and_other_words(tmp_path, monkeypatch):
|
def test_block_list_ignores_variables_and_other_words(tmp_path, monkeypatch):
|
||||||
server, _ = _project(tmp_path, monkeypatch)
|
server, _ = _project(tmp_path, monkeypatch)
|
||||||
for source in ("set x $BLOCK_LIST", "set x MY_BLOCK_LIST", "set x steady"):
|
for source in ("set x $BLOCK_LIST", "set x MY_BLOCK_LIST", "set x steady"):
|
||||||
|
|||||||
Reference in New Issue
Block a user