1use std::ops::Range;
2
3use typst_syntax::{
4 ast::{Expr, Markup, Pattern},
5 LinkedNode, Source, Span, SyntaxKind,
6};
7
8use crate::{
9 pretty::{Context, Mode},
10 utils, AttrStore, Error, PrettyPrinter, Typstyle,
11};
12
13impl Typstyle {
14 pub fn format_source_range(
16 &self,
17 source: &Source,
18 utf8_range: Range<usize>,
19 ) -> Result<(Range<usize>, String), Error> {
20 let range = utils::trim_range(source.text(), utf8_range);
22
23 let Some((node, mode)) =
24 get_node_cover_range(source, range.clone()).filter(|(node, _)| !node.erroneous())
25 else {
26 return Err(Error::SyntaxError);
27 };
28
29 let attrs = AttrStore::new(node.get()); let printer = PrettyPrinter::new(self.config.clone(), attrs);
31 let ctx = Context::default().with_mode(mode);
32 let doc = if let Some(markup) = node.cast() {
33 printer.convert_markup(ctx, markup)
34 } else if let Some(expr) = node.cast() {
35 printer.convert_expr(ctx, expr)
36 } else if let Some(pattern) = node.cast() {
37 printer.convert_pattern(ctx, pattern)
38 } else {
39 return Err(Error::SyntaxError);
40 };
41 let indent = utils::count_spaces_after_last_newline(source.text(), range.start);
43 let res = doc
44 .nest(indent as isize)
45 .pretty(self.config.max_width)
46 .to_string();
47 Ok((node.range(), res))
48 }
49}
50
51fn get_node_cover_range(source: &Source, range: Range<usize>) -> Option<(LinkedNode, Mode)> {
53 let range = range.start..range.end.min(source.len_bytes());
54 get_node_cover_range_impl(range, LinkedNode::new(source.root()), Mode::Markup)
55 .and_then(|(span, mode)| source.find(span).map(|node| (node, mode)))
56}
57
58fn get_node_cover_range_impl(
59 range: Range<usize>,
60 node: LinkedNode<'_>,
61 mode: Mode,
62) -> Option<(Span, Mode)> {
63 let mode = match node.kind() {
64 SyntaxKind::Markup => Mode::Markup,
65 SyntaxKind::CodeBlock => Mode::Code,
66 SyntaxKind::Equation => Mode::Math,
67 _ => mode,
68 };
69 for child in node.children() {
70 if let Some(res) = get_node_cover_range_impl(range.clone(), child, mode) {
71 return Some(res);
72 }
73 }
74 let node_range = node.range();
75 (node_range.start <= range.start
76 && node_range.end >= range.end
77 && (node.is::<Markup>() || node.is::<Expr>() || node.is::<Pattern>()))
78 .then(|| (node.span(), mode))
79 }