add outline to lsp

This commit is contained in:
Christoph Brandau
2025-08-11 18:28:23 +02:00
parent b3cac5c292
commit 0a26cb5c0f
3 changed files with 297 additions and 6 deletions
@@ -0,0 +1,115 @@
import sys
from pathlib import Path
THIS_DIR = Path(__file__).parent
SRC_DIR = THIS_DIR.parent.parent / "src"
if str(SRC_DIR) not in sys.path:
sys.path.insert(0, str(SRC_DIR))
import lsprotocol.types as lsp # type: ignore
from lsp_server import LSP_SERVER, document_symbols # type: ignore
def test_document_symbols_namespace_proc_set_hierarchy(tmp_path: Path):
source_lines = [
"set top_var 1",
"namespace eval myns {",
" set ns_var 2",
" proc add {a b} {",
" set sum [expr {$a + $b}]",
" return $sum",
" }",
"}",
"proc top_proc {} {",
" set x 3",
"}",
]
source = "\n".join(source_lines)
uri = Path(tmp_path / "sym.tcl").as_uri()
# Put a text document into the workspace
LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
# Request document symbols
params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
symbols = document_symbols(params)
# Expect at least 2 top-level children: root contains 'set top_var' (variable) and 'namespace myns' and 'proc top_proc'
names_kinds = {(s.name, s.kind) for s in symbols}
assert ("root", lsp.SymbolKind.Namespace) not in names_kinds # root should not be included itself
# Find namespace symbol
ns = next(s for s in symbols if s.name == "myns")
assert ns.kind == lsp.SymbolKind.Namespace
assert ns.children is not None
# Inside namespace: has variable and proc
child_names = {c.name for c in ns.children}
assert "ns_var" in child_names
assert "add" in child_names
# top-level variable and proc also present
top_names = {s.name for s in symbols}
assert "top_var" in top_names
assert "top_proc" in top_names
# Check that proc add has no children (we're not extracting params as children here)
add = next(c for c in ns.children if c.name == "add")
assert add.kind == lsp.SymbolKind.Function
assert add.children == []
def test_buffer_edit_events_are_symbols_with_type_and_name(tmp_path: Path):
source_lines = [
"LIB_GE_command_buffer_edit_insert LIB_ROTARY_positioning_first_move_pos ROTARY_POSITIONING_FIRST_MOVE_POS {",
" MOM_enable_address Z M_coolant_off D M_coolant_1 M_coolant_2 H_pressure",
"}",
" Coolant after @DECOMPOSEZUL",
"",
"LIB_GE_command_buffer_edit_append MOM_start_of_path_LIB MOM_start_of_path_LIB_ENTRY_end {",
" MOM_force once M_coolant_1 M_coolant_2 H_pressure",
"}",
" force_coolant",
]
source = "\n".join(source_lines)
uri = Path(tmp_path / "events.tcl").as_uri()
LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
symbols = document_symbols(params)
# Find event symbols
events = [s for s in symbols if s.kind == lsp.SymbolKind.Event]
assert events, "Expected at least one event symbol"
# Verify names and details
names = [e.name for e in events]
assert "Coolant" in names or "force_coolant" in names
for e in events:
assert e.detail.startswith("Event (")
def test_event_children_include_set_variable(tmp_path: Path):
source_lines = [
"LIB_GE_command_buffer_edit_append MOM_rapid_move_LIB MOM_rapid_move_LIB_ENTRY_start {",
" if {[info exists ::mom_lift_off_output] && $::kapp_vars(retract_start) == 0} {",
" kapp_retract_subpgm",
" }",
" set ::kapp_vars(retract_start) 0",
"}",
" KappRetractSubPgm",
]
source = "\n".join(source_lines)
uri = Path(tmp_path / "event_children.tcl").as_uri()
LSP_SERVER.workspace.put_text_document(lsp.TextDocumentItem(uri=uri, language_id="tcl", version=1, text=source))
params = lsp.DocumentSymbolParams(text_document=lsp.TextDocumentIdentifier(uri=uri))
symbols = document_symbols(params)
events = [s for s in symbols if s.kind == lsp.SymbolKind.Event and s.name == "KappRetractSubPgm"]
assert events, "Expected event symbol for KappRetractSubPgm"
ev = events[0]
assert ev.children is not None
# Ensure the set variable is a child of the event
child_names = {c.name for c in ev.children}
assert "::kapp_vars(retract_start)" in child_names