cargo_unfmt/
lib.rs

1use anyhow::Context;
2use ir::Ir;
3use location::Visitor;
4use syn::visit::Visit;
5
6mod location;
7
8mod emit;
9mod ir;
10mod lex;
11
12const JUNK: [&str; 81] = [
13    "",
14    ";",
15    "3;",
16    "();",
17    "{;};",
18    "({});",
19    "{();};",
20    "*&*&();",
21    "((),());",
22    "let _=();",
23    "if true{};",
24    "let _=||();",
25    "loop{break};",
26    "loop{break;};",
27    "if let _=(){};",
28    "*&*&();((),());",
29    "((),());((),());",
30    "((),());let _=();",
31    "let _=();let _=();",
32    "let _=();if true{};",
33    "if true{};if true{};",
34    "if true{};let _=||();",
35    "let _=||();let _=||();",
36    "let _=||();loop{break};",
37    "loop{break};loop{break};",
38    "loop{break};loop{break;};",
39    "loop{break;};loop{break;};",
40    "loop{break;};if let _=(){};",
41    "if let _=(){};if let _=(){};",
42    "if let _=(){};*&*&();((),());",
43    "*&*&();((),());*&*&();((),());",
44    "*&*&();((),());((),());((),());",
45    "((),());((),());((),());((),());",
46    "((),());((),());((),());let _=();",
47    "((),());let _=();((),());let _=();",
48    "((),());let _=();let _=();let _=();",
49    "let _=();let _=();let _=();let _=();",
50    "let _=();let _=();let _=();if true{};",
51    "let _=();if true{};let _=();if true{};",
52    "let _=();if true{};if true{};if true{};",
53    "if true{};if true{};if true{};if true{};",
54    "if true{};if true{};if true{};let _=||();",
55    "if true{};let _=||();if true{};let _=||();",
56    "if true{};let _=||();let _=||();let _=||();",
57    "let _=||();let _=||();let _=||();let _=||();",
58    "let _=||();let _=||();let _=||();loop{break};",
59    "let _=||();loop{break};let _=||();loop{break};",
60    "let _=||();loop{break};loop{break};loop{break};",
61    "loop{break};loop{break};loop{break};loop{break};",
62    "loop{break};loop{break};loop{break};loop{break;};",
63    "loop{break};loop{break;};loop{break};loop{break;};",
64    "loop{break};loop{break;};loop{break;};loop{break;};",
65    "loop{break;};loop{break;};loop{break;};loop{break;};",
66    "loop{break;};loop{break;};loop{break;};if let _=(){};",
67    "loop{break;};if let _=(){};loop{break;};if let _=(){};",
68    "loop{break;};if let _=(){};if let _=(){};if let _=(){};",
69    "if let _=(){};if let _=(){};if let _=(){};if let _=(){};",
70    "if let _=(){};if let _=(){};if let _=(){};*&*&();((),());",
71    "if let _=(){};*&*&();((),());if let _=(){};*&*&();((),());",
72    "if let _=(){};*&*&();((),());*&*&();((),());*&*&();((),());",
73    "*&*&();((),());*&*&();((),());*&*&();((),());*&*&();((),());",
74    "*&*&();((),());*&*&();((),());*&*&();((),());((),());((),());",
75    "*&*&();((),());((),());((),());*&*&();((),());((),());((),());",
76    "*&*&();((),());((),());((),());((),());((),());((),());((),());",
77    "((),());((),());((),());((),());((),());((),());((),());((),());",
78    "((),());((),());((),());((),());((),());((),());((),());let _=();",
79    "((),());((),());((),());let _=();((),());((),());((),());let _=();",
80    "((),());((),());((),());let _=();((),());let _=();((),());let _=();",
81    "((),());let _=();((),());let _=();((),());let _=();((),());let _=();",
82    "((),());let _=();((),());let _=();((),());let _=();let _=();let _=();",
83    "((),());let _=();let _=();let _=();((),());let _=();let _=();let _=();",
84    "((),());let _=();let _=();let _=();let _=();let _=();let _=();let _=();",
85    "let _=();let _=();let _=();let _=();let _=();let _=();let _=();let _=();",
86    "let _=();let _=();let _=();let _=();let _=();let _=();let _=();if true{};",
87    "let _=();let _=();let _=();if true{};let _=();let _=();let _=();if true{};",
88    "let _=();let _=();let _=();if true{};let _=();if true{};let _=();if true{};",
89    "let _=();if true{};let _=();if true{};let _=();if true{};let _=();if true{};",
90    "let _=();if true{};let _=();if true{};let _=();if true{};if true{};if true{};",
91    "let _=();if true{};if true{};if true{};let _=();if true{};if true{};if true{};",
92    "let _=();if true{};if true{};if true{};if true{};if true{};if true{};if true{};",
93    "if true{};if true{};if true{};if true{};if true{};if true{};if true{};if true{};",
94];
95
96/// Unformat a source file into lines of length `width`.
97///
98/// ## Details
99/// This process strips comments, inserts no-op statements, and wraps expressions
100/// in extra parentheses to achieve the desired line length.
101///
102/// ## Errors
103/// Returns an error if the source file is not valid Rust.
104///
105/// This function returns a spurious error if source has documentation comments
106/// not at the start of a line, for example:
107/// ```
108/// let x = blah; /// bad!
109/// ```
110/// This is because we use syn under the hood, which does not understand doc comments.
111pub fn unformat(src: &str, width: usize) -> anyhow::Result<Vec<u8>> {
112    let src = remove_doc_comments(src);
113
114    let tokens = lex::lex_file(&src).context("source was not valid")?;
115
116    let mut stmts = Visitor::new();
117    stmts.visit_file(&syn::parse_file(&src).unwrap());
118
119    let ir = Ir::new(tokens.into_iter());
120    let ir = ir.populate_events(stmts.events());
121
122    let mut unformatted = vec![];
123    crate::emit::block(&mut unformatted, &ir, width);
124
125    Ok(unformatted)
126}
127
128/// Remove doc comments heuristically. Necessary because syn doesn't understand them
129/// as comments, mand treats them as expressions.
130fn remove_doc_comments(src: &str) -> String {
131    let mut out = vec![];
132    for line in src.lines() {
133        if !line.trim_start().starts_with("///") {
134            out.push(line)
135        }
136    }
137    out.join("\n")
138}
139
140trait SafeLen {
141    /// Returns the displayed length of a string.
142    fn safe_len(&self) -> usize;
143}
144
145impl SafeLen for &str {
146    fn safe_len(&self) -> usize {
147        self.chars().count()
148    }
149}