1 //! Utilities for formatting macro expanded nodes until we get a proper formatter.
7 SyntaxNode, SyntaxToken, WalkEvent, T,
10 // FIXME: It would also be cool to share logic here and in the mbe tests,
11 // which are pretty unreadable at the moment.
12 /// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them.
13 pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
15 let mut last: Option<SyntaxKind> = None;
16 let mut mods = Vec::new();
17 let syn = syn.clone_subtree().clone_for_update();
19 let before = Position::before;
20 let after = Position::after;
22 let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| {
23 (pos(token.clone()), make::tokens::whitespace(&" ".repeat(2 * indent)))
25 let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| {
26 (pos(token.clone()), make::tokens::single_space())
28 let do_nl = |pos: fn(_) -> Position, token: &SyntaxToken| {
29 (pos(token.clone()), make::tokens::single_newline())
32 for event in syn.preorder_with_tokens() {
33 let token = match event {
34 WalkEvent::Enter(NodeOrToken::Token(token)) => token,
35 WalkEvent::Leave(NodeOrToken::Node(node))
36 if matches!(node.kind(), ATTR | MATCH_ARM | STRUCT | ENUM | UNION | FN | IMPL) =>
40 Position::after(node.clone()),
41 make::tokens::whitespace(&" ".repeat(2 * indent)),
44 if node.parent().is_some() {
45 mods.push((Position::after(node), make::tokens::single_newline()));
53 let is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
54 tok.next_token().map(|it| f(it.kind())).unwrap_or(default)
57 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
60 k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
61 mods.push(do_ws(after, tok));
63 L_CURLY if is_next(|it| it != R_CURLY, true) => {
65 if is_last(is_text, false) {
66 mods.push(do_ws(before, tok));
70 mods.push(do_indent(after, tok, indent));
72 mods.push(do_nl(after, &tok));
74 R_CURLY if is_last(|it| it != L_CURLY, true) => {
75 indent = indent.saturating_sub(1);
78 mods.push(do_indent(before, tok, indent));
80 mods.push(do_nl(before, tok));
84 mods.push(do_indent(after, tok, indent));
86 mods.push(do_nl(after, tok));
88 LIFETIME_IDENT if is_next(|it| is_text(it), true) => {
89 mods.push(do_ws(after, tok));
92 mods.push(do_ws(after, tok));
96 mods.push(do_indent(after, tok, indent));
98 mods.push(do_nl(after, tok));
100 T![->] | T![=] | T![=>] => {
101 mods.push(do_ws(before, tok));
102 mods.push(do_ws(after, tok));
107 last = Some(tok.kind());
110 for (pos, insert) in mods {
111 ted::insert(pos, insert);
117 fn is_text(k: SyntaxKind) -> bool {
118 k.is_keyword() || k.is_literal() || k == IDENT