update completion items

This commit is contained in:
Christoph Brandau
2025-07-30 17:28:18 +02:00
parent 8da61abfce
commit ed045aa459
6 changed files with 208 additions and 166 deletions
+105 -65
View File
@@ -1,76 +1,116 @@
from tclint.parser import Parser
from tclint.syntax_tree import Visitor, BareWord, VarSub, Comment, Command, Function
TOKEN_TYPES = {
"command": 0,
"variable": 1,
"function": 2,
"string": 3,
"number": 4,
"keyword": 5,
"comment": 6,
}
import enum
from typing import List
from tclint.syntax_tree import Visitor
from tclint.commands import get_commands
import attrs
from common.load_data import standard_items
import lsprotocol.types as lsp
class SemanticTokenCollector(Visitor):
def __init__(self):
self.tokens = []
def _add_token(self, node, token_type):
if not node.pos or not node.end_pos:
return
line, col = node.pos
end_line, end_col = node.end_pos
length = (end_col - col) if line == end_line else 1
self.tokens.append((line - 1, col - 1, length, token_type, 0))
def visit_command(self, command: Command):
self._add_token(command.routine, "command")
for arg in command.args:
arg.accept(self, recurse=True)
def visit_comment(self, comment: Comment):
self._add_token(comment, "comment")
def visit_bare_word(self, word: BareWord):
if word.value.isdigit():
self._add_token(word, "number")
else:
self._add_token(word, "string")
def visit_var_sub(self, var_sub: VarSub):
self._add_token(var_sub, "variable")
def visit_function(self, function: Function):
self._add_token(function.name, "function")
for arg in function.args:
arg.accept(self, recurse=True)
class TokenModifier(enum.IntFlag):
deprecated = enum.auto()
readonly = enum.auto()
defaultLibrary = enum.auto()
definition = enum.auto()
def collect_semantic_tokens(code: str):
parser = Parser()
tree = parser.parse(code)
visitor = SemanticTokenCollector()
tree.accept(visitor, recurse=True)
return visitor.tokens
@attrs.define
class Token:
line: int
offset: int
lenght: int
tok_type: str = ""
tok_modifiers: List[TokenModifier] = attrs.field(factory=list)
def encode_tokens(tokens):
tokens.sort()
encoded = []
TOKEN_TYPES = [
"keyword",
"variable",
"function",
"operator",
"parameter",
"type",
"class",
]
last_line = 0
last_char = 0
for line, char, length, token_type, modifiers in tokens:
delta_line = line - last_line
delta_start = char - last_char if delta_line == 0 else char
class _Highlighter(Visitor):
def __init__(self, plugins, log_to_output):
self._commands = get_commands(plugins)
self._tokens = []
self.log_to_output = log_to_output
encoded.extend([delta_line, delta_start, length, token_type, modifiers])
def visit_command(self, command):
routine = command.routine
self.log_to_output(str(command.routine))
if routine.contents in self._commands:
line, col = routine.pos
self._tokens.append(((line - 1, col - 1), len(routine.contents), "keyword"))
last_line = line
last_char = char if delta_line == 0 else 0
if routine.contents == "set" and command.args:
first_arg = command.args[0]
if hasattr(first_arg, "pos") and hasattr(first_arg, "value"):
line, col = first_arg.pos
self._tokens.append(
(((line - 1, col - 1), len(first_arg.value), "variable"))
)
if routine.contents == "proc" and command.args:
first_arg = command.args[0]
if hasattr(first_arg, "pos") and hasattr(first_arg, "value"):
line, col = first_arg.pos
self._tokens.append(
(((line - 1, col - 1), len(first_arg.value), "function"))
)
return encoded
if routine.contents == "namespace" and command.args:
first_arg = command.args[1]
if hasattr(first_arg, "pos") and hasattr(first_arg, "value"):
line, col = first_arg.pos
self._tokens.append(
(((line - 1, col - 1), len(first_arg.value), "class"))
)
def visit_var_sub(self, var_sub):
self.log_to_output(str(var_sub))
pass
def tokens(self) -> list[Token]:
"""Encode tokens as described in
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens.
"""
tokens = []
last_line = 0
last_col = 0
for (line, col), length, tok_type in sorted(self._tokens, key=lambda x: x[0]):
line_delta = line - last_line
col_delta = col
if line == last_line:
col_delta -= last_col
tokens.append(Token(line_delta, col_delta, length, tok_type))
last_line, last_col = line, col
return tokens
# @server.feature(
# lsp.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
# lsp.SemanticTokensLegend(token_types=["keyword"], token_modifiers=[]),
# )
# def semantic_tokens(ls: TclspServer, params: lsp.SemanticTokensParams):
# logging.debug("Received %s: %s", lsp.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL, params)
# document = ls.workspace.get_text_document(params.text_document.uri)
# path = Path(document.path)
# root = ls.get_root(path)
# config = ls.get_config(path, root)
# plugins = [config.commands] if config.commands is not None else []
# parser = Parser(command_plugins=plugins)
# hl = _Highlighter(plugins)
# tree = parser.parse(document.source)
# tree.accept(hl, recurse=True)
# return lsp.SemanticTokens(data=hl.tokens())