1use ls_types::*;
2
3use bbnf::types::{Expression, Token, AST};
4
5fn get_inner_expression<'a, T>(tok: &'a Token<'a, T>) -> &'a T {
7 &tok.value
8}
9
10use crate::state::DocumentState;
11
12const MAX_WIDTH: usize = 66;
13
14pub fn format_document(state: &DocumentState) -> Option<Vec<TextEdit>> {
15 let ast = state.ast()?;
16
17 let formatted = format_ast(ast);
18
19 let end = offset_to_end(&state.text);
21 Some(vec![TextEdit {
22 range: Range::new(Position::new(0, 0), end),
23 new_text: formatted,
24 }])
25}
26
27pub fn format_range(state: &DocumentState, range: Range) -> Option<Vec<TextEdit>> {
29 let ast = state.ast()?;
30
31 let range_start = state.line_index.position_to_offset(range.start);
32 let range_end = state.line_index.position_to_offset(range.end);
33
34 let mut edits = Vec::new();
35
36 for (lhs, rhs) in ast.iter() {
37 if let Expression::Nonterminal(Token { value: name, span: name_span, .. }) = lhs {
38 let rule_start = name_span.start;
39 let rule_end = crate::state::compute_expression_end_pub(rhs)
40 .unwrap_or_else(|| panic!("format_range could not compute expression end for rule `{}`", name));
41
42 if rule_end <= range_start || rule_start >= range_end {
44 continue;
45 }
46
47 let rhs_str = format_expression(rhs, 0);
48 let formatted = format!("{} = {};\n", name, rhs_str);
49
50 let text_after_rule = &state.text[rule_end..];
52 let extra = text_after_rule
53 .find(';')
54 .map(|i| i + 1)
55 .unwrap_or_else(|| panic!("format_range expected `;` terminator for rule `{}`", name));
56 let full_end = rule_end + extra;
57
58 let trailing = state.text[full_end..]
60 .chars()
61 .take_while(|c| c.is_whitespace())
62 .count();
63 let full_end = full_end + trailing;
64
65 let edit_range = state.line_index.span_to_range(rule_start, full_end);
66 edits.push(TextEdit {
67 range: edit_range,
68 new_text: formatted,
69 });
70 }
71 }
72
73 if edits.is_empty() {
74 None
75 } else {
76 Some(edits)
77 }
78}
79
80pub fn format_on_type(state: &DocumentState, position: Position) -> Option<Vec<TextEdit>> {
82 let offset = state.line_index.position_to_offset(position);
83
84 for rule in &state.info.rules {
86 if offset >= rule.full_span.0 && offset <= rule.full_span.1 + 2 {
87 let rule_range = state.line_index.span_to_range(rule.full_span.0, rule.full_span.1);
89 return format_range(state, rule_range);
90 }
91 }
92
93 None
94}
95
96fn offset_to_end(text: &str) -> Position {
97 let mut line: u32 = 0;
98 let mut col: u32 = 0;
99 for byte in text.bytes() {
100 if byte == b'\n' {
101 line += 1;
102 col = 0;
103 } else {
104 col += 1;
105 }
106 }
107 Position::new(line, col)
108}
109
110fn format_ast(ast: &AST<'_>) -> String {
111 let mut lines = Vec::new();
112 for (lhs, rhs) in ast.iter() {
113 if let Expression::Nonterminal(Token { value: name, .. }) = lhs {
114 let rhs_str = format_expression(rhs, 0);
115 let rule_line = format!("{} = {}", name, rhs_str);
116
117 lines.push(format!("{};", rule_line));
119 lines.push(String::new()); }
121 }
122
123 if lines.last().is_some_and(|l| l.is_empty()) {
125 lines.pop();
126 }
127
128 lines.join("\n") + "\n"
129}
130
131fn format_expression(expr: &Expression<'_>, indent_level: usize) -> String {
132 match expr {
133 Expression::Literal(tok) => {
134 let s = &tok.value;
135 if s.contains('"') && !s.contains('\'') {
136 format!("'{}'", s)
137 } else {
138 format!("\"{}\"", s)
139 }
140 }
141 Expression::Nonterminal(tok) => tok.value.to_string(),
142 Expression::Regex(tok) => format!("/{}/", tok.value),
143 Expression::Epsilon(_) => "epsilon".into(),
144 Expression::Group(inner) => {
145 let inner_str = format_expression(get_inner_expression(inner), indent_level + 1);
146 format!("({})", inner_str)
147 }
148 Expression::Optional(inner) => {
149 let inner_str = format_expression(get_inner_expression(inner), indent_level + 1);
150 format!("[{}]", inner_str)
151 }
152 Expression::Many(inner) => {
153 let inner_str = format_expression(get_inner_expression(inner), indent_level + 1);
154 format!("{{{}}}", inner_str)
155 }
156 Expression::Many1(inner) => {
157 let inner_str = format_expression(get_inner_expression(inner), indent_level);
158 format!("{}+", inner_str)
159 }
160 Expression::OptionalWhitespace(inner) => {
161 let inner_str = format_expression(get_inner_expression(inner), indent_level);
162 format!("{}?w", inner_str)
163 }
164 Expression::Skip(l, r) => {
165 format!(
166 "{} << {}",
167 format_expression(get_inner_expression(l), indent_level),
168 format_expression(get_inner_expression(r), indent_level),
169 )
170 }
171 Expression::Next(l, r) => {
172 format!(
173 "{} >> {}",
174 format_expression(get_inner_expression(l), indent_level),
175 format_expression(get_inner_expression(r), indent_level),
176 )
177 }
178 Expression::Minus(l, r) => {
179 format!(
180 "{} - {}",
181 format_expression(get_inner_expression(l), indent_level),
182 format_expression(get_inner_expression(r), indent_level),
183 )
184 }
185 Expression::Concatenation(inner) => {
186 let parts: Vec<String> = get_inner_expression(inner)
187 .iter()
188 .map(|e| format_expression(e, indent_level))
189 .collect();
190 let flat = parts.join(", ");
191 if flat.len() + indent_level * 4 <= MAX_WIDTH {
192 flat
193 } else {
194 let indent = " ".repeat(indent_level + 1);
195 let sep = format!(",\n{}", indent);
196 format!("\n{}{}", indent, parts.join(&sep))
197 }
198 }
199 Expression::Alternation(inner) => {
200 let parts: Vec<String> = get_inner_expression(inner)
201 .iter()
202 .map(|e| format_expression(e, indent_level))
203 .collect();
204 let flat = parts.join(" | ");
205 if flat.len() + indent_level * 4 <= MAX_WIDTH {
206 flat
207 } else {
208 let indent = " ".repeat(indent_level + 1);
209 let sep = format!("\n{}| ", indent);
210 format!("\n{}{}", indent, parts.join(&sep))
211 }
212 }
213 Expression::Rule(rhs, mapping) => {
214 let rhs_str = format_expression(rhs, indent_level);
215 if let Some(m) = mapping {
216 format!("{} {}", rhs_str, format_expression(m, indent_level))
217 } else {
218 rhs_str
219 }
220 }
221 Expression::ProductionRule(lhs, rhs) => {
222 format!(
223 "{} = {}",
224 format_expression(lhs, indent_level),
225 format_expression(rhs, indent_level),
226 )
227 }
228 Expression::MappedExpression((expr_tok, mapping_tok)) => {
229 format!(
230 "{} {}",
231 format_expression(get_inner_expression(expr_tok), indent_level),
232 format_expression(get_inner_expression(mapping_tok), indent_level),
233 )
234 }
235 Expression::DebugExpression((expr_tok, label)) => {
236 format!(
237 "{}#{}",
238 format_expression(get_inner_expression(expr_tok), indent_level),
239 label,
240 )
241 }
242 Expression::MappingFn(tok) => format!("=> {}", tok.value),
243 }
244}