update completion items
This commit is contained in:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user