update
This commit is contained in:
@@ -55,6 +55,8 @@ from plugins.poco_plugin import commands
|
||||
from tools import checks, parser
|
||||
from tools.semantic_tokens import _Highlighter, TOKEN_TYPES, TokenModifier
|
||||
from tools.completion_items import completion
|
||||
from tools.inlay_hint import InlayHintGenerator
|
||||
from tools.symbols import OutlineVisitor
|
||||
|
||||
DIAGNOSTIC_SOURCE = "nx-post-support"
|
||||
|
||||
@@ -259,6 +261,29 @@ def on_completion(params: lsp.CompletionParams) -> list[lsp.CompletionItem]:
|
||||
return lsp.CompletionList(is_incomplete=False, items=items)
|
||||
|
||||
|
||||
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
|
||||
def document_symbols(params: lsp.DocumentSymbolParams):
|
||||
doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
|
||||
tree = LSP_SERVER.parser.parse(doc.source)
|
||||
|
||||
visitor = OutlineVisitor(LSP_SERVER.parser)
|
||||
tree.accept(visitor, recurse=True)
|
||||
|
||||
return visitor.stack[0]
|
||||
|
||||
|
||||
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_INLAY_HINT)
|
||||
def inlay_hints(params: lsp.InlayHintParams):
|
||||
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
|
||||
tree = LSP_SERVER.parser.parse(document.source)
|
||||
|
||||
# Inlay Hints sammeln
|
||||
generator = InlayHintGenerator(completion.proc_signatures)
|
||||
tree.accept(generator, recurse=True)
|
||||
|
||||
return generator.hints
|
||||
|
||||
|
||||
@LSP_SERVER.feature(
|
||||
lsp.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
||||
lsp.SemanticTokensLegend(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tclint.syntax_tree import Visitor
|
||||
from tclint.syntax_tree import Visitor, Command, BareWord, List
|
||||
import lsprotocol.types as lsp
|
||||
|
||||
|
||||
@@ -19,15 +19,21 @@ class _Completion(Visitor):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._custom_functions: list[lsp.CompletionItem] = []
|
||||
self._proc_signatures = {}
|
||||
|
||||
@property
|
||||
def custom_functions(self) -> list[lsp.CompletionItem]:
|
||||
return self._custom_functions
|
||||
|
||||
@property
|
||||
def proc_signatures(self):
|
||||
return self._proc_signatures
|
||||
|
||||
def reset(self):
|
||||
self._custom_functions = []
|
||||
self._proc_signatures = {}
|
||||
|
||||
def visit_command(self, command):
|
||||
def visit_command(self, command: Command):
|
||||
routine = command.routine
|
||||
|
||||
if routine.contents == "proc" and command.args:
|
||||
@@ -40,6 +46,23 @@ class _Completion(Visitor):
|
||||
label=first_arg.value, kind=lsp.CompletionItemKind.Function
|
||||
)
|
||||
)
|
||||
if len(command.args) < 2:
|
||||
return
|
||||
|
||||
param_list_node = command.args[1]
|
||||
if not hasattr(param_list_node, "children"):
|
||||
return
|
||||
|
||||
param_names = []
|
||||
for arg in param_list_node.children:
|
||||
if isinstance(arg, BareWord):
|
||||
param_names.append(arg.value)
|
||||
elif isinstance(arg, List) and len(arg.children) >= 1:
|
||||
first = arg.children[0]
|
||||
if isinstance(first, BareWord):
|
||||
param_names.append(first.value)
|
||||
|
||||
self._proc_signatures[first_arg.value] = param_names
|
||||
|
||||
|
||||
completion = _Completion()
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import lsprotocol.types as lsp
|
||||
from tclint.syntax_tree import Visitor, Command
|
||||
|
||||
|
||||
class InlayHintGenerator(Visitor):
|
||||
def __init__(self, proc_signatures):
|
||||
self.proc_signatures = proc_signatures
|
||||
self.hints = []
|
||||
|
||||
def visit_command(self, command: Command):
|
||||
name = getattr(command.routine, "contents", None)
|
||||
if name not in self.proc_signatures:
|
||||
return
|
||||
|
||||
param_names = self.proc_signatures[name]
|
||||
for idx, arg in enumerate(command.args):
|
||||
if idx >= len(param_names):
|
||||
break
|
||||
param_name = param_names[idx]
|
||||
|
||||
if arg.pos:
|
||||
line, col = arg.pos
|
||||
self.hints.append(
|
||||
lsp.InlayHint(
|
||||
position=lsp.Position(line=line - 1, character=col - 1),
|
||||
label=f"{param_name}:",
|
||||
kind=lsp.InlayHintKind.Parameter,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
from tclint.syntax_tree import Visitor, BareWord, BracedWord, Script, Command
|
||||
from tclint.parser import Parser
|
||||
import lsprotocol.types as lsp
|
||||
|
||||
|
||||
class OutlineVisitor(Visitor):
|
||||
def __init__(self, parser: Parser):
|
||||
self.parser = parser
|
||||
self.stack = [[]] # Root symbol list
|
||||
|
||||
def _range(self, node) -> lsp.Range:
|
||||
line = node.line - 1
|
||||
col = node.col - 1
|
||||
if node.end_pos:
|
||||
end_line = node.end_pos[0] - 1
|
||||
end_col = node.end_pos[1] - 1
|
||||
else:
|
||||
end_line = line
|
||||
end_col = col + 1
|
||||
|
||||
return lsp.Range(
|
||||
start=lsp.Position(line=line, character=col),
|
||||
end=lsp.Position(line=end_line, character=end_col),
|
||||
)
|
||||
|
||||
def _add(self, name: str, kind: lsp.SymbolKind, node, children=None):
|
||||
symbol = lsp.DocumentSymbol(
|
||||
name=name,
|
||||
kind=kind,
|
||||
range=self._range(node),
|
||||
selection_range=self._range(node),
|
||||
children=children or [],
|
||||
)
|
||||
self.stack[-1].append(symbol)
|
||||
return symbol
|
||||
|
||||
def visit_script(self, script):
|
||||
for child in script.children:
|
||||
child.accept(self, recurse=False)
|
||||
|
||||
def visit_command(self, command: Command):
|
||||
if not isinstance(command.routine, BareWord):
|
||||
return
|
||||
name = command.routine.contents
|
||||
|
||||
# --- NAMESPACE EVAL ---
|
||||
if name == "namespace" and len(command.args) >= 3:
|
||||
subcmd = command.args[0]
|
||||
if isinstance(subcmd, BareWord) and subcmd.contents == "eval":
|
||||
ns_arg = command.args[1]
|
||||
ns_name = (
|
||||
ns_arg.contents if isinstance(ns_arg, BareWord) else "<namespace>"
|
||||
)
|
||||
ns_body = command.args[2]
|
||||
|
||||
ns_symbol = self._add(
|
||||
ns_name, lsp.SymbolKind.Namespace, command, children=[]
|
||||
)
|
||||
self.stack.append(ns_symbol.children)
|
||||
|
||||
if isinstance(ns_body, BracedWord):
|
||||
try:
|
||||
subtree = self.parser.parse_script(ns_body)
|
||||
subtree.accept(self, recurse=False)
|
||||
except Exception as e:
|
||||
print(f"Failed parsing namespace body: {e}")
|
||||
|
||||
self.stack.pop()
|
||||
|
||||
# --- PROC ---
|
||||
elif name == "proc" and len(command.args) >= 1:
|
||||
proc_arg = command.args[0]
|
||||
proc_name = (
|
||||
proc_arg.contents if isinstance(proc_arg, BareWord) else "<proc>"
|
||||
)
|
||||
self._add(proc_name, lsp.SymbolKind.Function, command)
|
||||
|
||||
# --- SET ---
|
||||
elif name == "set" and len(command.args) >= 1:
|
||||
var_arg = command.args[0]
|
||||
var_name = var_arg.contents if isinstance(var_arg, BareWord) else "<var>"
|
||||
self._add(var_name, lsp.SymbolKind.Variable, command)
|
||||
Reference in New Issue
Block a user