feat(lsp): add Tcl command-aware completion and integration
- Introduced a Tcl command-aware completion engine and wired to LSP. - Added a new module with Tcl commands, options, and contextual matching. - Updated completion to favor command-aware items and args.
This commit is contained in:
@@ -38,13 +38,18 @@ update_sys_path(
|
||||
# Imports needed for the language server goes below this.
|
||||
# **********************************************************
|
||||
# pylint: disable=wrong-import-position,import-error
|
||||
import lsp_jsonrpc as jsonrpc
|
||||
import lsprotocol.types as lsp
|
||||
from common.load_data import standard_items
|
||||
from lsp_tclserver import TclLanguageServer
|
||||
from pygls import uris
|
||||
from pygls.workspace.text_document import TextDocument
|
||||
from tools.completion_items import completion_context, ranked_completion_items
|
||||
|
||||
import lsp_jsonrpc as jsonrpc
|
||||
from common.load_data import standard_items
|
||||
from lsp_tclserver import TclLanguageServer
|
||||
from tools.completion_items import (
|
||||
CompletionContext,
|
||||
completion_context,
|
||||
ranked_completion_items,
|
||||
)
|
||||
from tools.folding_ranges import build_folding_ranges
|
||||
from tools.inlay_hint import (
|
||||
InlayHintGenerator,
|
||||
@@ -69,6 +74,11 @@ from tools.semantic_tokens import (
|
||||
_Highlighter,
|
||||
)
|
||||
from tools.signature_help import build_signature_help
|
||||
from tools.tcl_command_completion import (
|
||||
TCL_COMMAND_ITEMS,
|
||||
TCL_COMMAND_NAMES,
|
||||
tcl_argument_completions,
|
||||
)
|
||||
|
||||
WORKSPACE_SETTINGS = {}
|
||||
GLOBAL_SETTINGS = {}
|
||||
@@ -82,10 +92,12 @@ LSP_SERVER = TclLanguageServer(
|
||||
BUILTIN_PROC_NAMES = {
|
||||
item.label
|
||||
for item in standard_items.tcl_keyword_list + standard_items.nx_procs
|
||||
}
|
||||
} | set(TCL_COMMAND_NAMES)
|
||||
BUILTIN_VARIABLE_NAMES = {item.label for item in standard_items.nx_variables}
|
||||
_STATIC_TCL_LABELS = {item.label for item in standard_items.tcl_keyword_list}
|
||||
STATIC_COMPLETION_ITEMS = tuple(
|
||||
standard_items.tcl_keyword_list
|
||||
+ [item for item in TCL_COMMAND_ITEMS if item.label not in _STATIC_TCL_LABELS]
|
||||
+ standard_items.nx_procs
|
||||
+ standard_items.nx_variables
|
||||
)
|
||||
@@ -250,16 +262,40 @@ def document_diagnostic(params: lsp.DocumentDiagnosticParams):
|
||||
|
||||
@LSP_SERVER.feature(
|
||||
lsp.TEXT_DOCUMENT_COMPLETION,
|
||||
lsp.CompletionOptions(trigger_characters=["$"]),
|
||||
lsp.CompletionOptions(trigger_characters=["$", " ", "-"]),
|
||||
)
|
||||
def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
|
||||
doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
|
||||
position = params.position
|
||||
source_lines = LSP_SERVER.get_lines(doc)
|
||||
context = completion_context(source_lines, position)
|
||||
|
||||
# Variable completion wins inside command arguments. Otherwise prefer the
|
||||
# narrow command grammar when the cursor is at a known subcommand/option.
|
||||
if context != CompletionContext.VARIABLE:
|
||||
argument_items = tcl_argument_completions(source_lines, position)
|
||||
if argument_items is not None:
|
||||
items = ranked_completion_items(
|
||||
((0, item) for item in argument_items),
|
||||
CompletionContext.GENERAL,
|
||||
)
|
||||
return lsp.CompletionList(is_incomplete=False, items=items)
|
||||
|
||||
# Space and dash are registered only to open command-aware suggestions.
|
||||
# Do not display the broad fallback list when such a trigger has no match.
|
||||
if (
|
||||
params.context is not None
|
||||
and params.context.trigger_kind
|
||||
== lsp.CompletionTriggerKind.TriggerCharacter
|
||||
and params.context.trigger_character in {" ", "-"}
|
||||
):
|
||||
return lsp.CompletionList(is_incomplete=False, items=[])
|
||||
|
||||
tree = LSP_SERVER.get_tree(doc)
|
||||
globals_set, procs_locals, proc_ranges = LSP_SERVER.variable_index_for_document(
|
||||
doc, tree
|
||||
)
|
||||
|
||||
position = params.position
|
||||
local_names: set[str] = set()
|
||||
for proc_range in proc_ranges:
|
||||
end_line = proc_range.end_line or proc_range.start_line
|
||||
@@ -302,7 +338,6 @@ def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
|
||||
candidates.extend((priority, item) for item in items_by_file[item_path])
|
||||
|
||||
candidates.extend((300, item) for item in STATIC_COMPLETION_ITEMS)
|
||||
context = completion_context(LSP_SERVER.get_lines(doc), position)
|
||||
items = ranked_completion_items(candidates, context)
|
||||
return lsp.CompletionList(is_incomplete=False, items=items)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user