From abf32a5e500540cb79b94bbca137e231094d3144 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Thu, 24 Sep 2026 07:53:15 +0200 Subject: [PATCH] feat(server/lsp_tclserver): index .def symbols and provide completion items --- server/src/lsp_tclserver.py | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/server/src/lsp_tclserver.py b/server/src/lsp_tclserver.py index 1241433..81bd5a8 100644 --- a/server/src/lsp_tclserver.py +++ b/server/src/lsp_tclserver.py @@ -18,7 +18,8 @@ from tools import checks, incremental_parse, parser from tools.completion_items import CompletionCollector from tools.tcloo_symbols import class_completion_items from tools.tcloo_completion import indexed_classes -from tools.file_sourcing import get_all_psc_files, psc_script_files +from tools.def_symbols import DefSymbols, read_def_symbols +from tools.file_sourcing import get_all_psc_files, psc_defined_event_files, psc_script_files from tools.formatter import NxFormatter as Formatter from tools.index_cache import FileStat, IndexCache, file_stat from tools.inlay_hint import InlayHintSignature, build_custom_inlay_signatures @@ -61,6 +62,8 @@ class TclLanguageServer(LanguageServer): self.psc_script_paths: list[str] = [] self._psc_files: dict[str, list[pathlib.Path]] = {} self._psc_lock = threading.RLock() + # .def path -> BLOCK_TEMPLATE/ADDRESS names, in PSC DefinedEvents order. + self.def_symbols: dict[str, DefSymbols] = {} self.navigation_indexes: dict[str, FileSymbolIndex] = {} self.variable_indexes: dict[ str, @@ -252,8 +255,48 @@ class TclLanguageServer(LanguageServer): classes.update(indexes.get(self._normalized_path(path), {})) return classes + def refresh_def_symbols(self, roots, report=LOGGER.warning): + """Read the block templates and addresses of all .def files listed as PSC DefinedEvents.""" + symbols: dict[str, DefSymbols] = {} + for root in roots: + for psc in get_all_psc_files(root): + try: + def_files = psc_defined_event_files(psc) + except (OSError, ET.ParseError) as error: + report(f"Could not read PSC {psc}: {error}") + continue + for def_file in def_files: + if str(def_file) in symbols: + continue + try: + symbols[str(def_file)] = read_def_symbols(def_file) + except OSError as error: + report(f"Could not read DEF file {def_file}: {error}") + with self._index_lock: + self.def_symbols = symbols + + def _def_symbol_items(self, attribute: str, kind, description: str) -> list[lsp.CompletionItem]: + with self._index_lock: + symbols = dict(self.def_symbols) + return [ + lsp.CompletionItem( + label=name, + kind=kind, + detail=f"{description} ({pathlib.Path(path).name})", + ) + for path, def_symbols in symbols.items() + for name in getattr(def_symbols, attribute) + ] + + def block_template_items(self) -> list[lsp.CompletionItem]: + return self._def_symbol_items("block_templates", lsp.CompletionItemKind.Struct, "Block template") + + def address_items(self) -> list[lsp.CompletionItem]: + return self._def_symbol_items("addresses", lsp.CompletionItemKind.Field, "Address") + def refresh_psc_scripts(self, roots, report=LOGGER.warning): """Index PSC dependencies through the same pipeline as workspace procs.""" + self.refresh_def_symbols(roots, report=report) with self._psc_lock: discovered = {} for root in roots: