feat(tcl): add static variable name extraction and array key completion
This adds tooling to statically extract Tcl variable names from syntax trees without evaluating substitutions, enabling better completions for array elements and plain variables. The new helpers are wired into the completion and navigation flows and are supported by tests covering array keys and substitutions. - Introduce variable_names.py with variable_name() and array_key_parts() - Wire static name extraction into completion and symbol indexing - Add tests for array key completion with substitutions
This commit is contained in:
@@ -4,7 +4,8 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
import lsprotocol.types as lsp
|
||||
from tclint.syntax_tree import Command, List, Node, Script, VarSub
|
||||
from tclint.syntax_tree import Command, List, Node, QuotedWord, Script, VarSub
|
||||
from tools.variable_names import array_key_parts, variable_name
|
||||
|
||||
ROOT_NAMESPACE = "::"
|
||||
|
||||
@@ -27,6 +28,9 @@ class SymbolOccurrence:
|
||||
fallback_identity: SymbolIdentity | None = None
|
||||
caller: SymbolIdentity | None = None
|
||||
declaration_range: lsp.Range | None = None
|
||||
array_element: str | None = None
|
||||
array_parts: tuple[str | None, ...] = ()
|
||||
array_template_parts: tuple[str | None, ...] = ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -96,6 +100,8 @@ def _name_range(node: Node, raw_name: str, *, variable_sub: bool = False) -> lsp
|
||||
column += 2 if getattr(node, "braced", False) else 1
|
||||
else:
|
||||
position = getattr(node, "contents_pos", None) or node.pos
|
||||
if isinstance(node, QuotedWord) and node.contents is None and node.children:
|
||||
position = node.children[0].pos
|
||||
line, column = position
|
||||
|
||||
normalized = _without_array_index(raw_name)
|
||||
@@ -312,6 +318,13 @@ def build_file_symbol_index(
|
||||
is_definition=is_definition,
|
||||
symbol_kind=lsp.SymbolKind.Variable,
|
||||
container_name=_container_name(symbol_identity),
|
||||
array_element=(
|
||||
raw_name.split("(", 1)[1][:-1]
|
||||
if "(" in raw_name and raw_name.endswith(")")
|
||||
else None
|
||||
),
|
||||
array_parts=array_key_parts(node),
|
||||
array_template_parts=array_key_parts(node, preserve_variables=True),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -444,7 +457,7 @@ def build_file_symbol_index(
|
||||
for node, is_definition in _variable_command_nodes(command):
|
||||
if id(node) in declaration_ids:
|
||||
continue
|
||||
raw_name = _static_contents(node)
|
||||
raw_name = variable_name(node)
|
||||
if raw_name:
|
||||
add_variable(
|
||||
node,
|
||||
|
||||
Reference in New Issue
Block a user