1#![recursion_limit = "512"]
5#![feature(
6 never_type,
7 decl_macro,
8 macro_metavar_expr,
9 macro_metavar_expr_concat,
10 yeet_expr,
11 pattern,
12 unwrap_infallible,
13 substr_range,
14 try_trait_v2,
15 iter_array_chunks,
16 try_trait_v2_residual,
17 associated_type_defaults,
18 macro_derive,
19 debug_closure_helpers,
20 trait_alias,
21 anonymous_lifetime_in_impl_trait,
22 exact_size_is_empty,
23 coverage_attribute,
24 is_ascii_octdigit,
25 trim_prefix_suffix,
26 if_let_guard,
27 str_as_str,
28 thread_local,
29 type_changing_struct_update,
30 try_blocks,
31 closure_lifetime_binder
32)]
33
34pub mod attr;
36pub mod expr;
37pub mod item;
38pub mod lifetime;
39pub mod pat;
40pub mod path;
41pub mod shebang;
42pub mod stmt;
43pub mod token;
44pub mod ty;
45pub mod util;
46pub mod vis;
47
48use {
50 self::{attr::InnerAttrOrDocComment, item::Items, shebang::Shebang},
51 core::fmt::Debug,
52 rustidy_format::{Format, FormatOutput, FormatTag, Formattable, WhitespaceFormat},
53 rustidy_parse::Parse,
54 rustidy_print::Print,
55 rustidy_util::Whitespace,
56};
57
58#[derive(PartialEq, Eq, Clone, Debug)]
60#[derive(serde::Serialize, serde::Deserialize)]
61#[derive(Parse, Formattable, Print)]
62#[parse(name = "a crate")]
63pub struct Crate {
64 pub shebang: Option<Shebang>,
65 pub inner_attrs: Vec<InnerAttrOrDocComment>,
66 pub items: Items,
67 pub suffix_ws: Whitespace,
68}
69
70impl Format<(), ()> for Crate {
71 fn format(
72 &mut self,
73 ctx: &mut rustidy_format::Context,
74 _prefix_ws: (),
75 _args: ()
76 ) -> FormatOutput {
77 let mut ctx = ctx.sub_context();
78 for attr in &self.inner_attrs {
79 if let Some(attr) = attr.try_as_attr_ref() && let Err(err) = attr::update_from_attr(&attr.attr.value, &mut ctx) {
80 tracing::warn!("Malformed `#![rustidy::config(...)]` attribute: {err:?}");
81 }
82 }
83
84 let mut output = FormatOutput::default();
85
86 ctx
87 .format(&mut self.shebang, ())
88 .append_to(&mut output);
89
90 ctx.add_tag(FormatTag::AfterNewline);
93
94 let mut is_first = true;
95 for attr in &mut self.inner_attrs {
96 let prefix_ws = match is_first {
97 true => Whitespace::INDENT_REMOVE_IF_PURE,
98 false => Whitespace::INDENT,
99 };
100 ctx
101 .format(attr, prefix_ws)
102 .append_to(&mut output);
103 is_first = false;
104
105 if let Some(doc) = attr.try_as_doc_comment_ref() && doc.is_line() {
106 ctx.add_tag(FormatTag::AfterNewline);
107 }
108 }
109
110 let prefix_ws = match is_first {
111 true => Whitespace::INDENT_REMOVE_IF_PURE,
112 false => Whitespace::INDENT,
113 };
114 ctx
115 .format(&mut self.items, prefix_ws)
116 .append_to(&mut output);
117
118 ctx.format(
119 &mut self.suffix_ws,
120 Whitespace::indent(output.is_empty)
121 ).append_to(&mut output);
122
123 output
124 }
125}