Skip to content

Commit 5ee8434

Browse files
committed
fix rust-lang#6164: Reduce format failure for non default imports_granularity
This patch reduces format failure for non default `imports_granularity` and correct the behavior around some edge cases. - Supports too long line of `use ...` that contains `{}`. - Fixes the width calculation of too long lines of `use ...`.
1 parent 9f8fcc2 commit 5ee8434

15 files changed

+2113
-14
lines changed

src/imports.rs

+103-14
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::config::{Edition, IndentStyle, StyleEdition};
1919
use crate::lists::{
2020
ListFormatting, ListItem, Separator, definitive_tactic, itemize_list, write_list,
2121
};
22-
use crate::rewrite::{Rewrite, RewriteContext, RewriteErrorExt, RewriteResult};
22+
use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
2323
use crate::shape::Shape;
2424
use crate::sort::version_sort;
2525
use crate::source_map::SpanUtils;
@@ -1110,9 +1110,9 @@ impl Rewrite for UseSegment {
11101110
use_tree_list,
11111111
// 1 = "{" and "}"
11121112
shape
1113-
.offset_left_opt(1)
1114-
.and_then(|s| s.sub_width_opt(1))
1115-
.unknown_error()?,
1113+
.offset_left(1)
1114+
.unknown_error()?
1115+
.saturating_sub_width(1),
11161116
)?
11171117
}
11181118
})
@@ -1126,18 +1126,107 @@ impl Rewrite for UseTree {
11261126

11271127
// This does NOT format attributes and visibility or add a trailing `;`.
11281128
fn rewrite_result(&self, context: &RewriteContext<'_>, mut shape: Shape) -> RewriteResult {
1129-
let mut result = String::with_capacity(256);
1130-
let mut iter = self.path.iter().peekable();
1131-
while let Some(segment) = iter.next() {
1132-
let segment_str = segment.rewrite_result(context, shape)?;
1133-
result.push_str(&segment_str);
1134-
if iter.peek().is_some() {
1135-
result.push_str("::");
1136-
// 2 = "::"
1137-
shape = shape.offset_left(2 + segment_str.len(), self.span())?;
1129+
if context.config.style_edition() >= StyleEdition::Edition2024 {
1130+
fn proceed(
1131+
context: &RewriteContext<'_>,
1132+
span: &Span,
1133+
shape: &Shape,
1134+
curr_segment: &UseSegment,
1135+
curr_segment_is_allow_overflow: bool,
1136+
next_segment: Option<&&UseSegment>,
1137+
) -> Result<(String, Shape), RewriteError> {
1138+
let mut rewritten_segment = curr_segment.rewrite_result(context, shape.clone())?;
1139+
if next_segment.is_some() {
1140+
rewritten_segment.push_str("::");
1141+
}
1142+
let reserved_room_for_brace = match next_segment.map(|s| &s.kind) {
1143+
Some(UseSegmentKind::List(_)) => "{".len(),
1144+
_ => 0,
1145+
};
1146+
let next_shape = if matches!(&curr_segment.kind, UseSegmentKind::List(_)) {
1147+
// This is the last segment and we won't use `next_shape`. Return `shape`
1148+
// unchanged.
1149+
shape.clone()
1150+
} else if curr_segment_is_allow_overflow {
1151+
// If the segment follows `use ` or newline, force to consume the segment with
1152+
// overflow.
1153+
1154+
let s = shape.offset_left_maybe_overflow(rewritten_segment.len());
1155+
if s.width == 0 {
1156+
// We have to to commit current segment in this line. Make a room for next
1157+
// round.
1158+
s.add_width(reserved_room_for_brace)
1159+
} else {
1160+
s.clone()
1161+
}
1162+
} else {
1163+
let Some(ret) = shape.offset_left(rewritten_segment.len()) else {
1164+
return Err(RewriteError::ExceedsMaxWidth {
1165+
configured_width: shape.width,
1166+
span: span.clone(),
1167+
});
1168+
};
1169+
// Check that there is a room for the next "{". If not, return an error for
1170+
// retry with newline.
1171+
if ret.offset_left(reserved_room_for_brace).is_none() {
1172+
return Err(RewriteError::ExceedsMaxWidth {
1173+
configured_width: shape.width,
1174+
span: span.clone(),
1175+
});
1176+
}
1177+
ret
1178+
};
1179+
Ok((rewritten_segment, next_shape))
1180+
}
1181+
1182+
let shape_top_level = shape.clone();
1183+
let mut result = String::with_capacity(256);
1184+
let mut is_first = true;
1185+
let mut iter = self.path.iter().peekable();
1186+
let span = self.span();
1187+
while let Some(segment) = iter.next() {
1188+
let allow_overflow = is_first;
1189+
is_first = false;
1190+
match proceed(context, &span, &shape, segment, allow_overflow, iter.peek()) {
1191+
Ok((rewritten_segment, next_shape)) => {
1192+
result.push_str(&rewritten_segment);
1193+
shape = next_shape;
1194+
continue;
1195+
}
1196+
Err(RewriteError::ExceedsMaxWidth { .. }) => {
1197+
// If the first `proceed()` failed with no room, retry with newline.
1198+
}
1199+
Err(e) => {
1200+
// Abort otherwise.
1201+
return Err(e);
1202+
}
1203+
}
1204+
result.push_str("\n");
1205+
result.push_str(&" ".repeat(shape.indent.block_indent + 4));
1206+
shape = shape_top_level.clone();
1207+
let allow_overflow = true;
1208+
let (rewritten_segment, next_shape) =
1209+
proceed(context, &span, &shape, segment, allow_overflow, iter.peek())?;
1210+
result.push_str(&rewritten_segment);
1211+
shape = next_shape;
1212+
}
1213+
Ok(result)
1214+
} else {
1215+
let mut result = String::with_capacity(256);
1216+
let mut iter = self.path.iter().peekable();
1217+
while let Some(segment) = iter.next() {
1218+
let segment_str = segment.rewrite_result(context, shape)?;
1219+
result.push_str(&segment_str);
1220+
if iter.peek().is_some() {
1221+
result.push_str("::");
1222+
// 2 = "::"
1223+
shape = shape
1224+
.offset_left(2 + segment_str.len())
1225+
.max_width_error(shape.width, self.span())?;
1226+
}
11381227
}
1228+
Ok(result)
11391229
}
1140-
Ok(result)
11411230
}
11421231
}
11431232

src/shape.rs

+19
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,29 @@ impl Shape {
286286
.ok_or_else(|| self.exceeds_max_width_error(span))
287287
}
288288

289+
pub(crate) fn add_width(&self, width: usize) -> Shape {
290+
Shape {
291+
width: self.width + width,
292+
..*self
293+
}
294+
}
295+
296+
pub(crate) fn shrink_left(&self, width: usize) -> Option<Shape> {
297+
Some(Shape {
298+
width: self.width.checked_sub(width)?,
299+
indent: self.indent + width,
300+
offset: self.offset + width,
301+
})
302+
}
303+
289304
pub(crate) fn offset_left_opt(&self, delta: usize) -> Option<Shape> {
290305
self.add_offset(delta).sub_width_opt(delta)
291306
}
292307

308+
pub(crate) fn offset_left_maybe_overflow(&self, width: usize) -> Shape {
309+
self.add_offset(width).saturating_sub_width(width)
310+
}
311+
293312
pub(crate) fn used_width(&self) -> usize {
294313
self.indent.block_indent + self.offset
295314
}

tests/source/5131_crate.rs

+150
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,153 @@ use foo::d::e;
1212
use qux::h;
1313
use qux::h as h2;
1414
use qux::i;
15+
16+
mod indent4 {
17+
use column_____________________________________________________________________________________102::{
18+
Foo,
19+
bar::Bar,
20+
bar::baz::Baz,
21+
Foo2,
22+
bar::Bar2,
23+
};
24+
25+
use column_______________________________________________________________________________096::{
26+
Foo,
27+
bar::Bar,
28+
bar::baz::Baz,
29+
Foo2,
30+
bar::Bar2,
31+
};
32+
33+
use column_________________________________________________________________________090::{
34+
Foo,
35+
bar::Bar,
36+
bar::baz::Baz,
37+
Foo2,
38+
bar::Bar2,
39+
};
40+
41+
use c012::c018::c024::c030::c036::c042::c048::c054::c060::c066::c072::c078::c084::c090::c096::c102::{
42+
Foo,
43+
bar::Bar,
44+
bar::baz::Baz,
45+
Foo2,
46+
bar::Bar2,
47+
};
48+
49+
use c012::c018::c024::c030::c036::c042::c048::c054::c060::c066::c072::c078::c084::c090::c096::{
50+
Foo,
51+
bar::Bar,
52+
bar::baz::Baz,
53+
Foo2,
54+
bar::Bar2,
55+
};
56+
57+
use c012::c018::c024::c030::c036::c042::c048::c054::c060::c066::c072::c078::c084::c090::{
58+
Foo,
59+
bar::Bar,
60+
bar::baz::Baz,
61+
Foo2,
62+
bar::Bar2,
63+
};
64+
65+
use c012::c018::c024::c030::c036::c042::c048::c054::c060::c066::c072::c078::c084::{
66+
Foo,
67+
bar::Bar,
68+
bar::baz::Baz,
69+
Foo2,
70+
bar::Bar2,
71+
};
72+
}
73+
74+
use smithay::{
75+
backend::renderer::element::{
76+
default_primary_scanout_output_compare, utils::select_dmabuf_feedback, RenderElementStates,
77+
},
78+
delegate_compositor, delegate_data_control, delegate_data_device, delegate_fractional_scale,
79+
delegate_input_method_manager, delegate_keyboard_shortcuts_inhibit, delegate_layer_shell,
80+
delegate_output, delegate_pointer_constraints, delegate_pointer_gestures,
81+
delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat,
82+
delegate_security_context, delegate_shm, delegate_tablet_manager, delegate_text_input_manager,
83+
delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation,
84+
delegate_xdg_decoration, delegate_xdg_shell,
85+
desktop::{
86+
space::SpaceElement,
87+
utils::{
88+
surface_presentation_feedback_flags_from_states, surface_primary_scanout_output,
89+
update_surface_primary_scanout_output, OutputPresentationFeedback,
90+
},
91+
PopupKind, PopupManager, Space,
92+
},
93+
input::{
94+
keyboard::{Keysym, LedState, XkbConfig},
95+
pointer::{CursorImageStatus, PointerHandle},
96+
Seat, SeatHandler, SeatState,
97+
},
98+
output::Output,
99+
reexports::{
100+
calloop::{generic::Generic, Interest, LoopHandle, Mode, PostAction},
101+
wayland_protocols::xdg::decoration::{
102+
self as xdg_decoration,
103+
zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode,
104+
},
105+
wayland_server::{
106+
backend::{ClientData, ClientId, DisconnectReason},
107+
protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
108+
Display, DisplayHandle, Resource,
109+
},
110+
},
111+
utils::{Clock, Monotonic, Rectangle},
112+
wayland::{
113+
compositor::{get_parent, with_states, CompositorClientState, CompositorState},
114+
dmabuf::DmabufFeedback,
115+
fractional_scale::{
116+
with_fractional_scale, FractionalScaleHandler, FractionalScaleManagerState,
117+
},
118+
input_method::{InputMethodHandler, InputMethodManagerState, PopupSurface},
119+
keyboard_shortcuts_inhibit::{
120+
KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState,
121+
KeyboardShortcutsInhibitor,
122+
},
123+
output::{OutputHandler, OutputManagerState},
124+
pointer_constraints::{
125+
with_pointer_constraint, PointerConstraintsHandler, PointerConstraintsState,
126+
},
127+
pointer_gestures::PointerGesturesState,
128+
presentation::PresentationState,
129+
relative_pointer::RelativePointerManagerState,
130+
seat::WaylandFocus,
131+
security_context::{
132+
SecurityContext, SecurityContextHandler, SecurityContextListenerSource,
133+
SecurityContextState,
134+
},
135+
selection::data_device::{
136+
set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
137+
ServerDndGrabHandler,
138+
},
139+
selection::{
140+
primary_selection::{
141+
set_primary_focus, PrimarySelectionHandler, PrimarySelectionState,
142+
},
143+
wlr_data_control::{DataControlHandler, DataControlState},
144+
SelectionHandler,
145+
},
146+
shell::{
147+
wlr_layer::WlrLayerShellState,
148+
xdg::{
149+
decoration::{XdgDecorationHandler, XdgDecorationState},
150+
ToplevelSurface, XdgShellState, XdgToplevelSurfaceData,
151+
},
152+
},
153+
shm::{ShmHandler, ShmState},
154+
socket::ListeningSocketSource,
155+
tablet_manager::{TabletManagerState, TabletSeatTrait},
156+
text_input::TextInputManagerState,
157+
viewporter::ViewporterState,
158+
virtual_keyboard::VirtualKeyboardManagerState,
159+
xdg_activation::{
160+
XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData,
161+
},
162+
xdg_foreign::{XdgForeignHandler, XdgForeignState},
163+
},
164+
};

0 commit comments

Comments
 (0)