add new features and fix bugs

This commit is contained in:
Christoph Brandau
2026-06-18 17:31:51 +02:00
parent 41f331d4c4
commit 3ad3847045
14 changed files with 988 additions and 171 deletions
+2 -1
View File
@@ -8,4 +8,5 @@ __pycache__
*.pyc *.pyc
.nox .nox
*.g4 *.g4
.antlr .antlr
.claude
+70
View File
@@ -0,0 +1,70 @@
import * as vscode from "vscode"
/**
* Computes folding ranges for a TCL document based on brace matching.
*
* Handles same-line opening braces (`... {`), standalone `{`, `} elseif`/`} else`
* branch continuations and line continuations (`\`).
*/
export function computeTclFoldingRanges(document: vscode.TextDocument): vscode.FoldingRange[] {
const ranges: vscode.FoldingRange[] = []
const stack: number[] = []
let pendingStartLine: number | null = null
for (let i = 0; i < document.lineCount; i += 1) {
const line = document.lineAt(i).text
const trimmed = line.trim()
const branchContinuation = /^\}\s*(elseif|else)\b/.test(trimmed)
const sameLineOpen = trimmed.endsWith("{")
if (!trimmed || trimmed.startsWith("#")) {
continue
}
if (trimmed.startsWith("}")) {
const startLine = stack.pop()
const endLine = branchContinuation ? i - 1 : i
if (typeof startLine === "number" && startLine < endLine) {
ranges.push(
new vscode.FoldingRange(startLine, endLine, vscode.FoldingRangeKind.Region)
)
}
if (branchContinuation && sameLineOpen) {
stack.push(i)
pendingStartLine = null
} else if (trimmed !== "}" && trimmed.endsWith("\\")) {
pendingStartLine = i
} else {
pendingStartLine = null
}
continue
}
if (trimmed === "{") {
const startLine = pendingStartLine ?? i
if (startLine < i) {
stack.push(startLine)
} else {
stack.push(i)
}
pendingStartLine = null
continue
}
if (trimmed.endsWith("{")) {
stack.push(i)
pendingStartLine = null
continue
}
if (trimmed.endsWith("\\")) {
pendingStartLine = i
continue
}
pendingStartLine = null
}
return ranges
}
+12
View File
@@ -15,6 +15,7 @@ import {
cdlDocumentSymbolProvider, cdlDocumentSymbolProvider,
defDocumentSymbolProvider defDocumentSymbolProvider
} from "./common/handlers" } from "./common/handlers"
import { computeTclFoldingRanges } from "./common/folding"
import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging" import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging"
import { import {
checkVersion, checkVersion,
@@ -115,6 +116,17 @@ export async function activate(context: vscode.ExtensionContext) {
} }
}) })
// Folding ranges for TCL (brace based)
const tclFoldingProvider = vscode.languages.registerFoldingRangeProvider(
[{ language: "tcl" }],
{
provideFoldingRanges(document: vscode.TextDocument) {
return computeTclFoldingRanges(document)
}
}
)
context.subscriptions.push(tclFoldingProvider)
// //
const formatCdlProvider = vscode.languages.registerDocumentFormattingEditProvider( const formatCdlProvider = vscode.languages.registerDocumentFormattingEditProvider(
{ scheme: "file", language: "cdl" }, { scheme: "file", language: "cdl" },
+33 -26
View File
@@ -1,28 +1,35 @@
{ {
"comments": { "comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments // symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "#" "lineComment": "#"
}, },
// symbols used as brackets "indentationRules": {
"brackets": [ // Ignore pure comment lines so they don't terminate folds inside Tcl brace blocks.
["{", "}"], "unIndentedLinePattern": "^\\s*#.*$",
["[", "]"], // Opening braces on their own line are common in NX Tcl.
["(", ")"] "increaseIndentPattern": "^((?!#).)*(\\{[^}\"']*)$",
], "decreaseIndentPattern": "^\\s*[\\}\\]\\)].*$"
// symbols that are auto closed when typing },
"autoClosingPairs": [ // symbols used as brackets
["{", "}"], "brackets": [
["[", "]"], ["{", "}"],
["(", ")"], ["[", "]"],
["\"", "\""], ["(", ")"]
["'", "'"] ],
], // symbols that are auto closed when typing
// symbols that can be used to surround a selection "autoClosingPairs": [
"surroundingPairs": [ ["{", "}"],
["{", "}"], ["[", "]"],
["[", "]"], ["(", ")"],
["(", ")"], ["\"", "\""],
["\"", "\""], ["'", "'"]
["'", "'"] ],
] // symbols that can be used to surround a selection
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
} }
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "nx-post-support", "name": "nx-post-support",
"version": "0.3.0", "version": "2025.9.200",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nx-post-support", "name": "nx-post-support",
"version": "0.3.0", "version": "2025.9.200",
"devDependencies": { "devDependencies": {
"@types/vscode": "^1.96.0", "@types/vscode": "^1.96.0",
"@vscode/vsce": "^3.2.1", "@vscode/vsce": "^3.2.1",
+6 -1
View File
@@ -134,5 +134,10 @@
"esbuild": "^0.25.6", "esbuild": "^0.25.6",
"prettier": "^3.4.2", "prettier": "^3.4.2",
"typescript": "^5.7.2" "typescript": "^5.7.2"
},
"__metadata": {
"installedTimestamp": 1776513675781,
"targetPlatform": "undefined",
"size": 3267242
} }
} }
+4 -1
View File
@@ -12,6 +12,10 @@ from typing import List
import nox # pylint: disable=import-error import nox # pylint: disable=import-error
# Use uv to create session environments. The uv-managed standalone Python builds
# don't ship pythonw.exe, which makes the default virtualenv backend fail on Windows.
nox.options.default_venv_backend = "uv"
def _read_dependencies() -> List[str]: def _read_dependencies() -> List[str]:
"""Read project dependencies from pyproject.toml.""" """Read project dependencies from pyproject.toml."""
@@ -28,7 +32,6 @@ def _install_bundle(session: nox.Session) -> None:
"--target", "--target",
"./libs", "./libs",
"--no-cache-dir", "--no-cache-dir",
"py",
"--upgrade", "--upgrade",
*deps, *deps,
external=True, external=True,
+6 -1
View File
@@ -9,6 +9,11 @@ dependencies = [
"tclint", "tclint",
] ]
[dependency-groups]
dev = [
"nox>=2026.2.9",
]
[build-system] [build-system]
requires = ["setuptools>=61.0"] requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
+70 -19
View File
@@ -42,6 +42,7 @@ import lsp_jsonrpc as jsonrpc
import lsprotocol.types as lsp import lsprotocol.types as lsp
from pygls import uris, workspace from pygls import uris, workspace
from common.load_data import standard_items from common.load_data import standard_items
from tools.folding_ranges import build_folding_ranges
from tools.semantic_tokens import _Highlighter, TOKEN_TYPES, TokenModifier from tools.semantic_tokens import _Highlighter, TOKEN_TYPES, TokenModifier
from tools.completion_items import completion, remove_existing_items, remove_shared_keys from tools.completion_items import completion, remove_existing_items, remove_shared_keys
from tools.inlay_hint import InlayHintGenerator from tools.inlay_hint import InlayHintGenerator
@@ -54,7 +55,9 @@ GLOBAL_SETTINGS = {}
MAX_WORKERS = 5 MAX_WORKERS = 5
LSP_SERVER = TclLanguageServer(name="NX Postprocessor Support", version="0.0.1", max_workers=MAX_WORKERS) LSP_SERVER = TclLanguageServer(
name="NX Postprocessor Support", version="0.0.1", max_workers=MAX_WORKERS
)
# ********************************************************** # **********************************************************
# Tool specific code goes below this. # Tool specific code goes below this.
@@ -132,16 +135,24 @@ def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
# Base items # Base items
poco = [item for items in LSP_SERVER.poco_completion.values() for item in items] poco = [item for items in LSP_SERVER.poco_completion.values() for item in items]
base_items = standard_items.tcl_keyword_list + standard_items.nx_procs + standard_items.nx_variables + poco base_items = (
standard_items.tcl_keyword_list
+ standard_items.nx_procs
+ standard_items.nx_variables
+ poco
)
# Build variable index from current document # Build variable index from current document
globals_set, procs_locals, proc_ranges = build_variable_index(doc.source) tree = LSP_SERVER.get_tree(doc)
globals_set, procs_locals, proc_ranges = build_variable_index(doc.source, tree)
# Always include globals (excluding built-ins) # Always include globals (excluding built-ins)
dynamic_items = [] dynamic_items = []
for name in sorted(globals_set): for name in sorted(globals_set):
if name not in BUILTIN_VAR_LABELS: if name not in BUILTIN_VAR_LABELS:
dynamic_items.append(lsp.CompletionItem(label=name, kind=lsp.CompletionItemKind.Variable)) dynamic_items.append(
lsp.CompletionItem(label=name, kind=lsp.CompletionItemKind.Variable)
)
# Include proc-local variables when cursor is inside that proc # Include proc-local variables when cursor is inside that proc
pos = params.position pos = params.position
@@ -151,7 +162,11 @@ def on_completion(params: lsp.CompletionParams) -> lsp.CompletionList:
for name in sorted(procs_locals.get(pr.name, set())): for name in sorted(procs_locals.get(pr.name, set())):
# Exclude built-ins and globals to avoid duplication # Exclude built-ins and globals to avoid duplication
if name not in BUILTIN_VAR_LABELS and name not in globals_set: if name not in BUILTIN_VAR_LABELS and name not in globals_set:
dynamic_items.append(lsp.CompletionItem(label=name, kind=lsp.CompletionItemKind.Variable)) dynamic_items.append(
lsp.CompletionItem(
label=name, kind=lsp.CompletionItemKind.Variable
)
)
break break
# Merge with de-duplication for variables only # Merge with de-duplication for variables only
@@ -235,6 +250,13 @@ def semantic_tokens(params: lsp.SemanticTokensParams):
return lsp.SemanticTokens(data=data) return lsp.SemanticTokens(data=data)
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_FOLDING_RANGE)
def folding_ranges(params: lsp.FoldingRangeParams):
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
tree = LSP_SERVER.get_tree(document)
return build_folding_ranges(tree)
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_HOVER) @LSP_SERVER.feature(lsp.TEXT_DOCUMENT_HOVER)
def hover(params: lsp.HoverParams) -> lsp.Hover: def hover(params: lsp.HoverParams) -> lsp.Hover:
pos = params.position pos = params.position
@@ -270,7 +292,9 @@ def hover(params: lsp.HoverParams) -> lsp.Hover:
if match and match.get("kind") == "function": if match and match.get("kind") == "function":
label = match.get("label", "") label = match.get("label", "")
parameters = match.get("parameters", []) parameters = match.get("parameters", [])
param_lines = "\n".join(f"- `{p['name']}`: {p['desc']}" for p in parameters) or "_None_" param_lines = (
"\n".join(f"- `{p['name']}`: {p['desc']}" for p in parameters) or "_None_"
)
example_data = match.get("example", []) example_data = match.get("example", [])
example_md = "\n".join(f"{line}" for line in example_data) example_md = "\n".join(f"{line}" for line in example_data)
returns_data = match.get("returns", ["None"]) returns_data = match.get("returns", ["None"])
@@ -302,7 +326,9 @@ def hover(params: lsp.HoverParams) -> lsp.Hover:
proc_docs.update(file_docs) proc_docs.update(file_docs)
if token in proc_docs: if token in proc_docs:
return lsp.Hover(lsp.MarkupContent(kind=lsp.MarkupKind.Markdown, value=proc_docs[token])) return lsp.Hover(
lsp.MarkupContent(kind=lsp.MarkupKind.Markdown, value=proc_docs[token])
)
return None return None
@@ -432,8 +458,12 @@ def initialize(params: lsp.InitializeParams) -> lsp.InitializeResult:
settings = params.initialization_options["settings"] settings = params.initialization_options["settings"]
_update_workspace_settings(settings) _update_workspace_settings(settings)
log_to_output(f"Settings used to run Server:\r\n{json.dumps(settings, indent=4, ensure_ascii=False)}\r\n") log_to_output(
log_to_output(f"Global settings:\r\n{json.dumps(GLOBAL_SETTINGS, indent=4, ensure_ascii=False)}\r\n") f"Settings used to run Server:\r\n{json.dumps(settings, indent=4, ensure_ascii=False)}\r\n"
)
log_to_output(
f"Global settings:\r\n{json.dumps(GLOBAL_SETTINGS, indent=4, ensure_ascii=False)}\r\n"
)
semantic_tokens_legend = lsp.SemanticTokensLegend( semantic_tokens_legend = lsp.SemanticTokensLegend(
token_types=TOKEN_TYPES, token_types=TOKEN_TYPES,
token_modifiers=[m.name for m in TokenModifier], token_modifiers=[m.name for m in TokenModifier],
@@ -441,7 +471,10 @@ def initialize(params: lsp.InitializeParams) -> lsp.InitializeResult:
return lsp.InitializeResult( return lsp.InitializeResult(
capabilities=lsp.ServerCapabilities( capabilities=lsp.ServerCapabilities(
document_formatting_provider=GLOBAL_SETTINGS.get("formatter", True), document_formatting_provider=GLOBAL_SETTINGS.get("formatter", True),
semantic_tokens_provider=lsp.SemanticTokensOptions(legend=semantic_tokens_legend, full=True, range=False), folding_range_provider=True,
semantic_tokens_provider=lsp.SemanticTokensOptions(
legend=semantic_tokens_legend, full=True, range=False
),
definition_provider=True, definition_provider=True,
) )
) )
@@ -461,22 +494,38 @@ def initialized(_params: lsp.InitializedParams):
for sourced_layer in poco_files: for sourced_layer in poco_files:
completion.reset() completion.reset()
try: try:
file_root = pathlib.Path(root).joinpath(sourced_layer.subfolder if sourced_layer.subfolder else "") file_root = pathlib.Path(root).joinpath(
sourced_layer.subfolder if sourced_layer.subfolder else ""
)
for tcl_file in sourced_layer.files: for tcl_file in sourced_layer.files:
filepath = pathlib.Path(file_root).joinpath(f"{tcl_file}.tcl") filepath = pathlib.Path(file_root).joinpath(
f"{tcl_file}.tcl"
)
if not filepath.exists(): if not filepath.exists():
continue continue
completion.reset() completion.reset()
document = LSP_SERVER.workspace.get_text_document(filepath.as_uri()) document = LSP_SERVER.workspace.get_text_document(
filepath.as_uri()
)
tree = LSP_SERVER.parser.parse(document.source) tree = LSP_SERVER.parser.parse(document.source)
tree.accept(completion, recurse=True) tree.accept(completion, recurse=True)
remove_existing_items(completion.custom_functions, LSP_SERVER.poco_completion) remove_existing_items(
LSP_SERVER.poco_completion[str(filepath)] = completion.custom_functions completion.custom_functions, LSP_SERVER.poco_completion
remove_shared_keys(LSP_SERVER.proc_signatures, completion.proc_signatures) )
LSP_SERVER.proc_signatures[str(filepath)] = completion.proc_signatures LSP_SERVER.poco_completion[str(filepath)] = (
completion.custom_functions
)
remove_shared_keys(
LSP_SERVER.proc_signatures, completion.proc_signatures
)
LSP_SERVER.proc_signatures[str(filepath)] = (
completion.proc_signatures
)
from tools.proc_docs import build_proc_docs from tools.proc_docs import build_proc_docs
LSP_SERVER.proc_docs[str(filepath)] = build_proc_docs(tree, document.source) LSP_SERVER.proc_docs[str(filepath)] = build_proc_docs(
tree, document.source
)
except Exception as e: except Exception as e:
log_to_output(f"Fehler beim Parsen von {filepath}: {e}") log_to_output(f"Fehler beim Parsen von {filepath}: {e}")
log_to_output("Background indexing completed.") log_to_output("Background indexing completed.")
@@ -578,7 +627,9 @@ def _get_settings_by_document(document: workspace.Document | None):
# ***************************************************** # *****************************************************
# Logging and notification. # Logging and notification.
# ***************************************************** # *****************************************************
def log_to_output(message: str, msg_type: lsp.MessageType = lsp.MessageType.Log) -> None: def log_to_output(
message: str, msg_type: lsp.MessageType = lsp.MessageType.Log
) -> None:
LSP_SERVER.show_message_log(message, msg_type) LSP_SERVER.show_message_log(message, msg_type)
+52
View File
@@ -0,0 +1,52 @@
from __future__ import annotations
from typing import List
import lsprotocol.types as lsp
from tclint.syntax_tree import Command, Node, Script
def _add_range(
ranges: list[lsp.FoldingRange],
seen: set[tuple[int, int]],
start_line: int,
end_line: int,
) -> None:
if start_line >= end_line:
return
key = (start_line, end_line)
if key in seen:
return
seen.add(key)
ranges.append(
lsp.FoldingRange(
start_line=start_line,
end_line=end_line,
kind=lsp.FoldingRangeKind.Region,
)
)
def build_folding_ranges(tree: Node) -> List[lsp.FoldingRange]:
ranges: list[lsp.FoldingRange] = []
seen: set[tuple[int, int]] = set()
def walk(node: Node) -> None:
if isinstance(node, Command):
previous_node: Node = node.routine
for arg in node.args:
if isinstance(arg, Script):
anchor = getattr(previous_node, "pos", None) or getattr(
node, "pos", None
)
if anchor is not None and arg.end_pos is not None:
_add_range(ranges, seen, anchor[0] - 1, arg.end_pos[0] - 1)
previous_node = arg
for child in getattr(node, "children", []):
walk(child)
walk(tree)
return sorted(ranges, key=lambda item: (item.start_line, item.end_line))
+37 -52
View File
@@ -1,7 +1,7 @@
import enum import enum
from typing import List from typing import List
from tclint.syntax_tree import Visitor, QuotedWord, Command, BareWord from tclint.syntax_tree import Visitor, QuotedWord, Command, BareWord
from tclint.commands import get_commands from tclint.commands.plugins import PluginManager
import attrs import attrs
from common.load_data import standard_items from common.load_data import standard_items
import lsprotocol.types as lsp import lsprotocol.types as lsp
@@ -33,6 +33,7 @@ class Token:
TOKEN_TYPES = [ TOKEN_TYPES = [
"keyword", "keyword",
"comment",
"variable", "variable",
"function", "function",
"operator", "operator",
@@ -46,10 +47,15 @@ TOKEN_TYPES = [
class _Highlighter(Visitor): class _Highlighter(Visitor):
def __init__(self, plugins, custom_functions: dict[str : list[lsp.CompletionItem]]): def __init__(self, plugins, custom_functions: dict[str : list[lsp.CompletionItem]]):
self._commands = get_commands(plugins) self._commands = PluginManager().get_commands(plugins)
self._tokens = [] self._tokens = []
self.custom_functions = custom_functions self.custom_functions = custom_functions
def _append_token(self, position, length: int, tok_type: str, modifiers: List[TokenModifier] | None = None):
if position is None or length <= 0:
return
self._tokens.append((position, length, tok_type, modifiers or []))
def _get_token_info(self, node): def _get_token_info(self, node):
"""Hilfsmethode um Token-Informationen aus verschiedenen Node-Typen zu extrahieren.""" """Hilfsmethode um Token-Informationen aus verschiedenen Node-Typen zu extrahieren."""
if not hasattr(node, "pos"): if not hasattr(node, "pos"):
@@ -81,8 +87,18 @@ class _Highlighter(Visitor):
if not word.contents: if not word.contents:
return return
line, col = word.contents_pos line, col = word.contents_pos
self._tokens.append(((line - 1, col - 1), len(word.contents), "string", [])) self._append_token((line - 1, col - 1), len(word.contents), "string", [])
pass
def visit_comment(self, comment):
if not hasattr(comment, "pos") or comment.pos is None or comment.end_pos is None:
return
start_line, start_col = comment.pos
end_line, end_col = comment.end_pos
if start_line != end_line:
return
self._append_token((start_line - 1, start_col - 1), end_col - start_col, "comment", [])
def visit_bare_word(self, word: BareWord): def visit_bare_word(self, word: BareWord):
# Intentionally do not classify bare words as functions here. # Intentionally do not classify bare words as functions here.
@@ -100,49 +116,32 @@ class _Highlighter(Visitor):
in_standard = any(item.label == name for item in standard_items.nx_procs) in_standard = any(item.label == name for item in standard_items.nx_procs)
if in_custom or in_standard: if in_custom or in_standard:
line, col = routine.contents_pos line, col = routine.contents_pos
self._tokens.append((((line - 1, col - 1), len(name), "function", []))) self._append_token((line - 1, col - 1), len(name), "function", [])
if routine.contents in {"global", "variable"}:
line, col = routine.contents_pos
self._append_token((line - 1, col - 1), len(routine.contents), "keyword", [])
for arg in command.args:
token_info = self._get_token_info(arg)
if token_info:
(arg_line, arg_col), length = token_info
self._append_token((arg_line, arg_col), length, "variable", [])
if routine.contents == "puts": if routine.contents == "puts":
line, col = routine.contents_pos line, col = routine.contents_pos
self._tokens.append( self._append_token((line - 1, col - 1), len(routine.contents), "function", [TokenModifier.builtin])
(
(
(line - 1, col - 1),
len(routine.contents),
"function",
[TokenModifier.builtin],
)
)
)
if routine.contents == "set" and command.args: if routine.contents == "set" and command.args:
first_arg = command.args[0] first_arg = command.args[0]
token_info = self._get_token_info(first_arg) token_info = self._get_token_info(first_arg)
if token_info: if token_info:
(line, col), length = token_info (line, col), length = token_info
self._tokens.append( self._append_token((line, col), length, "variable", [TokenModifier.declaration])
(
(
(line, col),
length,
"variable",
[TokenModifier.declaration],
)
)
)
if routine.contents == "proc" and command.args: if routine.contents == "proc" and command.args:
first_arg = command.args[0] first_arg = command.args[0]
if hasattr(first_arg, "pos") and hasattr(first_arg, "value"): if hasattr(first_arg, "pos") and hasattr(first_arg, "value"):
line, col = first_arg.pos line, col = first_arg.pos
self._tokens.append( self._append_token((line - 1, col - 1), len(first_arg.value), "function", [TokenModifier.declaration])
(
(
(line - 1, col - 1),
len(first_arg.value),
"function",
[TokenModifier.declaration],
)
)
)
if len(command.args) >= 2: if len(command.args) >= 2:
param_list = command.args[1] param_list = command.args[1]
@@ -153,33 +152,19 @@ class _Highlighter(Visitor):
# Parameter kann einfaches Wort sein # Parameter kann einfaches Wort sein
if hasattr(child, "value") and child.value is not None: if hasattr(child, "value") and child.value is not None:
line, col = child.pos line, col = child.pos
self._tokens.append( self._append_token((line - 1, col - 1), len(child.value), "parameter", [TokenModifier.declaration])
(
(line - 1, col - 1),
len(child.value),
"parameter",
[TokenModifier.declaration],
)
)
# Parameter mit Default-Wert ist meist eine List (z.B. {arg default}) # Parameter mit Default-Wert ist meist eine List (z.B. {arg default})
elif hasattr(child, "children") and len(child.children) >= 1: elif hasattr(child, "children") and len(child.children) >= 1:
name_node = child.children[0] name_node = child.children[0]
if hasattr(name_node, "value") and hasattr(name_node, "pos"): if hasattr(name_node, "value") and hasattr(name_node, "pos"):
line, col = name_node.pos line, col = name_node.pos
self._tokens.append( self._append_token((line - 1, col - 1), len(name_node.value), "parameter", [TokenModifier.declaration])
(
(line - 1, col - 1),
len(name_node.value),
"parameter",
[TokenModifier.declaration],
)
)
if routine.contents == "namespace" and command.args: if routine.contents == "namespace" and command.args:
first_arg = command.args[1] first_arg = command.args[1]
if hasattr(first_arg, "pos") and first_arg.value is not None: if hasattr(first_arg, "pos") and first_arg.value is not None:
line, col = first_arg.pos line, col = first_arg.pos
self._tokens.append((((line - 1, col - 1), len(first_arg.value), "class", []))) self._append_token((line - 1, col - 1), len(first_arg.value), "class", [])
def tokens(self) -> list[Token]: def tokens(self) -> list[Token]:
"""Encode tokens as described in """Encode tokens as described in
+62 -66
View File
@@ -1,11 +1,9 @@
import re from __future__ import annotations
from dataclasses import dataclass
from typing import Dict, Set, List, Tuple
# Reuse patterns similar to document_symbols from dataclasses import dataclass
NS_RE = re.compile(r"^\s*namespace\s+eval\s+([^\s\{]+)") from typing import Dict, List, Set
PROC_RE = re.compile(r"^\s*proc\s+([^\s\{]+)\s+\{.*\}\s+\{")
SET_RE = re.compile(r"^\s*set\s+([^\s\}]+)") from tclint.syntax_tree import Command, Node, Script
@dataclass @dataclass
@@ -15,86 +13,84 @@ class ProcRange:
end_line: int | None = None end_line: int | None = None
def build_variable_index(source: str) -> tuple[Set[str], Dict[str, Set[str]], List[ProcRange]]: def _normalize_var_name(raw_name: str | None) -> str | None:
if not raw_name:
return None
base = raw_name.split("(", 1)[0]
if base.startswith("::"):
base = base[2:]
return base or None
def build_variable_index(source: str, tree: Node | None = None) -> tuple[Set[str], Dict[str, Set[str]], List[ProcRange]]:
""" """
Parse Tcl source text and build: Parse Tcl source text and build:
- globals: set of variable names considered global suggestions - globals: set of variable names considered global suggestions
- procs: mapping proc_name -> set of local variable names (set without :: inside that proc) - procs: mapping proc_name -> set of local variable names inside that proc
- proc_ranges: list of ProcRange (name, start_line, end_line) - proc_ranges: list of ProcRange (name, start_line, end_line)
Rules: Rules:
- set ::var -> global var suggestion (strip leading :: and any array index "(") - set ::var -> global var suggestion (strip leading :: and any array index "(")
- set var without :: at top level (not in namespace/proc) -> global suggestion - set var without :: at top level (not in namespace/proc) -> global suggestion
- set var without :: inside proc -> local to that proc - set var without :: inside proc -> local to that proc
- global var1 var2 inside a proc -> global suggestions for those names
- set var inside namespace (no ::) is ignored for global suggestions - set var inside namespace (no ::) is ignored for global suggestions
""" """
lines = source.split("\n") _ = source # Kept for signature compatibility with callers.
class Scope:
def __init__(self, name: str, kind: str, start_line: int):
self.name = name
self.kind = kind # "namespace" or "proc" or "root"
self.start_line = start_line
self.brace_count = 0
globals_set: Set[str] = set() globals_set: Set[str] = set()
procs: Dict[str, Set[str]] = {} procs: Dict[str, Set[str]] = {}
proc_ranges: List[ProcRange] = [] proc_ranges: List[ProcRange] = []
scope_stack: List[Scope] = [Scope("", "root", 0)] if tree is None:
return globals_set, procs, proc_ranges
for i, line in enumerate(lines): def walk(node: Node, scope_stack: list[tuple[str, str]]) -> None:
ns_match = NS_RE.match(line) if isinstance(node, Command):
proc_match = PROC_RE.match(line) routine = getattr(node.routine, "contents", None)
set_match = SET_RE.match(line)
# Namespace scope if routine == "proc" and len(node.args) >= 3 and isinstance(node.args[2], Script):
if ns_match: proc_name = _normalize_var_name(getattr(node.args[0], "contents", None))
scope_stack.append(Scope(ns_match.group(1), "namespace", i)) if proc_name is not None:
procs.setdefault(proc_name, set())
proc_ranges.append(
ProcRange(
name=proc_name,
start_line=node.pos[0] - 1,
end_line=node.args[2].end_pos[0] - 1,
)
)
walk(node.args[2], [*scope_stack, ("proc", proc_name)])
return
# Proc scope if routine == "namespace" and len(node.args) >= 3 and getattr(node.args[0], "contents", None) == "eval" and isinstance(node.args[2], Script):
elif proc_match: namespace_name = _normalize_var_name(getattr(node.args[1], "contents", None)) or ""
pname = proc_match.group(1) walk(node.args[2], [*scope_stack, ("namespace", namespace_name)])
scope_stack.append(Scope(pname, "proc", i)) return
proc_ranges.append(ProcRange(name=pname, start_line=i, end_line=None))
# Track set statements if routine == "set" and node.args:
if set_match: raw_name = getattr(node.args[0], "contents", None)
raw_name = set_match.group(1) base = _normalize_var_name(raw_name)
# Normalize array names and leading :: if base is not None:
base = raw_name.split("(", 1)[0] if raw_name and raw_name.startswith("::"):
if base.startswith("::"): globals_set.add(base)
clean = base[2:] else:
globals_set.add(clean) scope_kind, scope_name = scope_stack[-1]
else: if scope_kind == "root":
top = scope_stack[-1] globals_set.add(base)
if top.kind == "root": elif scope_kind == "proc":
globals_set.add(base) procs.setdefault(scope_name, set()).add(base)
elif top.kind == "proc":
procs.setdefault(top.name, set()).add(base)
else:
# inside namespace without :: -> ignore for globals
pass
# Brace balancing for current top scope if routine == "global":
open_count = line.count("{") for arg in node.args:
close_count = line.count("}") base = _normalize_var_name(getattr(arg, "contents", None))
scope_stack[-1].brace_count += open_count - close_count if base is not None:
globals_set.add(base)
# Close finished scopes for child in getattr(node, "children", []):
while len(scope_stack) > 1 and scope_stack[-1].brace_count <= 0: walk(child, scope_stack)
finished = scope_stack.pop()
if finished.kind == "proc":
# Update the last matching proc range end_line
for pr in reversed(proc_ranges):
if pr.name == finished.name and pr.end_line is None:
pr.end_line = i
break
# Finalize any unterminated proc ranges
for pr in proc_ranges:
if pr.end_line is None:
pr.end_line = len(lines) - 1
walk(tree, [("root", "")])
return globals_set, procs, proc_ranges return globals_set, procs, proc_ranges
+614
View File
@@ -0,0 +1,614 @@
version = 1
revision = 3
requires-python = ">=3.8"
resolution-markers = [
"python_full_version >= '3.10'",
"python_full_version == '3.9.*'",
"python_full_version < '3.9'",
]
[[package]]
name = "argcomplete"
version = "3.6.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" },
]
[[package]]
name = "attrs"
version = "25.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" },
]
[[package]]
name = "attrs"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
[[package]]
name = "cattrs"
version = "24.1.3"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
dependencies = [
{ name = "attrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.9'" },
{ name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/29/7b/da4aa2f95afb2f28010453d03d6eedf018f9e085bd001f039e15731aba89/cattrs-24.1.3.tar.gz", hash = "sha256:981a6ef05875b5bb0c7fb68885546186d306f10f0f6718fe9b96c226e68821ff", size = 426684, upload-time = "2025-03-25T15:01:00.325Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/ee/d68a3de23867a9156bab7e0a22fb9a0305067ee639032a22982cf7f725e7/cattrs-24.1.3-py3-none-any.whl", hash = "sha256:adf957dddd26840f27ffbd060a6c4dd3b2192c5b7c2c0525ef1bd8131d8a83f5", size = 66462, upload-time = "2025-03-25T15:00:58.663Z" },
]
[[package]]
name = "cattrs"
version = "25.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
dependencies = [
{ name = "attrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "exceptiongroup", marker = "python_full_version == '3.9.*'" },
{ name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6e/00/2432bb2d445b39b5407f0a90e01b9a271475eea7caf913d7a86bcb956385/cattrs-25.3.0.tar.gz", hash = "sha256:1ac88d9e5eda10436c4517e390a4142d88638fe682c436c93db7ce4a277b884a", size = 509321, upload-time = "2025-10-07T12:26:08.737Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d8/2b/a40e1488fdfa02d3f9a653a61a5935ea08b3c2225ee818db6a76c7ba9695/cattrs-25.3.0-py3-none-any.whl", hash = "sha256:9896e84e0a5bf723bc7b4b68f4481785367ce07a8a02e7e9ee6eb2819bc306ff", size = 70738, upload-time = "2025-10-07T12:26:06.603Z" },
]
[[package]]
name = "cattrs"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
dependencies = [
{ name = "attrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
{ name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a0/ec/ba18945e7d6e55a58364d9fb2e46049c1c2998b3d805f19b703f14e81057/cattrs-26.1.0.tar.gz", hash = "sha256:fa239e0f0ec0715ba34852ce813986dfed1e12117e209b816ab87401271cdd40", size = 495672, upload-time = "2026-02-18T22:15:19.406Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/80/56/60547f7801b97c67e97491dc3d9ade9fbccbd0325058fd3dfcb2f5d98d90/cattrs-26.1.0-py3-none-any.whl", hash = "sha256:d1e0804c42639494d469d08d4f26d6b9de9b8ab26b446db7b5f8c2e97f7c3096", size = 73054, upload-time = "2026-02-18T22:15:17.958Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "colorlog"
version = "6.10.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" },
]
[[package]]
name = "contextlib2"
version = "21.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c7/13/37ea7805ae3057992e96ecb1cffa2fa35c2ef4498543b846f90dd2348d8f/contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869", size = 43795, upload-time = "2021-06-27T06:54:40.841Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/56/6d6872f79d14c0cb02f1646cbb4592eef935857c0951a105874b7b62a0c3/contextlib2-21.6.0-py2.py3-none-any.whl", hash = "sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f", size = 13277, upload-time = "2021-06-27T06:54:20.972Z" },
]
[[package]]
name = "dependency-groups"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" },
]
[[package]]
name = "distlib"
version = "0.4.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" },
]
[[package]]
name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
]
[[package]]
name = "filelock"
version = "3.16.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037, upload-time = "2024-09-17T19:02:01.779Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163, upload-time = "2024-09-17T19:02:00.268Z" },
]
[[package]]
name = "filelock"
version = "3.19.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
]
[[package]]
name = "filelock"
version = "3.29.4"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
sdist = { url = "https://files.pythonhosted.org/packages/e6/dc/be6cbe99670cd6e4ad387123647cb08e0c32975e223f82551e914c5568a6/filelock-3.29.4.tar.gz", hash = "sha256:10cdb3656fc44541cdf30652a93fb10ec6b05325620eb316bd26893e4201538a", size = 63028, upload-time = "2026-06-13T16:12:00.744Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/13/37/a065dc3bd6e49423a6532c642ca7378d3f467b1ef44c2800c937af7f9739/filelock-3.29.4-py3-none-any.whl", hash = "sha256:dac1648087d5115554850d113e7dd8c83ab2d38e3435dde2d4f163847e57b767", size = 42757, upload-time = "2026-06-13T16:11:59.582Z" },
]
[[package]]
name = "humanize"
version = "4.10.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/5d/b1/c8f05d5dc8f64030d8cc71e91307c1daadf6ec0d70bcd6eabdfd9b6f153f/humanize-4.10.0.tar.gz", hash = "sha256:06b6eb0293e4b85e8d385397c5868926820db32b9b654b932f57fa41c23c9978", size = 79192, upload-time = "2024-07-08T10:31:04.945Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8f/49/a29c79bea335e52fb512a43faf84998c184c87fef82c65f568f8c56f2642/humanize-4.10.0-py3-none-any.whl", hash = "sha256:39e7ccb96923e732b5c2e27aeaa3b10a8dfeeba3eb965ba7b74a3eb0e30040a6", size = 126957, upload-time = "2024-07-08T10:31:02.751Z" },
]
[[package]]
name = "humanize"
version = "4.13.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/98/1d/3062fcc89ee05a715c0b9bfe6490c00c576314f27ffee3a704122c6fd259/humanize-4.13.0.tar.gz", hash = "sha256:78f79e68f76f0b04d711c4e55d32bebef5be387148862cb1ef83d2b58e7935a0", size = 81884, upload-time = "2025-08-25T09:39:20.04Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/c7/316e7ca04d26695ef0635dc81683d628350810eb8e9b2299fc08ba49f366/humanize-4.13.0-py3-none-any.whl", hash = "sha256:b810820b31891813b1673e8fec7f1ed3312061eab2f26e3fa192c393d11ed25f", size = 128869, upload-time = "2025-08-25T09:39:18.54Z" },
]
[[package]]
name = "humanize"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" },
]
[[package]]
name = "importlib-metadata"
version = "6.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "zipp", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "zipp", version = "3.23.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "zipp", version = "4.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/33/44/ae06b446b8d8263d712a211e959212083a5eda2bf36d57ca7415e03f6f36/importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743", size = 53494, upload-time = "2023-07-07T16:16:03.091Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", size = 22933, upload-time = "2023-07-07T16:16:01.381Z" },
]
[[package]]
name = "lsprotocol"
version = "2023.0.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "attrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
{ name = "cattrs", version = "24.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "cattrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "cattrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/f6/6e80484ec078d0b50699ceb1833597b792a6c695f90c645fbaf54b947e6f/lsprotocol-2023.0.1.tar.gz", hash = "sha256:cc5c15130d2403c18b734304339e51242d3018a05c4f7d0f198ad6e0cd21861d", size = 69434, upload-time = "2024-01-09T17:21:12.625Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8d/37/2351e48cb3309673492d3a8c59d407b75fb6630e560eb27ecd4da03adc9a/lsprotocol-2023.0.1-py3-none-any.whl", hash = "sha256:c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2", size = 70826, upload-time = "2024-01-09T17:21:14.491Z" },
]
[[package]]
name = "nox"
version = "2026.2.9"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
dependencies = [
{ name = "argcomplete", marker = "python_full_version < '3.9'" },
{ name = "attrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "colorlog", marker = "python_full_version < '3.9'" },
{ name = "dependency-groups", marker = "python_full_version < '3.9'" },
{ name = "humanize", version = "4.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "packaging", marker = "python_full_version < '3.9'" },
{ name = "tomli", marker = "python_full_version < '3.9'" },
{ name = "virtualenv", version = "21.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6e/8e/55a9679b31f1efc48facedd2448eb53c7f1e647fb592aa1403c9dd7a4590/nox-2026.2.9.tar.gz", hash = "sha256:1bc8a202ee8cd69be7aaada63b2a7019126899a06fc930a7aee75585bf8ee41b", size = 4031165, upload-time = "2026-02-10T04:38:58.878Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8d/58/0d5e5a044f1868bdc45f38afdc2d90ff9867ce398b4e8fa9e666bfc9bfba/nox-2026.2.9-py3-none-any.whl", hash = "sha256:1b7143bc8ecdf25f2353201326152c5303ae4ae56ca097b1fb6179ad75164c47", size = 74615, upload-time = "2026-02-10T04:38:57.266Z" },
]
[[package]]
name = "nox"
version = "2026.4.10"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
"python_full_version == '3.9.*'",
]
dependencies = [
{ name = "argcomplete", marker = "python_full_version >= '3.9'" },
{ name = "attrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
{ name = "colorlog", marker = "python_full_version >= '3.9'" },
{ name = "dependency-groups", marker = "python_full_version >= '3.9'" },
{ name = "humanize", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "humanize", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "packaging", marker = "python_full_version >= '3.9'" },
{ name = "tomli", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" },
{ name = "virtualenv", version = "21.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e7/6b/e672c862a43cfca704d32359221fa3780226daa1e5db5dfc401bcc8be9c9/nox-2026.4.10.tar.gz", hash = "sha256:2d0af5374f3f37a295428c927d1b04a8182aa01762897d172446dda2f1ce9692", size = 4034839, upload-time = "2026-04-10T17:42:42.209Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/95/4df134a100b5a9a12378d5301b934366686ef6fbdaffcd21211d5654970e/nox-2026.4.10-py3-none-any.whl", hash = "sha256:082c117627590d9b90aa21f86df89b310b07c5842539524203bcb3c719f116c1", size = 75536, upload-time = "2026-04-10T17:42:40.664Z" },
]
[[package]]
name = "nx-post-support-server"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "nox", version = "2026.2.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "nox", version = "2026.4.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" },
{ name = "packaging" },
{ name = "pygls" },
{ name = "tclint", version = "0.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "tclint", version = "0.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "tclint", version = "0.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
[package.metadata]
requires-dist = [
{ name = "nox", specifier = ">=2026.2.9" },
{ name = "packaging" },
{ name = "pygls" },
{ name = "tclint" },
]
[[package]]
name = "packaging"
version = "26.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
]
[[package]]
name = "pathspec"
version = "0.11.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a0/2a/bd167cdf116d4f3539caaa4c332752aac0b3a0cc0174cdb302ee68933e81/pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3", size = 47032, upload-time = "2023-07-29T01:05:04.481Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/2a/9b1be29146139ef459188f5e420a66e835dda921208db600b7037093891f/pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20", size = 29603, upload-time = "2023-07-29T01:05:02.656Z" },
]
[[package]]
name = "platformdirs"
version = "4.3.6"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302, upload-time = "2024-09-17T19:06:50.688Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" },
]
[[package]]
name = "platformdirs"
version = "4.4.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
]
[[package]]
name = "platformdirs"
version = "4.10.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" },
]
[[package]]
name = "ply"
version = "3.11"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" },
]
[[package]]
name = "pygls"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cattrs", version = "24.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "cattrs", version = "25.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "cattrs", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "lsprotocol" },
]
sdist = { url = "https://files.pythonhosted.org/packages/86/b9/41d173dad9eaa9db9c785a85671fc3d68961f08d67706dc2e79011e10b5c/pygls-1.3.1.tar.gz", hash = "sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018", size = 45527, upload-time = "2024-03-26T18:44:25.679Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/11/19/b74a10dd24548e96e8c80226cbacb28b021bc3a168a7d2709fb0d0185348/pygls-1.3.1-py3-none-any.whl", hash = "sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e", size = 56031, upload-time = "2024-03-26T18:44:24.249Z" },
]
[[package]]
name = "python-discovery"
version = "1.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock", version = "3.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "filelock", version = "3.29.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "platformdirs", version = "4.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/cbbaf13b730abb0a16b964d984e19f2fe520c21a4dc664051359a3f5a9e7/python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690", size = 70277, upload-time = "2026-06-11T16:10:42.383Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1a/82/a70006589557f267f15bd384c0642ad49f0d97b690c3a05b166b9dcbad3b/python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500", size = 33886, upload-time = "2026-06-11T16:10:41.192Z" },
]
[[package]]
name = "schema"
version = "0.7.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "contextlib2", marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4e/e8/01e1b46d9e04cdaee91c9c736d9117304df53361a191144c8eccda7f0ee9/schema-0.7.5.tar.gz", hash = "sha256:f06717112c61895cabc4707752b88716e8420a8819d71404501e114f91043197", size = 48173, upload-time = "2021-12-01T20:49:24.038Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0d/93/ca8aa5a772efd69043d0a745172d92bee027caa7565c7f774a2f44b91207/schema-0.7.5-py2.py3-none-any.whl", hash = "sha256:f3ffdeeada09ec34bf40d7d79996d9f7175db93b7a5065de0faa7f41083c1e6c", size = 17603, upload-time = "2021-12-01T20:49:21.252Z" },
]
[[package]]
name = "tclint"
version = "0.4.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
dependencies = [
{ name = "importlib-metadata", marker = "python_full_version < '3.9'" },
{ name = "pathspec", marker = "python_full_version < '3.9'" },
{ name = "ply", marker = "python_full_version < '3.9'" },
{ name = "schema", marker = "python_full_version < '3.9'" },
{ name = "tomli", marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/88/1c7a191cd487f73ead49f447ec7963866ef093e47382d51cc54b60e89c6d/tclint-0.4.2.tar.gz", hash = "sha256:27dc43f6804a560f0813bd0bca3b617369f9909e9db8d609906660b367ef1583", size = 70559, upload-time = "2024-10-08T02:45:28.603Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/b5/51832e9a286e65a17a4846ab4d634a6eee44692874cf298bf82c807e5495/tclint-0.4.2-py3-none-any.whl", hash = "sha256:9be008df348ad9558e07f21bc02e3b385be4444c448f4aed982ef6be40698309", size = 52481, upload-time = "2024-10-08T02:45:27.508Z" },
]
[[package]]
name = "tclint"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
dependencies = [
{ name = "importlib-metadata", marker = "python_full_version == '3.9.*'" },
{ name = "pathspec", marker = "python_full_version == '3.9.*'" },
{ name = "ply", marker = "python_full_version == '3.9.*'" },
{ name = "pygls", marker = "python_full_version == '3.9.*'" },
{ name = "tomli", marker = "python_full_version == '3.9.*'" },
{ name = "voluptuous", marker = "python_full_version == '3.9.*'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/84/57/bac53151cc404c8fd5b15c69943cde772b404cd740ee576d5a7ca12732d1/tclint-0.7.0.tar.gz", hash = "sha256:bd605b11d44708e1537b902e63d7dd1d05f2d85c2c99a36854b157606eac1e8a", size = 90458, upload-time = "2025-12-21T22:35:27.041Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/72/1465bedba4f2ea4ae501eaa9f8e06d31e62627f053c88c58544c50ec4ac5/tclint-0.7.0-py3-none-any.whl", hash = "sha256:58b54bf333a96ef4b4eac3bde23da997a64a4414a4cdec8e5e0a9fbafb6dcd25", size = 53945, upload-time = "2025-12-21T22:35:25.436Z" },
]
[[package]]
name = "tclint"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
dependencies = [
{ name = "importlib-metadata", marker = "python_full_version >= '3.10'" },
{ name = "pathspec", marker = "python_full_version >= '3.10'" },
{ name = "ply", marker = "python_full_version >= '3.10'" },
{ name = "pygls", marker = "python_full_version >= '3.10'" },
{ name = "tomli", marker = "python_full_version == '3.10.*'" },
{ name = "voluptuous", marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3f/4e/9ec785aa3f9473bcbd56bb858a46749db94baee2c1df603c458bfe189b51/tclint-0.8.0.tar.gz", hash = "sha256:0a0fff0dd4610859a85c06bd347c8ffb46e9bed79cdd34662738a518acc43c0c", size = 97995, upload-time = "2026-03-24T01:54:41.49Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/cc/781a8bf0ec24ebe8850f9aee7101c9177e90f98b3400c9ceaa1f5421b0d5/tclint-0.8.0-py3-none-any.whl", hash = "sha256:0fff3ec0878bc870005bf4cbcd4529e2764d2adfa602532f86f456e49df2c002", size = 57012, upload-time = "2026-03-24T01:54:40.186Z" },
]
[[package]]
name = "tomli"
version = "2.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed", size = 16096, upload-time = "2024-10-02T10:46:13.208Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cf/db/ce8eda256fa131af12e0a76d481711abe4681b6923c27efb9a255c9e4594/tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", size = 13237, upload-time = "2024-10-02T10:46:11.806Z" },
]
[[package]]
name = "typing-extensions"
version = "4.13.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "virtualenv"
version = "21.4.3"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
dependencies = [
{ name = "distlib", marker = "python_full_version < '3.9'" },
{ name = "filelock", version = "3.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
{ name = "python-discovery", marker = "python_full_version < '3.9'" },
{ name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4b/50/7564c805bb8966d9771caaba8a143fa5e57c848ce4e7fdf2d55a1feb2ead/virtualenv-21.4.3.tar.gz", hash = "sha256:938ff0fd3f4e0f0d3a025f67a3d2f25e3c3aabbcd5857ea6170619138d72d141", size = 7644454, upload-time = "2026-06-11T16:47:04.843Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a2/8d/84b0d07c6b5f685f85ddf6c87a59d3a8a895a3dfd89e759666fabe951b94/virtualenv-21.4.3-py3-none-any.whl", hash = "sha256:75f4127d4067397c64f38579ce918fec6bf9ca2cd4f48685e82952cc3c035840", size = 7625544, upload-time = "2026-06-11T16:47:01.78Z" },
]
[[package]]
name = "virtualenv"
version = "21.5.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
"python_full_version == '3.9.*'",
]
dependencies = [
{ name = "distlib", marker = "python_full_version >= '3.9'" },
{ name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "filelock", version = "3.29.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" },
{ name = "platformdirs", version = "4.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "python-discovery", marker = "python_full_version >= '3.9'" },
{ name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f1/a5/81f987504738e6defeed61ec1c47e2aefab3c35d8eeb87e1b3f38cf28254/virtualenv-21.5.1.tar.gz", hash = "sha256:dca3bf98275a59c652b69d68e73433e597d977c2da9198882479d1a7188009c8", size = 4578798, upload-time = "2026-06-16T16:23:58.603Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/02/3623e6169bed617ed1e2d372f7c69f92ec28d54c4dfc997055c8578ec148/virtualenv-21.5.1-py3-none-any.whl", hash = "sha256:55aa670b67bbfb991b03fda39bd3276d92c419d702376e98c5df1c9989a26783", size = 4558820, upload-time = "2026-06-16T16:23:56.963Z" },
]
[[package]]
name = "voluptuous"
version = "0.15.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/91/af/a54ce0fb6f1d867e0b9f0efe5f082a691f51ccf705188fca67a3ecefd7f4/voluptuous-0.15.2.tar.gz", hash = "sha256:6ffcab32c4d3230b4d2af3a577c87e1908a714a11f6f95570456b1849b0279aa", size = 51651, upload-time = "2024-07-02T19:10:00.528Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/db/a8/8f9cc6749331186e6a513bfe3745454f81d25f6e34c6024f88f80c71ed28/voluptuous-0.15.2-py3-none-any.whl", hash = "sha256:016348bc7788a9af9520b1764ebd4de0df41fe2138ebe9e06fa036bf86a65566", size = 31349, upload-time = "2024-07-02T19:09:58.125Z" },
]
[[package]]
name = "zipp"
version = "3.20.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.9'",
]
sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199, upload-time = "2024-09-13T13:44:16.101Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200, upload-time = "2024-09-13T13:44:14.38Z" },
]
[[package]]
name = "zipp"
version = "3.23.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version == '3.9.*'",
]
sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" },
]
[[package]]
name = "zipp"
version = "4.1.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.10'",
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" },
]
+18 -2
View File
@@ -38,11 +38,16 @@
"match": "(\\\\(?:\\d{1,3}|x[a-fA-F0-9]{1,2}|u[a-fA-F0-9]{1,4}|U[a-fA-F0-9]{1,8}|.))", "match": "(\\\\(?:\\d{1,3}|x[a-fA-F0-9]{1,2}|u[a-fA-F0-9]{1,4}|U[a-fA-F0-9]{1,8}|.))",
"name": "constant.character.escape.tcl" "name": "constant.character.escape.tcl"
}, },
{
"match": "(^\\s*#.*$)",
"name": "comment.tcl",
"comment": "Line comments inside braced scripts."
},
{ "include": "#keywords" }, { "include": "#keywords" },
{ {
"match": "((?<={)\\s*(?:after|append|apply|array|auto_execok|auto_import|auto_load|auto_mkindex|auto_qualify|auto_reset|bgerror|binary|break|catch|cd|chan|clock|close|concat|continue|coroutine|dde|dict|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|fileevent|file|flush|foreach|for|format|gets|global|glob|history|http|if|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|lmap|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|memory|my|namespace|nextto|next|oo::class|oo::copy|oo::define|oo::objdefine|oo::object|open|package|parray|pid|pkg::create|pkg_mkIndex|platform::shell|proc|puts|pwd|read|regexp|registry|regsub|rename|return|scan|seek|self|set|socket|source|split|string|subst|switch|tailcall|tcl::prefix|tcl_endOfWord|tcl_findLibrary|tcl_startOfNextWord|tcl_startOfPreviousWord|tcl_wordBreakAfter|tcl_wordBreakBefore|tell|throw|time|trace|try|unknown|unload|unset|update|uplevel|upvar|variable|vwait|while|yieldto|yield)\\s+)", "match": "((?<=^|[\\x{007b}\\x{003b}\\n])\\s*(?:after|append|apply|array|auto_execok|auto_import|auto_load|auto_mkindex|auto_qualify|auto_reset|bgerror|binary|break|catch|cd|chan|clock|close|concat|continue|coroutine|dde|dict|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|fileevent|file|flush|foreach|for|format|gets|global|glob|history|http|if|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|lmap|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|memory|my|namespace|nextto|next|oo::class|oo::copy|oo::define|oo::objdefine|oo::object|open|package|parray|pid|pkg::create|pkg_mkIndex|platform::shell|proc|puts|pwd|read|regexp|registry|regsub|rename|return|scan|seek|self|set|socket|source|split|string|subst|switch|tailcall|tcl::prefix|tcl_endOfWord|tcl_findLibrary|tcl_startOfNextWord|tcl_startOfPreviousWord|tcl_wordBreakAfter|tcl_wordBreakBefore|tell|throw|time|trace|try|unknown|unload|unset|update|uplevel|upvar|variable|vwait|while|yieldto|yield)\\s+)",
"name": "keyword.tcl", "name": "keyword.tcl",
"comment": "Special handling for known commands." "comment": "Special handling for known commands inside braced scripts."
}, },
{ "include": "#braced_inner" }, { "include": "#braced_inner" },
{ "include": "#args" } { "include": "#args" }
@@ -65,6 +70,17 @@
"match": "(\\\\[\\x{007b}\\x{007d}])", "match": "(\\\\[\\x{007b}\\x{007d}])",
"name": "constant.character.escape.tcl" "name": "constant.character.escape.tcl"
}, },
{
"match": "(^\\s*#.*$)",
"name": "comment.tcl",
"comment": "Line comments inside nested braced scripts."
},
{ "include": "#keywords" },
{
"match": "((?<=^|[\\x{007b}\\x{003b}\\n])\\s*(?:after|append|apply|array|auto_execok|auto_import|auto_load|auto_mkindex|auto_qualify|auto_reset|bgerror|binary|break|catch|cd|chan|clock|close|concat|continue|coroutine|dde|dict|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|fileevent|file|flush|foreach|for|format|gets|global|glob|history|http|if|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|lmap|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|memory|my|namespace|nextto|next|oo::class|oo::copy|oo::define|oo::objdefine|oo::object|open|package|parray|pid|pkg::create|pkg_mkIndex|platform::shell|proc|puts|pwd|read|regexp|registry|regsub|rename|return|scan|seek|self|set|socket|source|split|string|subst|switch|tailcall|tcl::prefix|tcl_endOfWord|tcl_findLibrary|tcl_startOfNextWord|tcl_startOfPreviousWord|tcl_wordBreakAfter|tcl_wordBreakBefore|tell|throw|time|trace|try|unknown|unload|unset|update|uplevel|upvar|variable|vwait|while|yieldto|yield)\\s+)",
"name": "keyword.tcl",
"comment": "Special handling for known commands inside nested braced scripts."
},
{ "include": "#numeric" }, { "include": "#numeric" },
{ "include": "#braced_inner" }, { "include": "#braced_inner" },
{ "include": "#args" } { "include": "#args" }