1use rust_minify::{minify_opt, MinifyOption};
2use std::{
3 io::Write as _,
4 path::Path,
5 process::{Command, Stdio},
6 str::FromStr,
7};
8
9#[derive(Debug, Clone)]
10pub enum FormatOption {
11 Rustfmt,
12 Minify,
13}
14
15impl Default for FormatOption {
16 fn default() -> Self {
17 Self::Rustfmt
18 }
19}
20
21impl FromStr for FormatOption {
22 type Err = &'static str;
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 match s {
25 "rustfmt" => Ok(Self::Rustfmt),
26 "minify" => Ok(Self::Minify),
27 _ => Err("expected one of [rustfmt|minify]"),
28 }
29 }
30}
31
32impl FormatOption {
33 pub const POSSIBLE_VALUES: [&'static str; 2] = ["rustfmt", "minify"];
34 pub fn format(&self, content: &str) -> Option<String> {
35 match self {
36 Self::Rustfmt => format_with_rustfmt(content),
37 Self::Minify => minify_opt(
38 content,
39 &MinifyOption {
40 remove_skip: true,
41 add_rustfmt_skip: true,
42 },
43 )
44 .ok(),
45 }
46 }
47}
48
49pub fn rustfmt_exits() -> bool {
50 let rustfmt = Path::new(env!("CARGO_HOME")).join("bin").join("rustfmt");
51 let output = Command::new(rustfmt).arg("--version").output();
52 output
53 .map(|output| output.status.success())
54 .unwrap_or_default()
55}
56
57pub fn format_with_rustfmt(s: &str) -> Option<String> {
58 let rustfmt = Path::new(env!("CARGO_HOME")).join("bin").join("rustfmt");
59 let mut command = Command::new(rustfmt)
60 .args([
61 "--quiet",
62 "--config",
63 "unstable_features=true,normalize_doc_attributes=true,newline_style=Unix",
64 ])
65 .stdin(Stdio::piped())
66 .stdout(Stdio::piped())
67 .stderr(Stdio::piped())
68 .spawn()
69 .ok()?;
70 command.stdin.take().unwrap().write_all(s.as_bytes()).ok()?;
71 let output = command.wait_with_output().ok()?;
72 if output.status.success() {
73 Some(unsafe { String::from_utf8_unchecked(output.stdout) })
74 } else {
75 None
76 }
77}
78
79#[test]
80fn test_format_contents() {
81 assert_eq!(
82 format_with_rustfmt("fn main ( ) { }"),
83 Some("fn main() {}\n".to_string())
84 )
85}