bbnf_analysis/features/
selection_range.rs1use ls_types::*;
2
3use bbnf::types::{Expression, Token};
4
5use crate::state::DocumentState;
6
7fn get_inner_expression<'a, T>(tok: &'a Token<'a, T>) -> &'a T {
9 &tok.value
10}
11
12pub fn selection_ranges(state: &DocumentState, positions: Vec<Position>) -> Vec<SelectionRange> {
17 let ast = state.ast().unwrap_or_else(|| panic!(
19 "selection_ranges requested for document with no parsed AST"
20 ));
21
22 positions
23 .iter()
24 .map(|&pos| {
25 let offset = state.line_index.position_to_offset(pos);
26 compute_selection_range(&state.line_index, ast, offset).unwrap_or_else(|| {
27 panic!(
28 "selection_ranges could not resolve a span chain for position {}:{}",
29 pos.line, pos.character
30 )
31 })
32 })
33 .collect()
34}
35
36fn compute_selection_range(
38 line_index: &crate::analysis::LineIndex,
39 ast: &bbnf::types::AST<'_>,
40 offset: usize,
41) -> Option<SelectionRange> {
42 for (lhs, rhs) in ast.iter() {
44 if let Expression::Nonterminal(Token { span: name_span, .. }) = lhs {
45 let rule_start = name_span.start;
46 let rule_end = crate::state::compute_expression_end_pub(rhs).unwrap_or_else(|| {
47 panic!(
48 "compute_selection_range could not compute expression end for rule at {}",
49 name_span.start
50 )
51 });
52
53 if offset < rule_start || offset > rule_end {
54 continue;
55 }
56
57 let mut spans = Vec::new();
59 collect_spans(rhs, offset, &mut spans);
60
61 spans.push((rule_start, rule_end));
63
64 spans.sort_by_key(|(start, end)| *end - *start);
66 spans.dedup();
67
68 let mut result: Option<SelectionRange> = None;
70 for (start, end) in spans.into_iter().rev() {
71 let range = line_index.span_to_range(start, end);
72 result = Some(SelectionRange {
73 range,
74 parent: result.map(Box::new),
75 });
76 }
77
78 return result;
79 }
80 }
81 None
82}
83
84fn collect_spans(expr: &Expression<'_>, offset: usize, spans: &mut Vec<(usize, usize)>) {
86 match expr {
87 Expression::Literal(tok) | Expression::Nonterminal(tok) | Expression::Regex(tok) => {
88 if offset >= tok.span.start && offset <= tok.span.end {
89 spans.push((tok.span.start, tok.span.end));
90 }
91 }
92 Expression::Epsilon(tok) => {
93 if offset >= tok.span.start && offset <= tok.span.end {
94 spans.push((tok.span.start, tok.span.end));
95 }
96 }
97 Expression::Alternation(inner) | Expression::Concatenation(inner) => {
98 if offset >= inner.span.start && offset <= inner.span.end {
99 spans.push((inner.span.start, inner.span.end));
100 }
101 for child in get_inner_expression(inner) {
102 collect_spans(child, offset, spans);
103 }
104 }
105 Expression::Group(inner)
106 | Expression::Optional(inner)
107 | Expression::Many(inner)
108 | Expression::Many1(inner)
109 | Expression::OptionalWhitespace(inner) => {
110 if offset >= inner.span.start && offset <= inner.span.end {
111 spans.push((inner.span.start, inner.span.end));
112 }
113 collect_spans(get_inner_expression(inner), offset, spans);
114 }
115 Expression::Skip(l, r) | Expression::Next(l, r) | Expression::Minus(l, r) => {
116 let start = l.span.start;
118 let end = r.span.end;
119 if offset >= start && offset <= end {
120 spans.push((start, end));
121 }
122 collect_spans(get_inner_expression(l), offset, spans);
123 collect_spans(get_inner_expression(r), offset, spans);
124 }
125 Expression::Rule(rhs, _) => {
126 collect_spans(rhs, offset, spans);
127 }
128 Expression::MappedExpression((expr_tok, _)) => {
129 collect_spans(get_inner_expression(expr_tok), offset, spans);
130 }
131 Expression::DebugExpression((expr_tok, _)) => {
132 collect_spans(get_inner_expression(expr_tok), offset, spans);
133 }
134 _ => {}
135 }
136}