use ls_types::*;
use bbnf::types::{Expression, Token};
use crate::state::DocumentState;
fn get_inner_expression<'a, T>(tok: &'a Token<'a, T>) -> &'a T {
&tok.value
}
pub fn selection_ranges(state: &DocumentState, positions: Vec<Position>) -> Vec<SelectionRange> {
let ast = state.ast().unwrap_or_else(|| panic!(
"selection_ranges requested for document with no parsed AST"
));
positions
.iter()
.map(|&pos| {
let offset = state.line_index.position_to_offset(pos);
compute_selection_range(&state.line_index, ast, offset).unwrap_or_else(|| {
panic!(
"selection_ranges could not resolve a span chain for position {}:{}",
pos.line, pos.character
)
})
})
.collect()
}
fn compute_selection_range(
line_index: &crate::analysis::LineIndex,
ast: &bbnf::types::AST<'_>,
offset: usize,
) -> Option<SelectionRange> {
for (lhs, rhs) in ast.iter() {
if let Expression::Nonterminal(Token { span: name_span, .. }) = lhs {
let rule_start = name_span.start;
let rule_end = crate::state::compute_expression_end_pub(rhs).unwrap_or_else(|| {
panic!(
"compute_selection_range could not compute expression end for rule at {}",
name_span.start
)
});
if offset < rule_start || offset > rule_end {
continue;
}
let mut spans = Vec::new();
collect_spans(rhs, offset, &mut spans);
spans.push((rule_start, rule_end));
spans.sort_by_key(|(start, end)| *end - *start);
spans.dedup();
let mut result: Option<SelectionRange> = None;
for (start, end) in spans.into_iter().rev() {
let range = line_index.span_to_range(start, end);
result = Some(SelectionRange {
range,
parent: result.map(Box::new),
});
}
return result;
}
}
None
}
fn collect_spans(expr: &Expression<'_>, offset: usize, spans: &mut Vec<(usize, usize)>) {
match expr {
Expression::Literal(tok) | Expression::Nonterminal(tok) | Expression::Regex(tok) => {
if offset >= tok.span.start && offset <= tok.span.end {
spans.push((tok.span.start, tok.span.end));
}
}
Expression::Epsilon(tok) => {
if offset >= tok.span.start && offset <= tok.span.end {
spans.push((tok.span.start, tok.span.end));
}
}
Expression::Alternation(inner) | Expression::Concatenation(inner) => {
if offset >= inner.span.start && offset <= inner.span.end {
spans.push((inner.span.start, inner.span.end));
}
for child in get_inner_expression(inner) {
collect_spans(child, offset, spans);
}
}
Expression::Group(inner)
| Expression::Optional(inner)
| Expression::Many(inner)
| Expression::Many1(inner)
| Expression::OptionalWhitespace(inner) => {
if offset >= inner.span.start && offset <= inner.span.end {
spans.push((inner.span.start, inner.span.end));
}
collect_spans(get_inner_expression(inner), offset, spans);
}
Expression::Skip(l, r) | Expression::Next(l, r) | Expression::Minus(l, r) => {
let start = l.span.start;
let end = r.span.end;
if offset >= start && offset <= end {
spans.push((start, end));
}
collect_spans(get_inner_expression(l), offset, spans);
collect_spans(get_inner_expression(r), offset, spans);
}
Expression::Rule(rhs, _) => {
collect_spans(rhs, offset, spans);
}
Expression::MappedExpression((expr_tok, _)) => {
collect_spans(get_inner_expression(expr_tok), offset, spans);
}
Expression::DebugExpression((expr_tok, _)) => {
collect_spans(get_inner_expression(expr_tok), offset, spans);
}
_ => {}
}
}