Rollup merge of #93513 - dtolnay:linewidth, r=nagisa
Allow any pretty printed line to have at least 60 chars Follow-up to #93155. The rustc AST pretty printer has a tendency to get stuck in "vertical smear mode" when formatting highly nested code, where it puts a linebreak at *every possible* linebreak opportunity once the indentation goes beyond the pretty printer's target line width: ```rust ... ((&([("test" as &str)] as [&str; 1]) as &[&str; 1]), (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) ... ``` ```rust ... [(1 as i32), (2 as i32), (3 as i32)] as [i32; 3] ... ``` This is less common after #93155 because that PR greatly reduced the total amount of indentation, but the "vertical smear mode" failure mode is still just as present when you have deeply nested modules, functions, or trait impls, such as in the case of macro-expanded code from `-Zunpretty=expanded`. Vertical smear mode is never the best way to format highly indented code though. It does not prevent the target line width from being exceeded, and it produces output that is less readable than just a longer line. This PR makes the pretty printing algorithm allow a minimum of 60 chars on every line independent of indentation. So as code gets more indented, the right margin eventually recedes to make room for formatting without vertical smear. ```console ├─────────────────────────────────────┤ ├─────────────────────────────────────┤ ├─────────────────────────────────────┤ ├───────────────────────────────────┤ ├─────────────────────────────────┤ ├───────────────────────────────┤ ├─────────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├───────────────────────────┤ ├─────────────────────────────┤ ├───────────────────────────────┤ ├─────────────────────────────────┤ ├───────────────────────────────────┤ ├─────────────────────────────────────┤ ```
This commit is contained in:
commit
2e39a3f6ec
4 changed files with 13 additions and 14 deletions
|
@ -136,6 +136,7 @@ mod ring;
|
|||
|
||||
use ring::RingBuffer;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp;
|
||||
use std::collections::VecDeque;
|
||||
use std::iter;
|
||||
|
||||
|
@ -199,10 +200,13 @@ enum PrintFrame {
|
|||
|
||||
const SIZE_INFINITY: isize = 0xffff;
|
||||
|
||||
/// Target line width.
|
||||
const MARGIN: isize = 78;
|
||||
/// Every line is allowed at least this much space, even if highly indented.
|
||||
const MIN_SPACE: isize = 60;
|
||||
|
||||
pub struct Printer {
|
||||
out: String,
|
||||
/// Width of lines we're constrained to
|
||||
margin: isize,
|
||||
/// Number of spaces left on line
|
||||
space: isize,
|
||||
/// Ring-buffer of tokens and calculated sizes
|
||||
|
@ -237,11 +241,9 @@ struct BufEntry {
|
|||
|
||||
impl Printer {
|
||||
pub fn new() -> Self {
|
||||
let linewidth = 78;
|
||||
Printer {
|
||||
out: String::new(),
|
||||
margin: linewidth as isize,
|
||||
space: linewidth as isize,
|
||||
space: MARGIN,
|
||||
buf: RingBuffer::new(),
|
||||
left_total: 0,
|
||||
right_total: 0,
|
||||
|
@ -395,7 +397,7 @@ impl Printer {
|
|||
self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
|
||||
self.indent = match token.indent {
|
||||
IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
|
||||
IndentStyle::Visual => (self.margin - self.space) as usize,
|
||||
IndentStyle::Visual => (MARGIN - self.space) as usize,
|
||||
};
|
||||
} else {
|
||||
self.print_stack.push(PrintFrame::Fits);
|
||||
|
@ -421,7 +423,7 @@ impl Printer {
|
|||
self.out.push('\n');
|
||||
let indent = self.indent as isize + token.offset;
|
||||
self.pending_indentation = indent;
|
||||
self.space = self.margin - indent;
|
||||
self.space = cmp::max(MARGIN - indent, MIN_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ pub fn bar() ({
|
|||
for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
|
||||
as
|
||||
fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
|
||||
as &str)] as [&str; 1]) as
|
||||
&[&str; 1]),
|
||||
as &str)] as [&str; 1]) as &[&str; 1]),
|
||||
(&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as
|
||||
Arguments)) as String);
|
||||
(res as String)
|
||||
|
|
|
@ -11,7 +11,6 @@ pub fn main() ({
|
|||
({ } as
|
||||
()) else if (let Some(a) =
|
||||
((Some as
|
||||
fn(i32) -> Option<i32> {Option::<i32>::Some})((3
|
||||
as i32)) as Option<i32>) as bool) ({ } as ())
|
||||
as ())
|
||||
fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
|
||||
Option<i32>) as bool) ({ } as ()) as ())
|
||||
} as ())
|
||||
|
|
|
@ -27,8 +27,7 @@ fn main() {
|
|||
crate::TokenStream::from(crate::TokenTree::Literal({
|
||||
let mut iter =
|
||||
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
|
||||
if let (Some(crate::TokenTree::Literal(mut lit)),
|
||||
None) =
|
||||
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
|
||||
(iter.next(), iter.next()) {
|
||||
lit.set_span(crate::Span::recover_proc_macro_span(2));
|
||||
lit
|
||||
|
|
Loading…
Add table
Reference in a new issue