Skip to main content

rustidy_ast/
lib.rs

1//! Syntax tree
2
3// Features
4#![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
34// Modules
35pub 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
48// Imports
49use {
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/// `Crate`
59#[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		// Note: We always say we're after a newline to ensure any comments
91		//       aren't forced to have a newline before them.
92		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}