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