diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5baca40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/result* +/target/ +/tarpaulin* diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2b473ad --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[dependencies] + clap = "3" + rnix = "0.10" + rowan = "0.15" + walkdir = "2" + +[dev-dependencies] + indoc = "*" + +[package] + authors = ["Kevin Amado "] + description = "The uncompromising Nix formatter" + edition = "2021" + name = "alejandra" + repository = "https://github.com/kamadorueda/alejandra" + version = "0.1.0" diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4d72307 --- /dev/null +++ b/flake.nix @@ -0,0 +1,81 @@ +{ + inputs = + { + flakeUtils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + }; + outputs = + inputs: + inputs.flakeUtils.lib.eachDefaultSystem + ( + system: + let + nixpkgs = import inputs.nixpkgs { inherit system; }; + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + in + { + checks = + { + defaultPackage = inputs.self.defaultPackage.${ system }; + inherit (inputs.self.packages.${ system }) nixpkgsFormatted; + }; + defaultApp = + { + type = "app"; + program = + "${ inputs.self.defaultPackage.${ system } }/bin/alejandra"; + }; + defaultPackage = + nixpkgs.rustPlatform.buildRustPackage + { + pname = cargoToml.package.name; + version = cargoToml.package.version; + src = inputs.self.sourceInfo; + cargoLock.lockFile = ./Cargo.lock; + NIX_BUILD_CORES = 0; + meta = + { + description = inputs.self.description; + homepage = "https://github.com/kamadorueda/alejandra"; + license = nixpkgs.lib.licenses.mit; + maintainers = [ nixpkgs.lib.maintainers.kamadorueda ]; + }; + }; + devShell = + nixpkgs.mkShell + { + packages = [ nixpkgs.cargo-tarpaulin nixpkgs.rustup ]; + shellHook = + '' + rustup toolchain install nightly + ''; + }; + packages = + { + nixpkgsFormatted = + nixpkgs.stdenv.mkDerivation + { + name = "nixpkgs-formatted"; + builder = + builtins.toFile + "builder.sh" + '' + source $stdenv/setup + + cp -rT $nixpkgs $out + chmod -R +w $out + + alejandra $out + + git diff --no-index $nixpkgs $out > $diff || true + ''; + buildInputs = + [ inputs.self.defaultPackage.${ system } nixpkgs.git ]; + nixpkgs = inputs.nixpkgs.sourceInfo.outPath; + NIX_BUILD_CORES = 0; + outputs = [ "diff" "out" ]; + }; + }; + } + ); +} diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..4362e9f --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,253 @@ +#[derive(PartialEq)] +pub enum Step { + Comment(String), + Dedent, + Format(rnix::SyntaxElement), + FormatWider(rnix::SyntaxElement), + Indent, + NewLine, + Pad, + Token(rnix::SyntaxKind, String), + Whitespace, +} + +#[derive(Clone)] +pub struct BuildCtx { + pub config: crate::config::Config, + pub force_wide: bool, + pub indentation: usize, + pub pos_new: crate::position::Position, + pub pos_old: crate::position::Position, +} + +impl BuildCtx { + pub fn new( + config: crate::config::Config, + force_wide: bool, + pos_new: crate::position::Position, + pos_old: crate::position::Position, + ) -> BuildCtx { + BuildCtx { config, force_wide, indentation: 0, pos_new, pos_old } + } +} + +pub fn build( + config: &crate::config::Config, + element: rnix::SyntaxElement, + force_wide: bool, + path: &str, +) -> Option { + let mut builder = rowan::GreenNodeBuilder::new(); + let mut build_ctx = BuildCtx::new( + config.clone(), + force_wide, + crate::position::Position::new(), + crate::position::Position::new(), + ); + + build_step( + &mut builder, + &mut build_ctx, + path, + &crate::builder::Step::Format(element), + ); + + if build_ctx.force_wide && build_ctx.pos_new.line > 1 { + None + } else { + Some(builder.finish()) + } +} + +fn build_step( + builder: &mut rowan::GreenNodeBuilder, + build_ctx: &mut BuildCtx, + path: &str, + step: &crate::builder::Step, +) { + if build_ctx.force_wide && build_ctx.pos_new.line > 1 { + return; + } + + match step { + crate::builder::Step::Comment(text) => { + add_token( + builder, + build_ctx, + rnix::SyntaxKind::TOKEN_COMMENT, + text, + ); + } + crate::builder::Step::Dedent => { + build_ctx.indentation -= 1; + } + crate::builder::Step::Format(element) => { + format(builder, build_ctx, element, path); + } + crate::builder::Step::FormatWider(element) => { + format_wider(builder, build_ctx, element, path); + } + crate::builder::Step::Indent => { + build_ctx.indentation += 1; + } + crate::builder::Step::NewLine => { + add_token( + builder, + build_ctx, + rnix::SyntaxKind::TOKEN_WHITESPACE, + "\n", + ); + } + crate::builder::Step::Pad => { + if build_ctx.indentation > 0 { + add_token( + builder, + build_ctx, + rnix::SyntaxKind::TOKEN_COMMA, + &format!("{0:<1$}", "", 2 * build_ctx.indentation), + ); + } + } + crate::builder::Step::Token(kind, text) => { + add_token(builder, build_ctx, *kind, &text); + } + crate::builder::Step::Whitespace => { + add_token( + builder, + build_ctx, + rnix::SyntaxKind::TOKEN_WHITESPACE, + " ", + ); + } + } +} + +fn add_token( + builder: &mut rowan::GreenNodeBuilder, + build_ctx: &mut BuildCtx, + kind: rnix::SyntaxKind, + text: &str, +) { + builder.token(rowan::SyntaxKind(kind as u16), text); + build_ctx.pos_new.update(text); +} + +fn format( + builder: &mut rowan::GreenNodeBuilder, + build_ctx: &mut BuildCtx, + element: &rnix::SyntaxElement, + path: &str, +) { + let kind = element.kind(); + + match element { + rnix::SyntaxElement::Node(node) => { + builder.start_node(rowan::SyntaxKind(kind as u16)); + + let rule = match kind { + rnix::SyntaxKind::NODE_APPLY => crate::rules::apply::rule, + rnix::SyntaxKind::NODE_ASSERT => crate::rules::assert::rule, + rnix::SyntaxKind::NODE_ATTR_SET => crate::rules::attr_set::rule, + rnix::SyntaxKind::NODE_BIN_OP => crate::rules::bin_op::rule, + rnix::SyntaxKind::NODE_DYNAMIC => crate::rules::dynamic::rule, + rnix::SyntaxKind::NODE_ERROR => { + eprintln!("Warning: found an error node at: {}", path); + crate::rules::default + } + rnix::SyntaxKind::NODE_IDENT => crate::rules::default, + rnix::SyntaxKind::NODE_IF_ELSE => crate::rules::if_else::rule, + rnix::SyntaxKind::NODE_INHERIT => crate::rules::inherit::rule, + rnix::SyntaxKind::NODE_INHERIT_FROM => { + crate::rules::inherit_from::rule + } + rnix::SyntaxKind::NODE_KEY => crate::rules::default, + rnix::SyntaxKind::NODE_KEY_VALUE => { + crate::rules::key_value::rule + } + rnix::SyntaxKind::NODE_LAMBDA => crate::rules::lambda::rule, + rnix::SyntaxKind::NODE_LET_IN => crate::rules::let_in::rule, + rnix::SyntaxKind::NODE_LIST => crate::rules::list::rule, + rnix::SyntaxKind::NODE_LITERAL => crate::rules::default, + rnix::SyntaxKind::NODE_LEGACY_LET => { + eprintln!( + "Warning: found a `legacy let` expression at: {}", + path + ); + crate::rules::default + } + rnix::SyntaxKind::NODE_OR_DEFAULT => { + crate::rules::or_default::rule + } + rnix::SyntaxKind::NODE_PAREN => crate::rules::paren::rule, + rnix::SyntaxKind::NODE_PAT_BIND => crate::rules::pat_bind::rule, + rnix::SyntaxKind::NODE_PATTERN => crate::rules::pattern::rule, + rnix::SyntaxKind::NODE_PAT_ENTRY => { + crate::rules::pat_entry::rule + } + rnix::SyntaxKind::NODE_PATH_WITH_INTERPOL => { + crate::rules::default + } + rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule, + rnix::SyntaxKind::NODE_SELECT => crate::rules::select::rule, + rnix::SyntaxKind::NODE_STRING => crate::rules::default, + rnix::SyntaxKind::NODE_STRING_INTERPOL => { + crate::rules::string_interpol::rule + } + rnix::SyntaxKind::NODE_UNARY_OP => crate::rules::default, + rnix::SyntaxKind::NODE_WITH => crate::rules::with::rule, + kind => { + panic!("Missing rule for {:?} at: {}", kind, path); + } + }; + + for step in rule(build_ctx, node) { + build_step(builder, build_ctx, path, &step); + } + + builder.finish_node(); + } + rnix::SyntaxElement::Token(token) => { + add_token(builder, build_ctx, kind, token.text()); + build_ctx.pos_old.update(token.text()); + } + } +} + +fn format_wider( + builder: &mut rowan::GreenNodeBuilder, + build_ctx: &mut BuildCtx, + element: &rnix::SyntaxElement, + path: &str, +) { + match element { + rnix::SyntaxElement::Node(node) => { + let maybe_green_node = build( + &build_ctx.config.with_layout(crate::config::Layout::Wide), + node.clone().into(), + true, + path, + ); + + let layout = match maybe_green_node { + Some(finished) => { + if build_ctx.pos_new.column + + finished.to_string().chars().count() + > build_ctx.config.max_width() + { + crate::config::Layout::Tall + } else { + crate::config::Layout::Wide + } + } + None => crate::config::Layout::Tall, + }; + + let mut build_ctx_clone = build_ctx.clone(); + build_ctx_clone.config = build_ctx.config.with_layout(layout); + format(builder, &mut build_ctx_clone, element, path); + } + rnix::SyntaxElement::Token(_) => { + format(builder, build_ctx, element, path); + } + }; +} diff --git a/src/children.rs b/src/children.rs new file mode 100644 index 0000000..f0ee139 --- /dev/null +++ b/src/children.rs @@ -0,0 +1,193 @@ +#[derive(Clone)] +pub struct Child { + pub element: rnix::SyntaxElement, + pub pos: crate::position::Position, +} + +pub struct Children { + children: Vec, + current_index: usize, +} + +impl Children { + pub fn new( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, + ) -> Children { + let mut children = Vec::new(); + + let mut pos = build_ctx.pos_old.clone(); + + for child in node.children_with_tokens() { + match child { + rnix::SyntaxElement::Node(_) => { + children + .push(Child { element: child, pos: pos.clone() }); + } + rnix::SyntaxElement::Token(token) => { + match token.kind() { + rnix::SyntaxKind::TOKEN_WHITESPACE => {} + _ => { + children.push(Child { + element: token.clone().into(), + pos: pos.clone(), + }); + } + } + + pos.update(token.text()); + } + } + } + + Children { children, current_index: 0 } + } + + pub fn count(&self) -> usize { + self.children.len() + } + + pub fn current_index(&self) -> usize { + self.current_index + } + + pub fn get(&mut self, index: usize) -> Option { + if index + 1 > self.children.len() { + None + } else { + Some(self.children[index].clone()) + } + } + + pub fn get_next(&mut self) -> Option { + let child = self.get(self.current_index); + self.move_next(); + child + } + + pub fn has_next(&self) -> bool { + self.current_index < self.children.len() + } + + pub fn peek_next(&mut self) -> Option { + self.get(self.current_index) + } + + pub fn peek_prev(&mut self) -> Option { + if self.current_index >= 1 { + self.get(self.current_index - 1) + } else { + None + } + } + + pub fn move_next(&mut self) { + self.current_index += 1 + } + + pub fn move_prev(&mut self) { + self.current_index -= 1 + } + + pub fn has_comments(&self) -> bool { + self.children.iter().any(|child| { + child.element.kind() == rnix::SyntaxKind::TOKEN_COMMENT + }) + } + + pub fn drain_comment(&mut self, mut callback: F) { + if let Some(child) = self.peek_next() { + match child.element.kind() { + rnix::SyntaxKind::TOKEN_COMMENT => { + callback(dedent_comment( + &child.pos, + child.element.into_token().unwrap().text(), + )); + self.move_next(); + } + _ => {} + } + } + } + + pub fn drain_comments(&mut self, mut callback: F) { + while let Some(child) = self.peek_next() { + match child.element.kind() { + rnix::SyntaxKind::TOKEN_COMMENT => { + callback(dedent_comment( + &child.pos, + child.element.into_token().unwrap().text(), + )); + self.move_next(); + } + _ => { + break; + } + } + } + } +} + +fn dedent_comment(pos: &crate::position::Position, text: &str) -> String { + if text.starts_with("#") { + text.to_string() + } else { + let text = text[2..text.len() - 2] + .lines() + .enumerate() + .map(|(index, line)| { + if index > 0 { + line.chars() + .skip(if pos.column >= 1 { pos.column - 1 } else { 0 }) + .collect::() + } else { + line.to_string() + } + }) + .collect::>() + .join("\n"); + + format!("/*{}*/", text) + } +} + +// fn dedent_string( +// pos: &crate::position::Position, +// node: &rnix::SyntaxNode, +// ) -> String { +// eprintln!("{}", text); +// if text.starts_with("\"") { +// text.to_string() +// } else { +// node.children_with_tokens().filter(|child| { +// child.kind() == rnix::SyntaxKind::TOKEN_STRING_CONTENT +// }).map(|child| { +// let lines = child.into_token().unwrap().lines(); +// "" +// " rustup toolchain install nightly" +// " " +// "" +// " " +// }); + +// // let padding_to_first_char = lines +// // TOKEN_STRING_CONTENT + +// let text = text[2..text.len() - 2] +// .lines() +// .enumerate() +// .map(|(index, line)| { +// if index > 0 { +// line.chars() +// .skip(if pos.column >= 1 { pos.column - 1 } else { 0 }) +// .collect::() +// } else { +// line.to_string() +// } +// }) +// .collect::>() +// .join("\n"); + +// format!("/*{}*/", text) +// } +// } diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..c661941 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,27 @@ +pub fn parse(args: Vec) -> clap::ArgMatches { + clap::App::new("alejandra") + .version("v0.1.0") + .about("The uncompromising Nix formatter.") + .arg( + clap::Arg::new("debug") + .help("Enable debug mode.") + .long("debug") + .short('d') + .takes_value(false), + ) + .arg( + clap::Arg::new("max-width") + .default_value("120") + .help("How many characters per line to allow.") + .long("max-width") + .takes_value(true) + .value_name("CHARS"), + ) + .arg( + clap::Arg::new("paths") + .help("Files or directories, or none to format stdin.") + .multiple_values(true), + ) + .term_width(80) + .get_matches_from(args) +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..326be5a --- /dev/null +++ b/src/config.rs @@ -0,0 +1,42 @@ +#[derive(Clone)] +pub enum Layout { + Tall, + Wide, +} + +#[derive(Clone)] +pub struct Config { + debug: bool, + layout: Layout, + max_width: usize, +} + +impl Config { + pub fn new() -> Config { + Config { debug: false, layout: Layout::Tall, max_width: 80 } + } + + pub fn debug(&self) -> bool { + self.debug + } + + pub fn layout(&self) -> &Layout { + &self.layout + } + + pub fn max_width(&self) -> usize { + self.max_width + } + + pub fn with_debug(&self, debug: bool) -> Config { + Config { debug, layout: self.layout.clone(), max_width: self.max_width } + } + + pub fn with_layout(&self, layout: Layout) -> Config { + Config { debug: self.debug, layout, max_width: self.max_width } + } + + pub fn with_max_width(&self, max_width: usize) -> Config { + Config { debug: self.debug, layout: self.layout.clone(), max_width } + } +} diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..2e47842 --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,27 @@ +pub fn display( + element: &rowan::NodeOrToken<&rowan::GreenNodeData, &rowan::GreenTokenData>, +) { + eprintln!("AST:"); + display_recursive(element, 2); +} + +fn display_recursive( + element: &rowan::NodeOrToken<&rowan::GreenNodeData, &rowan::GreenTokenData>, + depth: usize, +) { + let kind = unsafe { + std::mem::transmute::(element.kind().0) + }; + + match element { + rowan::NodeOrToken::Node(node) => { + eprintln!("{0:<1$}{2:?}", "", 2 * depth, kind); + for child in node.children() { + display_recursive(&child, depth + 1); + } + } + rowan::NodeOrToken::Token(token) => { + eprintln!("{0:<1$}{2:?} {3:?}", "", 2 * depth, kind, token.text()); + } + } +} diff --git a/src/find.rs b/src/find.rs new file mode 100644 index 0000000..775eab6 --- /dev/null +++ b/src/find.rs @@ -0,0 +1,29 @@ +pub fn nix_files(paths: Vec<&str>) -> Vec { + paths.iter().flat_map(nix_files_in_path).collect() +} + +fn nix_files_in_path(path: &&str) -> Vec { + walkdir::WalkDir::new(path) + .into_iter() + .filter_entry(is_nix_file_or_dir) + .filter_map(|entry| match entry { + Ok(entry) => Some(entry), + Err(_) => None, + }) + .filter(is_nix_file) + .map(to_full_path) + .collect() +} + +fn is_nix_file(entry: &walkdir::DirEntry) -> bool { + entry.file_type().is_file() + && entry.file_name().to_str().unwrap().ends_with(".nix") +} + +fn is_nix_file_or_dir(entry: &walkdir::DirEntry) -> bool { + entry.file_type().is_dir() || is_nix_file(entry) +} + +fn to_full_path(entry: walkdir::DirEntry) -> String { + entry.path().to_str().unwrap().to_string() +} diff --git a/src/format.rs b/src/format.rs new file mode 100644 index 0000000..36e99a5 --- /dev/null +++ b/src/format.rs @@ -0,0 +1,32 @@ +pub fn string( + config: &crate::config::Config, + path: &str, + string: String, +) -> String { + let tokens = rnix::tokenizer::Tokenizer::new(&string); + let ast = rnix::parser::parse(tokens); + + for error in ast.errors() { + eprintln!("Warning: parsing error: {}, at: {}", error, path); + } + + let green_node = + crate::builder::build(config, ast.node().into(), false, path).unwrap(); + + if config.debug() { + crate::debug::display(&(&green_node).into()); + } + + green_node.to_string() +} + +pub fn file(config: &crate::config::Config, path: &str) -> std::io::Result<()> { + use std::io::Write; + + let input = std::fs::read_to_string(path)?; + let output = crate::format::string(config, path, input); + + std::fs::File::create(path)?.write_all(output.as_bytes())?; + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..474252e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +pub mod builder; +pub mod children; +pub mod cli; +pub mod config; +pub mod debug; +pub mod find; +pub mod format; +pub mod position; +pub mod rules; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1e7713f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,33 @@ +use std::io::Read; + +fn main() -> std::io::Result<()> { + let matches = alejandra::cli::parse(std::env::args().collect()); + + let debug: bool = matches.is_present("debug"); + let max_width: usize = + matches.value_of("max-width").unwrap().parse().unwrap(); + + let config = alejandra::config::Config::new() + .with_debug(debug) + .with_max_width(max_width); + + match matches.values_of("paths") { + Some(paths) => { + let paths: Vec = + alejandra::find::nix_files(paths.collect()); + + eprintln!("Formatting {} files.", paths.len()); + for path in paths { + alejandra::format::file(&config, &path)?; + } + } + None => { + eprintln!("Formatting stdin."); + let mut stdin = String::new(); + std::io::stdin().read_to_string(&mut stdin).unwrap(); + print!("{}", alejandra::format::string(&config, "stdin", stdin)); + } + } + + std::process::exit(0); +} diff --git a/src/position.rs b/src/position.rs new file mode 100644 index 0000000..1be2414 --- /dev/null +++ b/src/position.rs @@ -0,0 +1,24 @@ +#[derive(Clone, Debug)] +pub struct Position { + pub column: usize, + pub line: usize, +} + +impl Position { + pub fn new() -> Position { + Position { column: 0, line: 1 } + } + + pub fn update(&mut self, text: &str) { + let chars: Vec = text.chars().collect(); + let newlines = chars.iter().filter(|&c| *c == '\n').count(); + self.line += newlines; + if newlines > 0 { + self.column = 0 + } + self.column += match chars.iter().rposition(|c| *c == '\n') { + Some(pos) => chars.len() - pos, + None => chars.len(), + }; + } +} diff --git a/src/rules/apply.rs b/src/rules/apply.rs new file mode 100644 index 0000000..9efd0dd --- /dev/null +++ b/src/rules/apply.rs @@ -0,0 +1,57 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + match child.element.kind() { + rnix::SyntaxKind::NODE_APPLY => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + _ => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + } + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + steps.push_back(crate::builder::Step::Whitespace); + } + } + + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/assert.rs b/src/rules/assert.rs new file mode 100644 index 0000000..c227c1e --- /dev/null +++ b/src/rules/assert.rs @@ -0,0 +1,72 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // assert + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // ; + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/attr_set.rs b/src/rules/attr_set.rs new file mode 100644 index 0000000..3dba837 --- /dev/null +++ b/src/rules/attr_set.rs @@ -0,0 +1,86 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // { + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => {} + } + + loop { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let Some(child) = children.peek_next() { + let kind = child.element.kind(); + + if let rnix::SyntaxKind::TOKEN_COMMENT + | rnix::SyntaxKind::TOKEN_CURLY_B_CLOSE = kind + { + break; + } + + // item + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + + children.move_next(); + } else { + break; + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // } + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/bin_op.rs b/src/rules/bin_op.rs new file mode 100644 index 0000000..74849cf --- /dev/null +++ b/src/rules/bin_op.rs @@ -0,0 +1,85 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + match child.element.kind() { + rnix::SyntaxKind::NODE_BIN_OP => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + _ => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + } + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // operator + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => {} + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/dynamic.rs b/src/rules/dynamic.rs new file mode 100644 index 0000000..c4cf3a1 --- /dev/null +++ b/src/rules/dynamic.rs @@ -0,0 +1,69 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // ${ + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // } + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/if_else.rs b/src/rules/if_else.rs new file mode 100644 index 0000000..57e9002 --- /dev/null +++ b/src/rules/if_else.rs @@ -0,0 +1,69 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + for branch in ["if", "then", "else"] { + // if/then/else + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + if branch != "else" { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + if branch != "else" { + steps.push_back(crate::builder::Step::Whitespace); + } + } + } + + if branch != "else" { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + } + } + + steps +} diff --git a/src/rules/inherit.rs b/src/rules/inherit.rs new file mode 100644 index 0000000..3dc3582 --- /dev/null +++ b/src/rules/inherit.rs @@ -0,0 +1,89 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // inherit + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => {} + } + + loop { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let Some(child) = children.peek_next() { + let kind = child.element.kind(); + + if let rnix::SyntaxKind::TOKEN_COMMENT + | rnix::SyntaxKind::TOKEN_SEMICOLON = kind + { + break; + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + } else { + break; + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + } + + // ; + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => {} + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/inherit_from.rs b/src/rules/inherit_from.rs new file mode 100644 index 0000000..298c1fe --- /dev/null +++ b/src/rules/inherit_from.rs @@ -0,0 +1,64 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/key_value.rs b/src/rules/key_value.rs new file mode 100644 index 0000000..06f710f --- /dev/null +++ b/src/rules/key_value.rs @@ -0,0 +1,99 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // a + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // = + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // b + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + // ; + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => {} + } + + steps +} diff --git a/src/rules/lambda.rs b/src/rules/lambda.rs new file mode 100644 index 0000000..0f782ff --- /dev/null +++ b/src/rules/lambda.rs @@ -0,0 +1,66 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // a + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_next().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // : + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + steps.push_back(crate::builder::Step::Whitespace); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // c + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/let_in.rs b/src/rules/let_in.rs new file mode 100644 index 0000000..6c472fc --- /dev/null +++ b/src/rules/let_in.rs @@ -0,0 +1,106 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // let + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => {} + } + + loop { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let Some(child) = children.peek_next() { + let kind = child.element.kind(); + + if let rnix::SyntaxKind::TOKEN_COMMENT + | rnix::SyntaxKind::TOKEN_IN = kind + { + break; + } + + // expr + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + + children.move_next(); + } else { + break; + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // in + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/list.rs b/src/rules/list.rs new file mode 100644 index 0000000..9625851 --- /dev/null +++ b/src/rules/list.rs @@ -0,0 +1,86 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // [ + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => {} + } + + loop { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let Some(child) = children.peek_next() { + let kind = child.element.kind(); + + if let rnix::SyntaxKind::TOKEN_COMMENT + | rnix::SyntaxKind::TOKEN_SQUARE_B_CLOSE = kind + { + break; + } + + // item + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + + children.move_next(); + } else { + break; + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // ] + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/mod.rs b/src/rules/mod.rs new file mode 100644 index 0000000..e988d96 --- /dev/null +++ b/src/rules/mod.rs @@ -0,0 +1,43 @@ +pub mod apply; +pub mod assert; +pub mod attr_set; +pub mod bin_op; +pub mod dynamic; +pub mod if_else; +pub mod inherit; +pub mod inherit_from; +pub mod key_value; +pub mod lambda; +pub mod let_in; +pub mod list; +pub mod or_default; +pub mod paren; +pub mod pat_bind; +pub mod pat_entry; +pub mod pattern; +pub mod root; +pub mod select; +pub mod string; +pub mod string_interpol; +pub mod with; + +pub fn default( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + while let Some(child) = children.get_next() { + let step = match build_ctx.config.layout() { + crate::config::Layout::Tall => { + crate::builder::Step::FormatWider(child.element) + } + _ => crate::builder::Step::Format(child.element), + }; + steps.push_back(step); + } + + steps +} diff --git a/src/rules/or_default.rs b/src/rules/or_default.rs new file mode 100644 index 0000000..bda7296 --- /dev/null +++ b/src/rules/or_default.rs @@ -0,0 +1,86 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + match child.element.kind() { + rnix::SyntaxKind::NODE_OR_DEFAULT => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + _ => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + } + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // operator + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/paren.rs b/src/rules/paren.rs new file mode 100644 index 0000000..298c1fe --- /dev/null +++ b/src/rules/paren.rs @@ -0,0 +1,64 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/pat_bind.rs b/src/rules/pat_bind.rs new file mode 100644 index 0000000..6aa59f8 --- /dev/null +++ b/src/rules/pat_bind.rs @@ -0,0 +1,53 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + children.move_prev(); + + steps +} diff --git a/src/rules/pat_entry.rs b/src/rules/pat_entry.rs new file mode 100644 index 0000000..7be2366 --- /dev/null +++ b/src/rules/pat_entry.rs @@ -0,0 +1,90 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + match child.element.kind() { + rnix::SyntaxKind::NODE_OR_DEFAULT => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + _ => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + } + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + if children.has_next() { + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // operator + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + } + + steps +} diff --git a/src/rules/pattern.rs b/src/rules/pattern.rs new file mode 100644 index 0000000..0f6f620 --- /dev/null +++ b/src/rules/pattern.rs @@ -0,0 +1,161 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // x @ + let child = children.peek_next().unwrap(); + if let rnix::SyntaxKind::NODE_PAT_BIND = child.element.kind() { + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + steps.push_back(crate::builder::Step::Whitespace); + } + } + children.move_next(); + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // { + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + while let Some(child) = children.peek_next() { + match child.element.kind() { + // /**/ + rnix::SyntaxKind::TOKEN_COMMENT => { + let prev_kind = children.peek_prev().unwrap().element.kind(); + if let rnix::SyntaxKind::TOKEN_COMMA + | rnix::SyntaxKind::TOKEN_CURLY_B_OPEN = prev_kind + { + steps.push_back(crate::builder::Step::Whitespace); + } + + if let rnix::SyntaxKind::TOKEN_COMMENT + | rnix::SyntaxKind::TOKEN_ELLIPSIS + | rnix::SyntaxKind::NODE_PAT_ENTRY = prev_kind + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Whitespace); + } + + children.drain_comment(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + }); + } + // item + rnix::SyntaxKind::TOKEN_ELLIPSIS + | rnix::SyntaxKind::NODE_PAT_ENTRY => { + let prev_kind = children.peek_prev().unwrap().element.kind(); + + if let rnix::SyntaxKind::TOKEN_COMMA + | rnix::SyntaxKind::TOKEN_CURLY_B_OPEN = prev_kind + { + steps.push_back(crate::builder::Step::Whitespace); + } + + if let rnix::SyntaxKind::TOKEN_COMMENT = prev_kind { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Whitespace); + } + + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format( + child.element, + )); + } + }; + children.move_next(); + } + // , + rnix::SyntaxKind::TOKEN_COMMA => { + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => {} + }; + steps.push_back(crate::builder::Step::Format(child.element)); + children.move_next(); + } + _ => { + break; + } + } + } + + // } + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // @ x + if let Some(child) = children.peek_next() { + if let rnix::SyntaxKind::NODE_PAT_BIND = child.element.kind() { + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + } + } + + steps +} diff --git a/src/rules/root.rs b/src/rules/root.rs new file mode 100644 index 0000000..5473245 --- /dev/null +++ b/src/rules/root.rs @@ -0,0 +1,45 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + while children.has_next() { + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + }); + + if let Some(child) = children.get_next() { + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + steps.push_back(crate::builder::Step::NewLine); + } + crate::config::Layout::Wide => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + } + } + + // Trailing newline + if let Some(last_step) = steps.back() { + if *last_step != crate::builder::Step::NewLine { + steps.push_back(crate::builder::Step::NewLine); + } + } + + steps +} diff --git a/src/rules/select.rs b/src/rules/select.rs new file mode 100644 index 0000000..b16829e --- /dev/null +++ b/src/rules/select.rs @@ -0,0 +1,77 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => match child.element.kind() { + rnix::SyntaxKind::NODE_SELECT => { + steps.push_back(crate::builder::Step::Format(child.element)); + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + _ => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + }, + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // . + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + steps.push_back(crate::builder::Step::Dedent); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/src/rules/string.rs b/src/rules/string.rs new file mode 100644 index 0000000..cee8eeb --- /dev/null +++ b/src/rules/string.rs @@ -0,0 +1,107 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let child = children.get_next().unwrap(); + let child_token = child.element.clone().into_token().unwrap(); + let text = child_token.text(); + steps.push_back(crate::builder::Step::Format(child.element)); + + if text == "\"" { + while let Some(child) = children.get_next() { + match build_ctx.config.layout() { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + } + crate::config::Layout::Wide => { + steps + .push_back(crate::builder::Step::Format(child.element)); + } + } + } + } else { + let indentation = get_double_quoted_string_indentation(&node); + + while let Some(child) = children.peek_next() { + match child.element.kind() { + rnix::SyntaxKind::TOKEN_STRING_CONTENT => { + let child_token = child.element.into_token().unwrap(); + let lines: Vec<&str> = + child_token.text().split('\n').collect(); + + children.move_next(); + for (index, line) in lines.iter().enumerate() { + if index + 1 == lines.len() && line.trim().len() == 0 { + if let rnix::SyntaxKind::TOKEN_STRING_END = + children.peek_next().unwrap().element.kind() + { + continue; + } + } + + steps.push_back(crate::builder::Step::Token( + rnix::SyntaxKind::TOKEN_STRING_CONTENT, + if indentation >= line.len() { + line.to_string() + } else { + line[indentation..line.len()].to_string() + }, + )); + + if index == 0 && lines.len() > 1 { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else if index + 1 < lines.len() + && lines[index + 1].trim().len() == 0 + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + } + } + rnix::SyntaxKind::TOKEN_STRING_END => { + steps + .push_back(crate::builder::Step::Format(child.element)); + children.move_next(); + } + _ => { + steps.push_back(crate::builder::Step::FormatWider( + child.element, + )); + children.move_next(); + } + } + } + } + + // steps = crate::rules::default(build_ctx, node); + steps +} + +fn get_double_quoted_string_indentation(node: &rnix::SyntaxNode) -> usize { + let mut indentation: usize = usize::MAX; + + let text: String = node + .children_with_tokens() + .filter(|child| child.kind() == rnix::SyntaxKind::TOKEN_STRING_CONTENT) + .map(|child| child.into_token().unwrap()) + .map(|token| token.text().to_string()) + .collect(); + + for line in text.split('\n') { + let line = line.trim_end(); + + if line.len() > 0 { + indentation = + usize::min(indentation, line.len() - line.trim_start().len()); + } + } + + if indentation == usize::MAX { 0 } else { indentation } +} diff --git a/src/rules/string_interpol.rs b/src/rules/string_interpol.rs new file mode 100644 index 0000000..c4cf3a1 --- /dev/null +++ b/src/rules/string_interpol.rs @@ -0,0 +1,69 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // ${ + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // } + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + } + } + steps.push_back(crate::builder::Step::Format(child.element)); + + steps +} diff --git a/src/rules/with.rs b/src/rules/with.rs new file mode 100644 index 0000000..60b6bb1 --- /dev/null +++ b/src/rules/with.rs @@ -0,0 +1,72 @@ +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children::Children::new(build_ctx, node); + + let layout = if children.has_comments() { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // with + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + if let rnix::SyntaxKind::TOKEN_COMMENT = + children.peek_prev().unwrap().element.kind() + { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else { + steps.push_back(crate::builder::Step::Whitespace); + } + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + // ; + let child = children.get_next().unwrap(); + steps.push_back(crate::builder::Step::Format(child.element)); + + // /**/ + children.drain_comments(|text| { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + }); + + // expr + let child = children.get_next().unwrap(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::FormatWider(child.element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Format(child.element)); + } + } + + steps +} diff --git a/tests/cases/apply/in b/tests/cases/apply/in new file mode 100644 index 0000000..3848271 --- /dev/null +++ b/tests/cases/apply/in @@ -0,0 +1,4 @@ +(a b) +(a b) +(a /*b*/ c) +(/*a*/ b /*c*/ d /*e*/) diff --git a/tests/cases/apply/out b/tests/cases/apply/out new file mode 100644 index 0000000..99c9e16 --- /dev/null +++ b/tests/cases/apply/out @@ -0,0 +1,14 @@ +( a b ) + ( a b ) + ( + a + /*b*/ + c + ) + ( + /*a*/ + b + /*c*/ + d + /*e*/ + ) diff --git a/tests/cases/assert/in b/tests/cases/assert/in new file mode 100644 index 0000000..eb9708d --- /dev/null +++ b/tests/cases/assert/in @@ -0,0 +1,8 @@ +[ + (assert b; c) + (assert b; /*b*/ c) + (assert /*a*/ b; c) + (assert /*a*/ b; /*b*/ c) + ( assert b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ) + ( assert b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ) +] diff --git a/tests/cases/assert/out b/tests/cases/assert/out new file mode 100644 index 0000000..212a240 --- /dev/null +++ b/tests/cases/assert/out @@ -0,0 +1,28 @@ +[ + ( assert b; c ) + ( + assert b; + /*b*/ + c + ) + ( + assert + /*a*/ + b; + c + ) + ( + assert + /*a*/ + b; + /*b*/ + c + ) + ( + assert b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + ) + ( + assert b; + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + ) +] diff --git a/tests/cases/attr_set/in b/tests/cases/attr_set/in new file mode 100644 index 0000000..0ab24f8 --- /dev/null +++ b/tests/cases/attr_set/in @@ -0,0 +1,7 @@ +[ + {} + {/*a*/} + {a=1;} + {/*a*/b=1;/*c*/} + {a={a={a={a={a={a={a={a={a={a={};};};};};};};};};};} +] diff --git a/tests/cases/attr_set/out b/tests/cases/attr_set/out new file mode 100644 index 0000000..1a21d5a --- /dev/null +++ b/tests/cases/attr_set/out @@ -0,0 +1,24 @@ +[ + { } + { + /*a*/ + } + { a = 1; } + { + /*a*/ + b = 1; + /*c*/ + } + { + a = + { + a = + { + a = + { + a = { a = { a = { a = { a = { a = { a = { }; }; }; }; }; }; }; + }; + }; + }; + } +] diff --git a/tests/cases/bin_op/in b/tests/cases/bin_op/in new file mode 100644 index 0000000..61a9cb9 --- /dev/null +++ b/tests/cases/bin_op/in @@ -0,0 +1,9 @@ +[ + (1 + 1) + (1 +/**/1) + (1/**/+ 1) + (1/**/+/**/1) + (1/**/+/**/(1/**/+/**/(1/**/+/**/1))) + ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 ) + ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1) +] diff --git a/tests/cases/bin_op/out b/tests/cases/bin_op/out new file mode 100644 index 0000000..6e8199f --- /dev/null +++ b/tests/cases/bin_op/out @@ -0,0 +1,63 @@ +[ + ( 1 + 1 ) + ( + 1 + + + /**/ + 1 + ) + ( + 1 + /**/ + + 1 + ) + ( + 1 + /**/ + + + /**/ + 1 + ) + ( + 1 + /**/ + + + /**/ + ( + 1 + /**/ + + + /**/ + ( + 1 + /**/ + + + /**/ + 1 + ) + ) + ) + ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 ) + ( + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + ) +] diff --git a/tests/cases/dynamic/in b/tests/cases/dynamic/in new file mode 100644 index 0000000..bad6cfa --- /dev/null +++ b/tests/cases/dynamic/in @@ -0,0 +1 @@ +a.${/*b*/c.${/*d*/e.${f}}/*g*/} diff --git a/tests/cases/dynamic/out b/tests/cases/dynamic/out new file mode 100644 index 0000000..40dba96 --- /dev/null +++ b/tests/cases/dynamic/out @@ -0,0 +1,10 @@ +a + .${ + /*b*/ + c + .${ + /*d*/ + e.${ f } + } + /*g*/ + } diff --git a/tests/cases/if_else/in b/tests/cases/if_else/in new file mode 100644 index 0000000..b276d87 --- /dev/null +++ b/tests/cases/if_else/in @@ -0,0 +1,4 @@ +[ + (if a then b else c) + (if /**/ a /**/ then /**/ b /**/ else /**/ c) +] diff --git a/tests/cases/if_else/out b/tests/cases/if_else/out new file mode 100644 index 0000000..0cbfb0d --- /dev/null +++ b/tests/cases/if_else/out @@ -0,0 +1,16 @@ +[ + ( if a then b else c ) + ( + if + /**/ + a + /**/ + then + /**/ + b + /**/ + else + /**/ + c + ) +] diff --git a/tests/cases/inherit/in b/tests/cases/inherit/in new file mode 100644 index 0000000..b0c31d5 --- /dev/null +++ b/tests/cases/inherit/in @@ -0,0 +1,12 @@ +[ + { inherit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; } + { inherit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; } + { inherit b d ; } + { inherit b d /*e*/ ; } + { inherit b /*c*/ d ; } + { inherit b /*c*/ d /*e*/ ; } + { inherit /*a*/ b d ; } + { inherit /*a*/ b d /*e*/ ; } + { inherit /*a*/ b /*c*/ d ; } + { inherit /*a*/ b /*c*/ d /*e*/ ; } +] diff --git a/tests/cases/inherit/out b/tests/cases/inherit/out new file mode 100644 index 0000000..6f2b5a1 --- /dev/null +++ b/tests/cases/inherit/out @@ -0,0 +1,61 @@ +[ + { + inherit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + } + { + inherit + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + } + { inherit b d; } + { + inherit + b + d + /*e*/ + ; + } + { + inherit + b + /*c*/ + d; + } + { + inherit + b + /*c*/ + d + /*e*/ + ; + } + { + inherit + /*a*/ + b + d; + } + { + inherit + /*a*/ + b + d + /*e*/ + ; + } + { + inherit + /*a*/ + b + /*c*/ + d; + } + { + inherit + /*a*/ + b + /*c*/ + d + /*e*/ + ; + } +] diff --git a/tests/cases/inherit_from/in b/tests/cases/inherit_from/in new file mode 100644 index 0000000..52bb08c --- /dev/null +++ b/tests/cases/inherit_from/in @@ -0,0 +1,6 @@ +[ + { inherit ( b ) d; } + { inherit ( b /*c*/) d; } + { inherit (/*a*/ b ) d; } + { inherit (/*a*/ b /*c*/) d; } +] diff --git a/tests/cases/inherit_from/out b/tests/cases/inherit_from/out new file mode 100644 index 0000000..2539761 --- /dev/null +++ b/tests/cases/inherit_from/out @@ -0,0 +1,28 @@ +[ + { inherit ( b ) d; } + { + inherit + ( + b + /*c*/ + ) + d; + } + { + inherit + ( + /*a*/ + b + ) + d; + } + { + inherit + ( + /*a*/ + b + /*c*/ + ) + d; + } +] diff --git a/tests/cases/key_value/in b/tests/cases/key_value/in new file mode 100644 index 0000000..5146a9d --- /dev/null +++ b/tests/cases/key_value/in @@ -0,0 +1,10 @@ +{ + a = {a = 1 ;}; + b = {a = 1/*d*/;}; + c = {a =/*c*/1 ;}; + d = {a =/*c*/1/*d*/;}; + e = {a/*b*/= 1 ;}; + f = {a/*b*/= 1/*d*/;}; + h = {a/*b*/=/*c*/1 ;}; + i = {a/*b*/=/*c*/1/*d*/;}; +} diff --git a/tests/cases/key_value/out b/tests/cases/key_value/out new file mode 100644 index 0000000..270df92 --- /dev/null +++ b/tests/cases/key_value/out @@ -0,0 +1,58 @@ +{ + a = { a = 1; }; + b = + { + a = + 1 + /*d*/ + ; + }; + c = + { + a = + /*c*/ + 1; + }; + d = + { + a = + /*c*/ + 1 + /*d*/ + ; + }; + e = + { + a + /*b*/ + = + 1; + }; + f = + { + a + /*b*/ + = + 1 + /*d*/ + ; + }; + h = + { + a + /*b*/ + = + /*c*/ + 1; + }; + i = + { + a + /*b*/ + = + /*c*/ + 1 + /*d*/ + ; + }; +} diff --git a/tests/cases/lambda/in b/tests/cases/lambda/in new file mode 100644 index 0000000..b78cf36 --- /dev/null +++ b/tests/cases/lambda/in @@ -0,0 +1,10 @@ +[ + (a : d) + (a : /*c*/ d) + (a /*b*/ : d) + (a /*b*/ : /*c*/ d) + ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ) + ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ) +] diff --git a/tests/cases/lambda/out b/tests/cases/lambda/out new file mode 100644 index 0000000..f0cf195 --- /dev/null +++ b/tests/cases/lambda/out @@ -0,0 +1,28 @@ +[ + ( a: d ) + ( + a: + /*c*/ + d + ) + ( + a + /*b*/ + : + d + ) + ( + a + /*b*/ + : + /*c*/ + d + ) + ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ) + ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ) +] diff --git a/tests/cases/let_in/in b/tests/cases/let_in/in new file mode 100644 index 0000000..b877889 --- /dev/null +++ b/tests/cases/let_in/in @@ -0,0 +1,21 @@ +let + /**/ + a = let c=1; in f; + /**/ + a = let c=1; in /*e*/ f; + /**/ + a = let c=1; /*d*/ in f; + /**/ + a = let c=1; /*d*/ in /*e*/ f; + /**/ + a = let /*b*/ c=1; in f; + /**/ + a = let /*b*/ c=1; in /*e*/ f; + /**/ + a = let /*b*/ c=1; /*d*/ in f; + /**/ + a = let /*b*/ c=1; /*d*/ in /*e*/ f; + /**/ +in +/**/ +a diff --git a/tests/cases/let_in/out b/tests/cases/let_in/out new file mode 100644 index 0000000..fb04aff --- /dev/null +++ b/tests/cases/let_in/out @@ -0,0 +1,61 @@ +let + /**/ + a = let c = 1; in f; + /**/ + a = + let + c = 1; + in + /*e*/ + f; + /**/ + a = + let + c = 1; + /*d*/ + in + f; + /**/ + a = + let + c = 1; + /*d*/ + in + /*e*/ + f; + /**/ + a = + let + /*b*/ + c = 1; + in + f; + /**/ + a = + let + /*b*/ + c = 1; + in + /*e*/ + f; + /**/ + a = + let + /*b*/ + c = 1; + /*d*/ + in + f; + /**/ + a = + let + /*b*/ + c = 1; + /*d*/ + in + /*e*/ + f; + /**/ +in +/**/ +a diff --git a/tests/cases/or_default/in b/tests/cases/or_default/in new file mode 100644 index 0000000..b75e390 --- /dev/null +++ b/tests/cases/or_default/in @@ -0,0 +1,9 @@ +[ + (a ? a) + (a ?/**/a) + (a/**/? a) + (a/**/?/**/a) + (a/**/?/**/(a/**/?/**/(a/**/?/**/a))) + ( a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ) + ( a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a) +] diff --git a/tests/cases/or_default/out b/tests/cases/or_default/out new file mode 100644 index 0000000..d23e82f --- /dev/null +++ b/tests/cases/or_default/out @@ -0,0 +1,63 @@ +[ + ( a ? a ) + ( + a + ? + /**/ + a + ) + ( + a + /**/ + ? a + ) + ( + a + /**/ + ? + /**/ + a + ) + ( + a + /**/ + ? + /**/ + ( + a + /**/ + ? + /**/ + ( + a + /**/ + ? + /**/ + a + ) + ) + ) + ( a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ? a ) + ( + a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ? a + ) +] diff --git a/tests/cases/paren/in b/tests/cases/paren/in new file mode 100644 index 0000000..3346a37 --- /dev/null +++ b/tests/cases/paren/in @@ -0,0 +1 @@ +(/*a*/(/*b*/(c))/*d*/) diff --git a/tests/cases/paren/out b/tests/cases/paren/out new file mode 100644 index 0000000..99fe7bc --- /dev/null +++ b/tests/cases/paren/out @@ -0,0 +1,8 @@ +( + /*a*/ + ( + /*b*/ + ( c ) + ) + /*d*/ +) diff --git a/tests/cases/pat_bind/in b/tests/cases/pat_bind/in new file mode 100644 index 0000000..e55187b --- /dev/null +++ b/tests/cases/pat_bind/in @@ -0,0 +1,11 @@ +[ + ({} @ a: _) + ({} @ /**/ a: _) + ({} /**/ @ a: _) + ({} /**/ @ /**/ a: _) + + (a @ {}: _) + (a @ /**/ {}: _) + (a /**/ @ {}: _) + (a /**/ @ /**/ {}: _) +] diff --git a/tests/cases/pat_bind/out b/tests/cases/pat_bind/out new file mode 100644 index 0000000..59c9ee6 --- /dev/null +++ b/tests/cases/pat_bind/out @@ -0,0 +1,52 @@ +[ + ( { } @ a: _ ) + ( + { + } + @ + /**/ + a: + _ + ) + ( + { + } + /**/ + @ a: + _ + ) + ( + { + } + /**/ + @ + /**/ + a: + _ + ) + ( a @ { }: _ ) + ( + a @ + /**/ + { + }: + _ + ) + ( + a + /**/ + @ + { + }: + _ + ) + ( + a + /**/ + @ + /**/ + { + }: + _ + ) +] diff --git a/tests/cases/pattern/in b/tests/cases/pattern/in new file mode 100644 index 0000000..ca248aa --- /dev/null +++ b/tests/cases/pattern/in @@ -0,0 +1,73 @@ +[ + ({}: _) + ({ /**/ }: _) + ({ ... }: _) + ({ ... /**/}: _) + ({ /**/ ... }: _) + ({ /**/ ... /**/}: _) + + ({ b , e , ... }: _) + ({ b , e , ... /*h*/ }: _) + ({ b , e , /*g*/ ... }: _) + ({ b , e , /*g*/ ... /*h*/ }: _) + ({ b , e /*f*/ , ... }: _) + ({ b , e /*f*/ , ... /*h*/ }: _) + ({ b , e /*f*/ , /*g*/ ... }: _) + ({ b , e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ b , /*d*/ e , ... }: _) + ({ b , /*d*/ e , ... /*h*/ }: _) + ({ b , /*d*/ e , /*g*/ ... }: _) + ({ b , /*d*/ e , /*g*/ ... /*h*/ }: _) + ({ b , /*d*/ e /*f*/ , ... }: _) + ({ b , /*d*/ e /*f*/ , ... /*h*/ }: _) + ({ b , /*d*/ e /*f*/ , /*g*/ ... }: _) + ({ b , /*d*/ e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ b /*c*/ , e , ... }: _) + ({ b /*c*/ , e , ... /*h*/ }: _) + ({ b /*c*/ , e , /*g*/ ... }: _) + ({ b /*c*/ , e , /*g*/ ... /*h*/ }: _) + ({ b /*c*/ , e /*f*/ , ... }: _) + ({ b /*c*/ , e /*f*/ , ... /*h*/ }: _) + ({ b /*c*/ , e /*f*/ , /*g*/ ... }: _) + ({ b /*c*/ , e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ b /*c*/ , /*d*/ e , ... }: _) + ({ b /*c*/ , /*d*/ e , ... /*h*/ }: _) + ({ b /*c*/ , /*d*/ e , /*g*/ ... }: _) + ({ b /*c*/ , /*d*/ e , /*g*/ ... /*h*/ }: _) + ({ b /*c*/ , /*d*/ e /*f*/ , ... }: _) + ({ b /*c*/ , /*d*/ e /*f*/ , ... /*h*/ }: _) + ({ b /*c*/ , /*d*/ e /*f*/ , /*g*/ ... }: _) + ({ b /*c*/ , /*d*/ e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b , e , ... }: _) + ({ /*a*/ b , e , ... /*h*/ }: _) + ({ /*a*/ b , e , /*g*/ ... }: _) + ({ /*a*/ b , e , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b , e /*f*/ , ... }: _) + ({ /*a*/ b , e /*f*/ , ... /*h*/ }: _) + ({ /*a*/ b , e /*f*/ , /*g*/ ... }: _) + ({ /*a*/ b , e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b , /*d*/ e , ... }: _) + ({ /*a*/ b , /*d*/ e , ... /*h*/ }: _) + ({ /*a*/ b , /*d*/ e , /*g*/ ... }: _) + ({ /*a*/ b , /*d*/ e , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b , /*d*/ e /*f*/ , ... }: _) + ({ /*a*/ b , /*d*/ e /*f*/ , ... /*h*/ }: _) + ({ /*a*/ b , /*d*/ e /*f*/ , /*g*/ ... }: _) + ({ /*a*/ b , /*d*/ e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , e , ... }: _) + ({ /*a*/ b /*c*/ , e , ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , e , /*g*/ ... }: _) + ({ /*a*/ b /*c*/ , e , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , e /*f*/ , ... }: _) + ({ /*a*/ b /*c*/ , e /*f*/ , ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , e /*f*/ , /*g*/ ... }: _) + ({ /*a*/ b /*c*/ , e /*f*/ , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , /*d*/ e , ... }: _) + ({ /*a*/ b /*c*/ , /*d*/ e , ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , /*d*/ e , /*g*/ ... }: _) + ({ /*a*/ b /*c*/ , /*d*/ e , /*g*/ ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , /*d*/ e /*f*/ , ... }: _) + ({ /*a*/ b /*c*/ , /*d*/ e /*f*/ , ... /*h*/ }: _) + ({ /*a*/ b /*c*/ , /*d*/ e /*f*/ , /*g*/ ... }: _) + ({ /*a*/ b /*c*/ , /*d*/ e /*f*/ , /*g*/ ... /*h*/ }: _) +] diff --git a/tests/cases/pattern/out b/tests/cases/pattern/out new file mode 100644 index 0000000..99573fb --- /dev/null +++ b/tests/cases/pattern/out @@ -0,0 +1,662 @@ +[ + ( { }: _ ) + ( + { /**/ + }: + _ + ) + ( { ... }: _ ) + ( + { ... + /**/ + }: + _ + ) + ( + { /**/ + ... + }: + _ + ) + ( + { /**/ + ... + /**/ + }: + _ + ) + ( { b, e, ... }: _ ) + ( + { b + , e + , ... + /*h*/ + }: + _ + ) + ( + { b + , e + , /*g*/ + ... + }: + _ + ) + ( + { b + , e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + , e + /*f*/ + , ... + }: + _ + ) + ( + { b + , e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { b + , e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { b + , e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + , /*d*/ + e + , ... + }: + _ + ) + ( + { b + , /*d*/ + e + , ... + /*h*/ + }: + _ + ) + ( + { b + , /*d*/ + e + , /*g*/ + ... + }: + _ + ) + ( + { b + , /*d*/ + e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + , /*d*/ + e + /*f*/ + , ... + }: + _ + ) + ( + { b + , /*d*/ + e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { b + , /*d*/ + e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { b + , /*d*/ + e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , e + , ... + }: + _ + ) + ( + { b + /*c*/ + , e + , ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , e + , /*g*/ + ... + }: + _ + ) + ( + { b + /*c*/ + , e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , e + /*f*/ + , ... + }: + _ + ) + ( + { b + /*c*/ + , e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { b + /*c*/ + , e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + , ... + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + , ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + , /*g*/ + ... + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + /*f*/ + , ... + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { b + /*c*/ + , /*d*/ + e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , e + , ... + }: + _ + ) + ( + { /*a*/ + b + , e + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , e + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + , e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , e + /*f*/ + , ... + }: + _ + ) + ( + { /*a*/ + b + , e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + , e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + , ... + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + /*f*/ + , ... + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + , /*d*/ + e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + , ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + /*f*/ + , ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + , ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + , /*g*/ + ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + /*f*/ + , ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + /*f*/ + , ... + /*h*/ + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + /*f*/ + , /*g*/ + ... + }: + _ + ) + ( + { /*a*/ + b + /*c*/ + , /*d*/ + e + /*f*/ + , /*g*/ + ... + /*h*/ + }: + _ + ) +] diff --git a/tests/cases/root/in b/tests/cases/root/in new file mode 100644 index 0000000..73a0c5a --- /dev/null +++ b/tests/cases/root/in @@ -0,0 +1,14 @@ +# a + /* test + * test + */ + +# a + +"test" + +# b +/* c */ + +/* c */ +# c diff --git a/tests/cases/root/out b/tests/cases/root/out new file mode 100644 index 0000000..1a79940 --- /dev/null +++ b/tests/cases/root/out @@ -0,0 +1,10 @@ +# a +/* test + * test + */ +# a +"test" +# b +/* c */ +/* c */ +# c diff --git a/tests/cases/select/in b/tests/cases/select/in new file mode 100644 index 0000000..8ffc381 --- /dev/null +++ b/tests/cases/select/in @@ -0,0 +1,8 @@ +[ + (a . a) + (a ./**/a) + (a/**/. a) + (a/**/./**/a) + ( a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a ) + ( a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a ) +] diff --git a/tests/cases/select/out b/tests/cases/select/out new file mode 100644 index 0000000..46e263b --- /dev/null +++ b/tests/cases/select/out @@ -0,0 +1,65 @@ +[ + ( a.a ) + ( + a + . + /**/ + a + ) + ( + a + /**/ + .a + ) + ( + a + /**/ + . + /**/ + a + ) + ( + a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a + ) + ( + a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + .a + ) +] diff --git a/tests/cases/string/in b/tests/cases/string/in new file mode 100644 index 0000000..de62ede --- /dev/null +++ b/tests/cases/string/in @@ -0,0 +1,40 @@ +[ + "" + + " + " + + "a + ${x} + b + " + + '''' + + + ''a'' + + ''${""}'' + + '' + a + ${""} + b + ${""} + c ${""} d + e + '' + + '' + '' + + '' + declare -a makefiles=(./*.mak) + sed -i -f ${makefile-sed} "''${makefiles[@]}" + # assign Makefile variables eagerly & change backticks to `$(shell …)` + sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \ + -e 's/`\([^`]\+\)`/$(shell \1)/' \ + "''${makefiles[@]}" + '' + +] diff --git a/tests/cases/string/out b/tests/cases/string/out new file mode 100644 index 0000000..7fd26ce --- /dev/null +++ b/tests/cases/string/out @@ -0,0 +1,30 @@ +[ + "" + " + " + "a + ${ x } + b + " + '''' + ''a'' + ''${ "" }'' + '' + a + ${ "" } + b + ${ "" } + c ${ "" } d + e + '' + '' + '' + '' + declare -a makefiles=(./*.mak) + sed -i -f ${ makefile-sed } "''${makefiles[@]}" + # assign Makefile variables eagerly & change backticks to `$(shell …)` + sed -i -e 's/ = `\([^`]\+\)`/ := $(shell \1)/' \ + -e 's/`\([^`]\+\)`/$(shell \1)/' \ + "''${makefiles[@]}" + '' +] diff --git a/tests/cases/string_interpol/in b/tests/cases/string_interpol/in new file mode 100644 index 0000000..29a7e92 --- /dev/null +++ b/tests/cases/string_interpol/in @@ -0,0 +1 @@ +"${/*a*/"${/*b*/"${c}"}"/*d*/}" diff --git a/tests/cases/string_interpol/out b/tests/cases/string_interpol/out new file mode 100644 index 0000000..ed198c0 --- /dev/null +++ b/tests/cases/string_interpol/out @@ -0,0 +1,8 @@ +"${ + /*a*/ + "${ + /*b*/ + "${ c }" + }" + /*d*/ +}" diff --git a/tests/cases/with/in b/tests/cases/with/in new file mode 100644 index 0000000..1a36adf --- /dev/null +++ b/tests/cases/with/in @@ -0,0 +1,8 @@ +[ + (with b; c) + (with b; /*b*/ c) + (with /*a*/ b; c) + (with /*a*/ b; /*b*/ c) + ( with b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ) + ( with b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ) +] diff --git a/tests/cases/with/out b/tests/cases/with/out new file mode 100644 index 0000000..e9edeeb --- /dev/null +++ b/tests/cases/with/out @@ -0,0 +1,28 @@ +[ + ( with b; c ) + ( + with b; + /*b*/ + c + ) + ( + with + /*a*/ + b; + c + ) + ( + with + /*a*/ + b; + /*b*/ + c + ) + ( + with b; cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + ) + ( + with b; + cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + ) +] diff --git a/tests/fmt.rs b/tests/fmt.rs new file mode 100644 index 0000000..2c3b4fa --- /dev/null +++ b/tests/fmt.rs @@ -0,0 +1,52 @@ +use std::io::Write; + +#[test] +fn cases() { + let should_update = std::env::var("UPDATE").is_ok(); + + let config = alejandra::config::Config::new(); + + let cases: std::collections::HashSet = + std::fs::read_dir("tests/cases") + .unwrap() + .map(|entry| entry.unwrap().file_name().into_string().unwrap()) + .collect(); + + for case in cases { + let path_in = format!("tests/cases/{}/in", case); + let path_out = format!("tests/cases/{}/out", case); + let content_in = std::fs::read_to_string(path_in.clone()).unwrap(); + let content_got = + alejandra::format::string(&config, &path_in, content_in.clone()); + + if should_update { + std::fs::File::create(&path_out) + .unwrap() + .write_all(content_got.as_bytes()) + .unwrap(); + } + + let content_out = std::fs::read_to_string(path_out.clone()).unwrap(); + + assert!( + content_got == content_out, + indoc::indoc!( + r" + + + input from {}: + {} + after formatting: + {} + expected from {}: + {} + " + ), + path_in, + &content_in, + &content_got, + path_out, + &content_out, + ); + } +}