1pub mod with;
5pub mod meta;
6
7pub use self::with::{BracedWithInnerAttributes, WithOuterAttributes};
9
10use {
12 super::{
13 expr::Expression,
14 path::SimplePath,
15 token,
16 util::{Braced, Bracketed, Parenthesized},
17 },
18 self::meta::MetaItem,
19 app_error::{AppError, Context, bail},
20 core::fmt::Debug,
21 rustidy_ast_util::{Longest, RemainingBlockComment, RemainingLine, delimited},
22 rustidy_format::{Format, Formattable, WhitespaceFormat},
23 rustidy_parse::{ParsableFrom, Parse, ParserTag},
24 rustidy_print::Print,
25 rustidy_util::{Config, Whitespace},
26};
27
28#[derive(PartialEq, Eq, Clone, Debug)]
29#[derive(strum::EnumTryAs)]
30#[derive(serde::Serialize, serde::Deserialize)]
31#[derive(Parse, Formattable, Format, Print)]
32pub enum InnerAttrOrDocComment {
33 Attr(InnerAttribute),
34 DocComment(InnerDocComment),
35}
36
37#[derive(PartialEq, Eq, Clone, Debug)]
39#[derive(serde::Serialize, serde::Deserialize)]
40#[derive(Parse, Formattable, Format, Print)]
41#[parse(name = "an inner attribute")]
42pub struct InnerAttribute {
43 pub pound: token::Pound,
44 #[format(prefix_ws = Whitespace::REMOVE)]
45 pub not: token::Not,
46 #[parse(fatal)]
47 #[format(prefix_ws = Whitespace::REMOVE)]
48 #[format(args = delimited::FmtRemove)]
49 pub attr: Bracketed<AttrOrMetaItem>,
50}
51
52#[derive(PartialEq, Eq, Clone, Debug)]
54#[derive(strum::EnumIs)]
55#[derive(serde::Serialize, serde::Deserialize)]
56#[derive(Parse, Formattable, Format, Print)]
57pub enum InnerDocComment {
58 Line(InnerLineDoc),
59 Block(InnerBlockDoc),
60}
61
62#[derive(PartialEq, Eq, Clone, Debug)]
64#[derive(serde::Serialize, serde::Deserialize)]
65#[derive(Parse, Formattable, Format, Print)]
66pub struct InnerLineDoc {
67 pub prefix: token::InnerLineDoc,
68 #[format(prefix_ws = ())]
69 pub comment: RemainingLine,
70}
71
72#[derive(PartialEq, Eq, Clone, Debug)]
74#[derive(serde::Serialize, serde::Deserialize)]
75#[derive(Parse, Formattable, Format, Print)]
76pub struct InnerBlockDoc {
77 pub prefix: token::InnerBlockDoc,
78 pub comment: RemainingBlockComment,
79}
80
81#[derive(PartialEq, Eq, Clone, Debug)]
83#[derive(strum::EnumTryAs)]
84#[derive(serde::Serialize, serde::Deserialize)]
85#[derive(Parse, Formattable, Format, Print)]
86pub enum OuterAttrOrDocComment {
87 Attr(OuterAttribute),
88 DocComment(OuterDocComment),
89}
90
91#[derive(PartialEq, Eq, Clone, Debug)]
93#[derive(serde::Serialize, serde::Deserialize)]
94#[derive(Parse, Formattable, Format, Print)]
95pub struct OuterAttribute {
96 pub pound: token::Pound,
97 #[format(prefix_ws = Whitespace::REMOVE)]
98 #[format(args = delimited::FmtRemove)]
99 pub open: Bracketed<AttrOrMetaItem>,
100}
101
102#[derive(PartialEq, Eq, Clone, Debug)]
104#[derive(strum::EnumTryAs)]
105#[derive(serde::Serialize, serde::Deserialize)]
106#[derive(Parse, Formattable, Format, Print)]
107pub enum OuterDocComment {
108 Line(OuterLineDoc),
109 Block(OuterBlockDoc),
110}
111
112#[derive(PartialEq, Eq, Clone, Debug)]
114#[derive(serde::Serialize, serde::Deserialize)]
115#[derive(Parse, Formattable, Format, Print)]
116pub struct OuterLineDoc {
117 pub prefix: token::OuterLineDoc,
118 #[format(prefix_ws = ())]
119 pub comment: RemainingLine,
120}
121
122#[derive(PartialEq, Eq, Clone, Debug)]
124#[derive(serde::Serialize, serde::Deserialize)]
125#[derive(Parse, Formattable, Format, Print)]
126pub struct OuterBlockDoc {
127 pub prefix: token::OuterBlockDoc,
128 pub comment: RemainingBlockComment,
131}
132
133#[derive(PartialEq, Eq, Clone, Debug)]
134#[derive(strum::EnumTryAs)]
135#[derive(serde::Serialize, serde::Deserialize)]
136#[derive(Parse, Formattable, Format, Print)]
137#[parse(from = Longest::<Attr, MetaItem>)]
138pub enum AttrOrMetaItem {
139 Meta(MetaItem),
140 Attr(Attr),
141}
142
143impl ParsableFrom<Longest<Attr, MetaItem>> for AttrOrMetaItem {
144 fn from_parsable(value: Longest<Attr, MetaItem>) -> Self {
145 match value {
146 Longest::Left(attr) => Self::Attr(attr),
147 Longest::Right(meta) => Self::Meta(meta),
148 }
149 }
150}
151
152#[derive(PartialEq, Eq, Clone, Debug)]
154#[derive(serde::Serialize, serde::Deserialize)]
155#[derive(Parse, Formattable, Format, Print)]
156pub struct Attr {
157 pub path: SimplePath,
159 #[format(prefix_ws = Whitespace::PRESERVE)]
160 pub input: Option<AttrInput>,
161}
162
163#[derive(PartialEq, Eq, Clone, Debug)]
165#[derive(serde::Serialize, serde::Deserialize)]
166#[derive(Parse, Formattable, Format, Print)]
167pub enum AttrInput {
168 #[format(prefix_ws = Whitespace::REMOVE)]
169 DelimTokenTree(DelimTokenTree),
170 #[format(prefix_ws = Whitespace::SINGLE)]
171 EqExpr(AttrInputEqExpr),
172}
173
174#[derive(PartialEq, Eq, Clone, Debug)]
175#[derive(serde::Serialize, serde::Deserialize)]
176#[derive(Parse, Formattable, Format, Print)]
177pub struct AttrInputEqExpr {
178 pub eq: token::Eq,
179 #[format(prefix_ws = Whitespace::SINGLE)]
180 pub expr: Expression,
181}
182
183#[derive(PartialEq, Eq, Clone, Debug)]
185#[derive(serde::Serialize, serde::Deserialize)]
186#[derive(Parse, Formattable, Format, Print)]
187pub enum DelimTokenTree {
188 #[format(args = delimited::fmt_preserve())]
189 Parens(Parenthesized<DelimTokenTreeInner>),
190 #[format(args = delimited::fmt_preserve())]
191 Brackets(Bracketed<DelimTokenTreeInner>),
192 #[format(args = delimited::fmt_preserve())]
193 Braces(Braced<DelimTokenTreeInner>),
194}
195
196#[derive(PartialEq, Eq, Clone, Debug)]
197#[derive(serde::Serialize, serde::Deserialize)]
198#[derive(Parse, Formattable, Format, Print)]
199pub struct DelimTokenTreeInner(
200 #[parse(fatal)]
201 #[format(args = rustidy_format::vec::args_prefix_ws(Whitespace::PRESERVE))]
202 pub Vec<TokenTree>,
203);
204
205#[derive(PartialEq, Eq, Clone, Debug)]
207#[derive(serde::Serialize, serde::Deserialize)]
208#[derive(Parse, Formattable, Format, Print)]
209pub enum TokenTree {
210 Tree(DelimTokenTree),
211 Token(TokenNonDelimited),
212}
213
214#[derive(PartialEq, Eq, Clone, Debug)]
216#[derive(serde::Serialize, serde::Deserialize)]
217#[derive(Parse, Formattable, Format, Print)]
218pub struct TokenNonDelimited(#[parse(with_tag = ParserTag::SkipDelimiters)] pub token::Token);
219
220pub fn update_from_attr(attr: &AttrOrMetaItem, ctx: &mut rustidy_format::Context) -> Result<(), AppError> {
223 let meta = match attr {
224 AttrOrMetaItem::Meta(meta) => match meta.path().starts_with("rustidy") {
225 true => meta,
226 false => return Ok(()),
227 },
228 AttrOrMetaItem::Attr(attr) => match attr.path.starts_with("rustidy") {
229 true => bail!("`#[rustidy]` attributes must be meta items"),
230 false => return Ok(()),
231 },
232 };
233
234 match meta.path().as_str().as_str() {
235 "rustidy::config" => self::update_config(meta, ctx)?,
236 "rustidy::skip" => ctx.config_mut().skip = true,
237 path => bail!("Unknown `#[rustidy]` attribute: {path:?}"),
238 }
239
240 Ok(())
241}
242
243fn update_config(meta: &MetaItem, ctx: &mut rustidy_format::Context) -> Result<(), AppError> {
245 let MetaItem::Seq(meta) = meta else {
246 bail!("Expected `rustidy::config([...])`");
247 };
248
249 let Some(configs) = &meta.seq.value else {
250 return Ok(())
251 };
252
253 for config in configs.0.values() {
254 let config = try {
255 config.try_as_meta_ref()?.try_as_eq_expr_ref()?
256 };
257 let Some(config) = config else {
258 bail!("Expected `rustidy::config(<config-name> = <value>)`");
259 };
260
261 macro str() {
262 config
263 .expr
264 .as_string_literal()
265 .context("Expected a string literal")?
266 .contents()
267 }
268 macro int() {
269 config
270 .expr
271 .as_integer_literal()
272 .context("Expected an integer literal")?
273 .value()
274 .context("Unable to parse integer")?
275 .try_into()
276 .expect("`u64` didn't fit into `usize`")
277 }
278
279 macro fields(
280 $( $field:ident = $value:expr ),* $(,)?
281 ) {
282 let Config {
283 $( $field, )*
284
285 skip: _,
287 } = ctx.config_mut();
288
289 match config.path.as_str().as_str() {
290 $(
291 stringify!($field) => *$field = $value,
292 )*
293 ident => bail!("Unknown configuration: {ident:?}"),
294 }
295 }
296
297 fields! {
299 indent = str!().into(),
300 min_empty_lines = int!(),
301 max_empty_lines = int!(),
302 max_use_tree_len = int!(),
303 array_expr_cols = Some(int!()),
304 max_array_expr_len = int!(),
305 max_chain_len = int!(),
306 max_inline_tuple_struct_len = int!(),
307 }
308 };
309
310 Ok(())
311}