|
| 1 | +#[derive(PartialEq)] |
| 2 | +pub enum Step { |
| 3 | + Comment(String), |
| 4 | + Dedent, |
| 5 | + Format(rnix::SyntaxElement), |
| 6 | + FormatWider(rnix::SyntaxElement), |
| 7 | + Indent, |
| 8 | + NewLine, |
| 9 | + Pad, |
| 10 | + Token(rnix::SyntaxKind, String), |
| 11 | + Whitespace, |
| 12 | +} |
| 13 | + |
| 14 | +#[derive(Clone)] |
| 15 | +pub struct BuildCtx { |
| 16 | + pub config: crate::config::Config, |
| 17 | + pub force_wide: bool, |
| 18 | + pub indentation: usize, |
| 19 | + pub pos_new: crate::position::Position, |
| 20 | + pub pos_old: crate::position::Position, |
| 21 | +} |
| 22 | + |
| 23 | +impl BuildCtx { |
| 24 | + pub fn new( |
| 25 | + config: crate::config::Config, |
| 26 | + force_wide: bool, |
| 27 | + pos_new: crate::position::Position, |
| 28 | + pos_old: crate::position::Position, |
| 29 | + ) -> BuildCtx { |
| 30 | + BuildCtx { config, force_wide, indentation: 0, pos_new, pos_old } |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +pub fn build( |
| 35 | + config: &crate::config::Config, |
| 36 | + element: rnix::SyntaxElement, |
| 37 | + force_wide: bool, |
| 38 | + path: &str, |
| 39 | +) -> Option<rowan::GreenNode> { |
| 40 | + let mut builder = rowan::GreenNodeBuilder::new(); |
| 41 | + let mut build_ctx = BuildCtx::new( |
| 42 | + config.clone(), |
| 43 | + force_wide, |
| 44 | + crate::position::Position::new(), |
| 45 | + crate::position::Position::new(), |
| 46 | + ); |
| 47 | + |
| 48 | + build_step( |
| 49 | + &mut builder, |
| 50 | + &mut build_ctx, |
| 51 | + path, |
| 52 | + &crate::builder::Step::Format(element), |
| 53 | + ); |
| 54 | + |
| 55 | + if build_ctx.force_wide && build_ctx.pos_new.line > 1 { |
| 56 | + None |
| 57 | + } else { |
| 58 | + Some(builder.finish()) |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +fn build_step( |
| 63 | + builder: &mut rowan::GreenNodeBuilder, |
| 64 | + build_ctx: &mut BuildCtx, |
| 65 | + path: &str, |
| 66 | + step: &crate::builder::Step, |
| 67 | +) { |
| 68 | + if build_ctx.force_wide && build_ctx.pos_new.line > 1 { |
| 69 | + return; |
| 70 | + } |
| 71 | + |
| 72 | + match step { |
| 73 | + crate::builder::Step::Comment(text) => { |
| 74 | + add_token( |
| 75 | + builder, |
| 76 | + build_ctx, |
| 77 | + rnix::SyntaxKind::TOKEN_COMMENT, |
| 78 | + text, |
| 79 | + ); |
| 80 | + } |
| 81 | + crate::builder::Step::Dedent => { |
| 82 | + build_ctx.indentation -= 1; |
| 83 | + } |
| 84 | + crate::builder::Step::Format(element) => { |
| 85 | + format(builder, build_ctx, element, path); |
| 86 | + } |
| 87 | + crate::builder::Step::FormatWider(element) => { |
| 88 | + format_wider(builder, build_ctx, element, path); |
| 89 | + } |
| 90 | + crate::builder::Step::Indent => { |
| 91 | + build_ctx.indentation += 1; |
| 92 | + } |
| 93 | + crate::builder::Step::NewLine => { |
| 94 | + add_token( |
| 95 | + builder, |
| 96 | + build_ctx, |
| 97 | + rnix::SyntaxKind::TOKEN_WHITESPACE, |
| 98 | + "\n", |
| 99 | + ); |
| 100 | + } |
| 101 | + crate::builder::Step::Pad => { |
| 102 | + if build_ctx.indentation > 0 { |
| 103 | + add_token( |
| 104 | + builder, |
| 105 | + build_ctx, |
| 106 | + rnix::SyntaxKind::TOKEN_COMMA, |
| 107 | + &format!("{0:<1$}", "", 2 * build_ctx.indentation), |
| 108 | + ); |
| 109 | + } |
| 110 | + } |
| 111 | + crate::builder::Step::Token(kind, text) => { |
| 112 | + add_token(builder, build_ctx, *kind, &text); |
| 113 | + } |
| 114 | + crate::builder::Step::Whitespace => { |
| 115 | + add_token( |
| 116 | + builder, |
| 117 | + build_ctx, |
| 118 | + rnix::SyntaxKind::TOKEN_WHITESPACE, |
| 119 | + " ", |
| 120 | + ); |
| 121 | + } |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +fn add_token( |
| 126 | + builder: &mut rowan::GreenNodeBuilder, |
| 127 | + build_ctx: &mut BuildCtx, |
| 128 | + kind: rnix::SyntaxKind, |
| 129 | + text: &str, |
| 130 | +) { |
| 131 | + builder.token(rowan::SyntaxKind(kind as u16), text); |
| 132 | + build_ctx.pos_new.update(text); |
| 133 | +} |
| 134 | + |
| 135 | +fn format( |
| 136 | + builder: &mut rowan::GreenNodeBuilder, |
| 137 | + build_ctx: &mut BuildCtx, |
| 138 | + element: &rnix::SyntaxElement, |
| 139 | + path: &str, |
| 140 | +) { |
| 141 | + let kind = element.kind(); |
| 142 | + |
| 143 | + match element { |
| 144 | + rnix::SyntaxElement::Node(node) => { |
| 145 | + builder.start_node(rowan::SyntaxKind(kind as u16)); |
| 146 | + |
| 147 | + let rule = match kind { |
| 148 | + rnix::SyntaxKind::NODE_APPLY => crate::rules::apply::rule, |
| 149 | + rnix::SyntaxKind::NODE_ASSERT => crate::rules::assert::rule, |
| 150 | + rnix::SyntaxKind::NODE_ATTR_SET => crate::rules::attr_set::rule, |
| 151 | + rnix::SyntaxKind::NODE_BIN_OP => crate::rules::bin_op::rule, |
| 152 | + rnix::SyntaxKind::NODE_DYNAMIC => crate::rules::dynamic::rule, |
| 153 | + rnix::SyntaxKind::NODE_ERROR => { |
| 154 | + eprintln!("Warning: found an error node at: {}", path); |
| 155 | + crate::rules::default |
| 156 | + } |
| 157 | + rnix::SyntaxKind::NODE_IDENT => crate::rules::default, |
| 158 | + rnix::SyntaxKind::NODE_IF_ELSE => crate::rules::if_else::rule, |
| 159 | + rnix::SyntaxKind::NODE_INHERIT => crate::rules::inherit::rule, |
| 160 | + rnix::SyntaxKind::NODE_INHERIT_FROM => { |
| 161 | + crate::rules::inherit_from::rule |
| 162 | + } |
| 163 | + rnix::SyntaxKind::NODE_KEY => crate::rules::default, |
| 164 | + rnix::SyntaxKind::NODE_KEY_VALUE => { |
| 165 | + crate::rules::key_value::rule |
| 166 | + } |
| 167 | + rnix::SyntaxKind::NODE_LAMBDA => crate::rules::lambda::rule, |
| 168 | + rnix::SyntaxKind::NODE_LET_IN => crate::rules::let_in::rule, |
| 169 | + rnix::SyntaxKind::NODE_LIST => crate::rules::list::rule, |
| 170 | + rnix::SyntaxKind::NODE_LITERAL => crate::rules::default, |
| 171 | + rnix::SyntaxKind::NODE_LEGACY_LET => { |
| 172 | + eprintln!( |
| 173 | + "Warning: found a `legacy let` expression at: {}", |
| 174 | + path |
| 175 | + ); |
| 176 | + crate::rules::default |
| 177 | + } |
| 178 | + rnix::SyntaxKind::NODE_OR_DEFAULT => { |
| 179 | + crate::rules::or_default::rule |
| 180 | + } |
| 181 | + rnix::SyntaxKind::NODE_PAREN => crate::rules::paren::rule, |
| 182 | + rnix::SyntaxKind::NODE_PAT_BIND => crate::rules::pat_bind::rule, |
| 183 | + rnix::SyntaxKind::NODE_PATTERN => crate::rules::pattern::rule, |
| 184 | + rnix::SyntaxKind::NODE_PAT_ENTRY => { |
| 185 | + crate::rules::pat_entry::rule |
| 186 | + } |
| 187 | + rnix::SyntaxKind::NODE_PATH_WITH_INTERPOL => { |
| 188 | + crate::rules::default |
| 189 | + } |
| 190 | + rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule, |
| 191 | + rnix::SyntaxKind::NODE_SELECT => crate::rules::select::rule, |
| 192 | + rnix::SyntaxKind::NODE_STRING => crate::rules::default, |
| 193 | + rnix::SyntaxKind::NODE_STRING_INTERPOL => { |
| 194 | + crate::rules::string_interpol::rule |
| 195 | + } |
| 196 | + rnix::SyntaxKind::NODE_UNARY_OP => crate::rules::default, |
| 197 | + rnix::SyntaxKind::NODE_WITH => crate::rules::with::rule, |
| 198 | + kind => { |
| 199 | + panic!("Missing rule for {:?} at: {}", kind, path); |
| 200 | + } |
| 201 | + }; |
| 202 | + |
| 203 | + for step in rule(build_ctx, node) { |
| 204 | + build_step(builder, build_ctx, path, &step); |
| 205 | + } |
| 206 | + |
| 207 | + builder.finish_node(); |
| 208 | + } |
| 209 | + rnix::SyntaxElement::Token(token) => { |
| 210 | + add_token(builder, build_ctx, kind, token.text()); |
| 211 | + build_ctx.pos_old.update(token.text()); |
| 212 | + } |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +fn format_wider( |
| 217 | + builder: &mut rowan::GreenNodeBuilder, |
| 218 | + build_ctx: &mut BuildCtx, |
| 219 | + element: &rnix::SyntaxElement, |
| 220 | + path: &str, |
| 221 | +) { |
| 222 | + match element { |
| 223 | + rnix::SyntaxElement::Node(node) => { |
| 224 | + let maybe_green_node = build( |
| 225 | + &build_ctx.config.with_layout(crate::config::Layout::Wide), |
| 226 | + node.clone().into(), |
| 227 | + true, |
| 228 | + path, |
| 229 | + ); |
| 230 | + |
| 231 | + let layout = match maybe_green_node { |
| 232 | + Some(finished) => { |
| 233 | + if build_ctx.pos_new.column |
| 234 | + + finished.to_string().chars().count() |
| 235 | + > build_ctx.config.max_width() |
| 236 | + { |
| 237 | + crate::config::Layout::Tall |
| 238 | + } else { |
| 239 | + crate::config::Layout::Wide |
| 240 | + } |
| 241 | + } |
| 242 | + None => crate::config::Layout::Tall, |
| 243 | + }; |
| 244 | + |
| 245 | + let mut build_ctx_clone = build_ctx.clone(); |
| 246 | + build_ctx_clone.config = build_ctx.config.with_layout(layout); |
| 247 | + format(builder, &mut build_ctx_clone, element, path); |
| 248 | + } |
| 249 | + rnix::SyntaxElement::Token(_) => { |
| 250 | + format(builder, build_ctx, element, path); |
| 251 | + } |
| 252 | + }; |
| 253 | +} |
0 commit comments