update
This commit is contained in:
@@ -179,11 +179,11 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
context.subscriptions.push(formatDefProvider)
|
||||
|
||||
const tclOutlineProvider = vscode.languages.registerDocumentSymbolProvider(
|
||||
{ scheme: "file", language: "tcl" },
|
||||
{ provideDocumentSymbols: tclDocumentSymbolProvider }
|
||||
)
|
||||
context.subscriptions.push(tclOutlineProvider)
|
||||
// const tclOutlineProvider = vscode.languages.registerDocumentSymbolProvider(
|
||||
// { scheme: "file", language: "tcl" },
|
||||
// { provideDocumentSymbols: tclDocumentSymbolProvider }
|
||||
// )
|
||||
// context.subscriptions.push(tclOutlineProvider)
|
||||
|
||||
// Diagnostics collection
|
||||
const diagnosticCollectionCdl = vscode.languages.createDiagnosticCollection("cdl")
|
||||
|
||||
@@ -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)
|
||||
+12
-2
@@ -5,21 +5,31 @@ if {$main == 1 && 1 == 1} {
|
||||
|
||||
proc test {} {
|
||||
puts "main"
|
||||
proc llll {} {}
|
||||
set rrrrrrr
|
||||
}
|
||||
LIB_GE_command_buffer_edit_insert MOM_tool_change_LIB TOOL_CHANGE_AUTO {CUSTOM_after_tool_change_call} mytag after @TOOL_CHANGE_AUTO
|
||||
|
||||
MOM_abort
|
||||
|
||||
namespace eval myns {
|
||||
proc add {a b} {
|
||||
set sum [expr {$a + $b}]
|
||||
return $sum
|
||||
}
|
||||
set config "debug"
|
||||
}
|
||||
|
||||
#_________________________________________________________________________________________________
|
||||
# <Documentation>
|
||||
# Function to output a spacer line or empty line
|
||||
#_________________________________________________________________________________________________
|
||||
proc SERVICE_spacer_output {type {length 20} {line_num 0} {output 1} check} {
|
||||
proc SERVICE_spacer_output {type {length 20} {line_num 0} {output 1}} {
|
||||
LIB_GE_message [string repeat $type $length] "output_$output" $line_num
|
||||
}
|
||||
|
||||
|
||||
SERVICE_spacer_output "*" 50 0 1
|
||||
SERVICE_remove_file $filename
|
||||
|
||||
#_________________________________________________________________________________________________
|
||||
# <Documentation>
|
||||
|
||||
Reference in New Issue
Block a user