Skip to content

Commit 0660429

Browse files
authored
Reapply "Initial work on formatting headers" (#6457)
* Reapply "Initial work on formatting headers" This reverts commit f2c84b5.
1 parent e6d1d52 commit 0660429

4 files changed

Lines changed: 147 additions & 6 deletions

File tree

src/header.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//! headers are sets of consecutive keywords and tokens, such as
2+
//! `pub const unsafe fn foo` and `pub(crate) unsafe trait Bar`.
3+
//!
4+
//! This module contains general logic for formatting such headers,
5+
//! where they are always placed on a single line except when there
6+
//! are comments between parts of the header.
7+
8+
use std::borrow::Cow;
9+
10+
use rustc_ast as ast;
11+
use rustc_span::Span;
12+
use rustc_span::symbol::Ident;
13+
use tracing::debug;
14+
15+
use crate::comment::{combine_strs_with_missing_comments, contains_comment};
16+
use crate::rewrite::RewriteContext;
17+
use crate::shape::Shape;
18+
use crate::utils::rewrite_ident;
19+
20+
pub(crate) fn format_header(
21+
context: &RewriteContext<'_>,
22+
shape: Shape,
23+
parts: Vec<HeaderPart<'_>>,
24+
) -> String {
25+
debug!(?parts, "format_header");
26+
let shape = shape.infinite_width();
27+
28+
// Empty `HeaderPart`s are ignored.
29+
let mut parts = parts.into_iter().filter(|x| !x.snippet.is_empty());
30+
let Some(part) = parts.next() else {
31+
return String::new();
32+
};
33+
34+
let mut result = part.snippet.into_owned();
35+
let mut span = part.span;
36+
37+
for part in parts {
38+
debug!(?result, "before combine");
39+
let comments_span = span.between(part.span);
40+
let comments_snippet = context.snippet(comments_span);
41+
result = if contains_comment(comments_snippet) {
42+
// FIXME(fee1-dead): preserve (potentially misaligned) comments instead of reformatting
43+
// them. Revisit this once we have a strategy for properly dealing with them.
44+
format!("{result}{comments_snippet}{}", part.snippet)
45+
} else {
46+
combine_strs_with_missing_comments(
47+
context,
48+
&result,
49+
&part.snippet,
50+
comments_span,
51+
shape,
52+
true,
53+
)
54+
.unwrap_or_else(|_| format!("{} {}", &result, part.snippet))
55+
};
56+
debug!(?result);
57+
span = part.span;
58+
}
59+
60+
result
61+
}
62+
63+
#[derive(Debug)]
64+
pub(crate) struct HeaderPart<'a> {
65+
/// snippet of this part without surrounding space
66+
snippet: Cow<'a, str>,
67+
span: Span,
68+
}
69+
70+
impl<'a> HeaderPart<'a> {
71+
pub(crate) fn new(snippet: impl Into<Cow<'a, str>>, span: Span) -> Self {
72+
Self {
73+
snippet: snippet.into(),
74+
span,
75+
}
76+
}
77+
78+
pub(crate) fn ident(context: &'a RewriteContext<'_>, ident: Ident) -> Self {
79+
Self::new(rewrite_ident(context, ident), ident.span)
80+
}
81+
82+
pub(crate) fn visibility(context: &RewriteContext<'_>, vis: &ast::Visibility) -> Self {
83+
let snippet = match vis.kind {
84+
ast::VisibilityKind::Public => Cow::from("pub"),
85+
ast::VisibilityKind::Inherited => Cow::from(""),
86+
ast::VisibilityKind::Restricted { ref path, .. } => {
87+
let ast::Path { ref segments, .. } = **path;
88+
let mut segments_iter =
89+
segments.iter().map(|seg| rewrite_ident(context, seg.ident));
90+
if path.is_global() {
91+
segments_iter
92+
.next()
93+
.expect("Non-global path in pub(restricted)?");
94+
}
95+
let is_keyword = |s: &str| s == "crate" || s == "self" || s == "super";
96+
let path = segments_iter.collect::<Vec<_>>().join("::");
97+
let in_str = if is_keyword(&path) { "" } else { "in " };
98+
99+
// FIXME(fee1-dead): comments around parens
100+
Cow::from(format!("pub({}{})", in_str, path))
101+
}
102+
};
103+
104+
Self::new(snippet, vis.span)
105+
}
106+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ mod emitter;
7171
mod expr;
7272
mod format_report_formatter;
7373
pub(crate) mod formatting;
74+
pub(crate) mod header;
7475
mod ignore_path;
7576
mod imports;
7677
mod items;

src/macros.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::comment::{
2525
use crate::config::StyleEdition;
2626
use crate::config::lists::*;
2727
use crate::expr::{RhsAssignKind, rewrite_array, rewrite_assign_rhs};
28+
use crate::header::{HeaderPart, format_header};
2829
use crate::lists::{ListFormatting, itemize_list, write_list};
2930
use crate::overflow;
3031
use crate::parse::macros::lazy_static::parse_lazy_static;
@@ -36,7 +37,7 @@ use crate::shape::{Indent, Shape};
3637
use crate::source_map::SpanUtils;
3738
use crate::spanned::Spanned;
3839
use crate::utils::{
39-
NodeIdExt, filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp,
40+
NodeIdExt, filtered_str_fits, indent_next_line, is_empty_line, mk_sp,
4041
remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout,
4142
};
4243
use crate::visitor::FmtVisitor;
@@ -430,14 +431,21 @@ pub(crate) fn rewrite_macro_def(
430431
None => return snippet,
431432
};
432433

433-
let mut result = if def.macro_rules {
434-
String::from("macro_rules!")
434+
let mut header = if def.macro_rules {
435+
let pos = context.snippet_provider.span_after(span, "macro_rules!");
436+
vec![HeaderPart::new("macro_rules!", span.with_hi(pos))]
435437
} else {
436-
format!("{}macro", format_visibility(context, vis))
438+
let macro_lo = context.snippet_provider.span_before(span, "macro");
439+
let macro_hi = macro_lo + BytePos("macro".len() as u32);
440+
vec![
441+
HeaderPart::visibility(context, vis),
442+
HeaderPart::new("macro", mk_sp(macro_lo, macro_hi)),
443+
]
437444
};
438445

439-
result += " ";
440-
result += rewrite_ident(context, ident);
446+
header.push(HeaderPart::ident(context, ident));
447+
448+
let mut result = format_header(context, shape, header);
441449

442450
let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
443451

tests/target/keywords.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
pub // a
2+
macro // b
3+
hi(
4+
// c
5+
) {
6+
// d
7+
}
8+
9+
macro_rules! // a
10+
my_macro {
11+
() => {};
12+
}
13+
14+
// == comments don't get reformatted ==
15+
macro_rules!// a
16+
// b
17+
// c
18+
// d
19+
my_macro {
20+
() => {};
21+
}
22+
23+
macro_rules! /* a block comment */
24+
my_macro {
25+
() => {};
26+
}

0 commit comments

Comments
 (0)