usse/scrape/venv/lib/python3.10/site-packages/esbonio/lsp/symbols.py

132 lines
3.7 KiB
Python
Raw Normal View History

2023-12-22 14:26:01 +00:00
from typing import Optional
from docutils import nodes
from docutils.nodes import NodeVisitor
from lsprotocol.types import DocumentSymbol
from lsprotocol.types import Position
from lsprotocol.types import Range
from lsprotocol.types import SymbolKind
class SymbolVisitor(NodeVisitor):
"""A visitor used to build the hierarchy we return from a
``textDocument/documentSymbol`` request.
"""
def __init__(self, rst, *args, **kwargs):
super().__init__(*args, **kwargs)
self.logger = rst.logger
self.symbols = []
self.symbol_stack = []
@property
def current_symbol(self) -> Optional[DocumentSymbol]:
if len(self.symbol_stack) == 0:
return None
return self.symbol_stack[-1]
def push_symbol(self):
symbol = DocumentSymbol(
name="",
kind=SymbolKind.String,
range=Range(
start=Position(line=1, character=0),
end=Position(line=1, character=10),
),
selection_range=Range(
start=Position(line=1, character=0),
end=Position(line=1, character=10),
),
children=[],
)
current_symbol = self.current_symbol
if not current_symbol:
self.symbols.append(symbol)
else:
if current_symbol.children is None:
current_symbol.children = [symbol]
else:
current_symbol.children.append(symbol)
self.symbol_stack.append(symbol)
return symbol
def pop_symbol(self):
self.symbol_stack.pop()
def visit_section(self, node: nodes.Node) -> None:
self.push_symbol()
def depart_section(self, node: nodes.Node) -> None:
self.pop_symbol()
def visit_title(self, node: nodes.Node) -> None:
symbol = self.current_symbol
has_parent = True
if symbol is None:
has_parent = False
symbol = self.push_symbol()
name = node.astext()
line = (node.line or 1) - 1
symbol.name = name
symbol.range.start.line = line
symbol.range.end.line = line
symbol.range.end.character = len(name) - 1
symbol.selection_range.start.line = line
symbol.selection_range.end.line = line
symbol.selection_range.end.character = len(name) - 1
if not has_parent:
self.pop_symbol()
def depart_title(self, node: nodes.Node) -> None:
pass
def visit_a_directive(self, node: nodes.Element):
symbol = self.push_symbol()
name = node["text"] # type: ignore
line = (node.line or 1) - 1
symbol.name = name
symbol.kind = SymbolKind.Class
symbol.range.start.line = line
symbol.range.end.line = line
symbol.range.end.character = len(name) - 1
symbol.selection_range.start.line = line
symbol.selection_range.end.line = line
symbol.selection_range.end.character = len(name) - 1
def depart_a_directive(self, node: nodes.Node):
self.pop_symbol()
# TODO: Enable symbols for roles
# However the reported line numbers can be inaccurate...
def visit_a_role(self, node: nodes.Node) -> None:
...
def depart_a_role(self, node: nodes.Node) -> None:
...
# TODO: Enable symbols for definition list items
# However the reported line numbers appear to be inaccurate...
def visit_Text(self, node: nodes.Node) -> None:
pass
def depart_Text(self, node: nodes.Node) -> None:
pass
def unknown_visit(self, node: nodes.Node) -> None:
pass
def unknown_departure(self, node: nodes.Node) -> None:
pass