1use std::ffi::OsString;
10use std::process::ExitCode;
11
12use bynk_driver::{FmtArgs, IndentKind};
13
14use crate::compiler::{Compiler, Origin, SkewAsker, skew_gate};
15
16pub fn run(compiler: &Compiler, args: FmtArgs) -> ExitCode {
19 if let (Some(Origin::Override), Some(bynkc)) = (compiler.origin, compiler.path.as_deref()) {
20 let asker = SkewAsker {
22 command: Some("fmt"),
23 has_flag: false,
24 };
25 if !skew_gate(compiler, asker, false) {
26 return ExitCode::FAILURE;
27 }
28 return crate::shell::delegate(bynkc, delegated_argv(&args));
29 }
30 fmt_in_process(args)
31}
32
33fn delegated_argv(args: &FmtArgs) -> Vec<OsString> {
46 let mut argv: Vec<OsString> = vec!["fmt".into()];
47 if args.check {
48 argv.push("--check".into());
49 }
50 if let Some(kind) = args.indent {
51 argv.push("--indent".into());
52 argv.push(
53 match kind {
54 IndentKind::Tab => "tab",
55 IndentKind::Spaces => "spaces",
56 }
57 .into(),
58 );
59 }
60 if let Some(width) = args.indent_width {
61 argv.push("--indent-width".into());
62 argv.push(width.to_string().into());
63 }
64 if let Some(width) = args.max_line_width {
65 argv.push("--max-line-width".into());
66 argv.push(width.to_string().into());
67 }
68 if args.trailing_comma {
69 argv.push("--trailing-comma".into());
70 }
71 if args.no_trailing_comma {
72 argv.push("--no-trailing-comma".into());
73 }
74 if args.no_config {
75 argv.push("--no-config".into());
76 }
77 argv.push("--".into());
82 argv.extend(args.inputs.iter().map(|p| p.as_os_str().to_os_string()));
83 argv
84}
85
86fn fmt_in_process(args: FmtArgs) -> ExitCode {
88 bynk_driver::run_fmt("bynk", &args)
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 fn argv_of(args: FmtArgs) -> Vec<String> {
96 delegated_argv(&args)
97 .into_iter()
98 .map(|a| a.to_string_lossy().into_owned())
99 .collect()
100 }
101
102 fn base() -> FmtArgs {
103 FmtArgs {
104 inputs: vec!["a.bynk".into()],
105 check: false,
106 indent: None,
107 indent_width: None,
108 max_line_width: None,
109 trailing_comma: false,
110 no_trailing_comma: false,
111 no_config: false,
112 }
113 }
114
115 #[test]
116 fn an_unflagged_run_forwards_no_style_at_all() {
117 assert_eq!(argv_of(base()), vec!["fmt", "--", "a.bynk"]);
121 }
122
123 #[test]
124 fn style_overrides_reach_the_pinned_compiler() {
125 let args = FmtArgs {
128 check: true,
129 indent: Some(IndentKind::Spaces),
130 indent_width: Some(4),
131 max_line_width: Some(120),
132 no_trailing_comma: true,
133 ..base()
134 };
135 assert_eq!(
136 argv_of(args),
137 vec![
138 "fmt",
139 "--check",
140 "--indent",
141 "spaces",
142 "--indent-width",
143 "4",
144 "--max-line-width",
145 "120",
146 "--no-trailing-comma",
147 "--",
148 "a.bynk",
149 ]
150 );
151 }
152
153 #[test]
154 fn an_explicit_tab_is_forwarded_so_it_can_beat_a_manifest() {
155 let args = FmtArgs {
159 indent: Some(IndentKind::Tab),
160 ..base()
161 };
162 let argv = argv_of(args);
163 assert!(
164 argv.windows(2).any(|w| w == ["--indent", "tab"]),
165 "an explicit `--indent tab` must be forwarded: {argv:?}"
166 );
167 }
168
169 #[test]
170 fn trailing_comma_and_no_config_are_forwarded() {
171 let args = FmtArgs {
172 trailing_comma: true,
173 no_config: true,
174 ..base()
175 };
176 let argv = argv_of(args);
177 assert!(argv.contains(&"--trailing-comma".to_string()), "{argv:?}");
178 assert!(argv.contains(&"--no-config".to_string()), "{argv:?}");
179 }
180
181 #[test]
182 fn every_input_is_forwarded_after_the_separator() {
183 let args = FmtArgs {
187 inputs: vec!["-".into(), "b/c.bynk".into(), "-weird.bynk".into()],
188 ..base()
189 };
190 let argv = argv_of(args);
191 let sep = argv
192 .iter()
193 .position(|a| a == "--")
194 .expect("a `--` separator");
195 assert_eq!(
196 &argv[sep + 1..],
197 ["-", "b/c.bynk", "-weird.bynk"],
198 "every input must follow the separator, in order: {argv:?}"
199 );
200 }
201}