Files
nx_post_support/server/src/tools/tcloo_navigation.py
T
Christoph Brandau b2e6e9d250 perf(server): avoid unnecessary reparses and cache navigation definitions
Introduce several changes to reduce full-document reparses, lock contention and
redundant work when handling TclOO analysis and navigation:

- Add a cheap may_contain_classes pre-check and several cursor/receiver
  heuristics so completions, signature help and tcloo definitions skip the
  expensive marker reparse when the document cannot contain useful OO info.
- Allow passing an existing parsed tree into tcloo completion/signature/definition
  helpers; update callers to use the server's cached tree when available.
- Use a thread-local parser for request-time parse_source to avoid blocking the
  shared parser during background indexing, and add navigation_state() which
  returns cached definition identities (invalidated on index generation changes).
- Add a cheap name pre-filter (_may_resolve_to) for symbol matching and only
  run class highlighting when classes may exist.

These changes reduce contention and repeated parsing, improve responsiveness for
requests during background indexing, and cache navigation definition identities.
Tests were added/updated to assert caching and non-blocking behavior.
2026-09-23 12:04:36 +02:00

39 lines
1.7 KiB
Python

"""Definition targets for literal TclOO classes and resolved method calls."""
from tools.tcloo_completion import _analyze, may_contain_classes, name_location, parse_completion_source
from tools.tcloo_symbols import class_symbols
def tcloo_definition(source, uri, position, external_classes=None, tree=None):
if not may_contain_classes(source, external_classes):
return None
if tree is None:
tree = parse_completion_source(source)
if tree is None:
return None
classes, _, calls = _analyze(tree, external_classes=external_classes, uri=uri, source=source)
def contains(location):
if location is None:
return False
start, end = location.range.start, location.range.end
return (start.line, start.character) <= (position.line, position.character) < (end.line, end.character)
targets = {}
declarations, references = class_symbols(tree, classes, targets)
for node in references:
if contains(name_location(node, uri, source)):
return classes[targets[node.pos]].definition
for name, node in declarations.items():
if contains(name_location(node, uri, source)):
return classes[name].definition
for call in calls:
if call.command.args and contains(name_location(call.command.args[0], uri, source)):
return call.definition
# F12 on a declaration itself should stay on that declaration.
for info in classes.values():
for location in [*info.method_definitions.values(), info.constructor_definition]:
if location is not None and location.uri == uri and contains(location):
return location
return None