1use std::borrow::Cow;
59use std::cmp::min;
60
61use rustc_ast::{ast, ptr};
62use rustc_span::{BytePos, Span, symbol};
63use tracing::debug;
64
65use crate::comment::{CharClasses, FullCodeCharKind, RichChar, rewrite_comment};
66use crate::config::{IndentStyle, StyleEdition};
67use crate::expr::rewrite_call;
68use crate::lists::extract_pre_comment;
69use crate::macros::convert_try_mac;
70use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
71use crate::shape::Shape;
72use crate::source_map::SpanUtils;
73use crate::utils::{
74 self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp,
75 rewrite_ident, trimmed_last_line_width, wrap_str,
76};
77
78use thin_vec::ThinVec;
79
80fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option<String> {
83 context.snippet_provider.span_to_snippet(span).map(|s| {
87 s.lines()
88 .map(|l| l.trim_end())
89 .collect::<Vec<_>>()
90 .join("\n")
91 })
92}
93
94fn format_chain_item(
95 item: &ChainItem,
96 context: &RewriteContext<'_>,
97 rewrite_shape: Shape,
98 allow_overflow: bool,
99) -> RewriteResult {
100 if allow_overflow {
101 item.rewrite_result(context, rewrite_shape)
106 .or_else(|_| format_overflow_style(item.span, context).unknown_error())
107 } else {
108 item.rewrite_result(context, rewrite_shape)
109 }
110}
111
112fn get_block_child_shape(
113 prev_ends_with_block: bool,
114 context: &RewriteContext<'_>,
115 shape: Shape,
116) -> Shape {
117 if prev_ends_with_block {
118 shape.block_indent(0)
119 } else {
120 shape.block_indent(context.config.tab_spaces())
121 }
122 .with_max_width(context.config)
123}
124
125fn get_visual_style_child_shape(
126 context: &RewriteContext<'_>,
127 shape: Shape,
128 offset: usize,
129 parent_overflowing: bool,
130) -> Option<Shape> {
131 if !parent_overflowing {
132 shape
133 .with_max_width(context.config)
134 .offset_left(offset)
135 .map(|s| s.visual_indent(0))
136 } else {
137 Some(shape.visual_indent(offset))
138 }
139}
140
141pub(crate) fn rewrite_chain(
142 expr: &ast::Expr,
143 context: &RewriteContext<'_>,
144 shape: Shape,
145) -> RewriteResult {
146 let chain = Chain::from_ast(expr, context);
147 debug!("rewrite_chain {:?} {:?}", chain, shape);
148
149 if chain.children.is_empty() {
152 return chain.parent.rewrite_result(context, shape);
153 }
154
155 chain.rewrite_result(context, shape)
156}
157
158#[derive(Debug)]
159enum CommentPosition {
160 Back,
161 Top,
162}
163
164struct SubExpr {
166 expr: ast::Expr,
167 is_method_call_receiver: bool,
168}
169
170#[derive(Debug)]
172struct ChainItem {
173 kind: ChainItemKind,
174 tries: usize,
175 span: Span,
176}
177
178#[derive(Debug)]
182enum ChainItemKind {
183 Parent {
184 expr: ast::Expr,
185 parens: bool,
186 },
187 MethodCall(
188 ast::PathSegment,
189 Vec<ast::GenericArg>,
190 ThinVec<ptr::P<ast::Expr>>,
191 ),
192 StructField(symbol::Ident),
193 TupleField(symbol::Ident, bool),
194 Await,
195 Yield,
196 Comment(String, CommentPosition),
197}
198
199impl ChainItemKind {
200 fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
201 match self {
202 ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
203 ChainItemKind::MethodCall(..)
204 | ChainItemKind::StructField(..)
205 | ChainItemKind::TupleField(..)
206 | ChainItemKind::Await
207 | ChainItemKind::Yield
208 | ChainItemKind::Comment(..) => false,
209 }
210 }
211
212 fn is_tup_field_access(expr: &ast::Expr) -> bool {
213 match expr.kind {
214 ast::ExprKind::Field(_, ref field) => {
215 field.name.as_str().chars().all(|c| c.is_digit(10))
216 }
217 _ => false,
218 }
219 }
220
221 fn from_ast(
222 context: &RewriteContext<'_>,
223 expr: &ast::Expr,
224 is_method_call_receiver: bool,
225 ) -> (ChainItemKind, Span) {
226 let (kind, span) = match expr.kind {
227 ast::ExprKind::MethodCall(ref call) => {
228 let types = if let Some(ref generic_args) = call.seg.args {
229 if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
230 data.args
231 .iter()
232 .filter_map(|x| match x {
233 ast::AngleBracketedArg::Arg(ref generic_arg) => {
234 Some(generic_arg.clone())
235 }
236 _ => None,
237 })
238 .collect::<Vec<_>>()
239 } else {
240 vec![]
241 }
242 } else {
243 vec![]
244 };
245 let span = mk_sp(call.receiver.span.hi(), expr.span.hi());
246 let kind = ChainItemKind::MethodCall(call.seg.clone(), types, call.args.clone());
247 (kind, span)
248 }
249 ast::ExprKind::Field(ref nested, field) => {
250 let kind = if Self::is_tup_field_access(expr) {
251 ChainItemKind::TupleField(field, Self::is_tup_field_access(nested))
252 } else {
253 ChainItemKind::StructField(field)
254 };
255 let span = mk_sp(nested.span.hi(), field.span.hi());
256 (kind, span)
257 }
258 ast::ExprKind::Await(ref nested, _) => {
259 let span = mk_sp(nested.span.hi(), expr.span.hi());
260 (ChainItemKind::Await, span)
261 }
262 ast::ExprKind::Yield(ast::YieldKind::Postfix(ref nested)) => {
263 let span = mk_sp(nested.span.hi(), expr.span.hi());
264 (ChainItemKind::Yield, span)
265 }
266 _ => {
267 return (
268 ChainItemKind::Parent {
269 expr: expr.clone(),
270 parens: is_method_call_receiver && should_add_parens(expr),
271 },
272 expr.span,
273 );
274 }
275 };
276
277 let lo = context.snippet_provider.span_before(span, ".");
279 (kind, mk_sp(lo, span.hi()))
280 }
281}
282
283impl Rewrite for ChainItem {
284 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
285 self.rewrite_result(context, shape).ok()
286 }
287
288 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
289 let shape = shape
290 .sub_width(self.tries)
291 .max_width_error(shape.width, self.span)?;
292 let rewrite = match self.kind {
293 ChainItemKind::Parent {
294 ref expr,
295 parens: true,
296 } => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
297 ChainItemKind::Parent {
298 ref expr,
299 parens: false,
300 } => expr.rewrite_result(context, shape)?,
301 ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
302 Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
303 }
304 ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)),
305 ChainItemKind::TupleField(ident, nested) => format!(
306 "{}.{}",
307 if nested && context.config.style_edition() <= StyleEdition::Edition2021 {
308 " "
309 } else {
310 ""
311 },
312 rewrite_ident(context, ident)
313 ),
314 ChainItemKind::Await => ".await".to_owned(),
315 ChainItemKind::Yield => ".yield".to_owned(),
316 ChainItemKind::Comment(ref comment, _) => {
317 rewrite_comment(comment, false, shape, context.config)?
318 }
319 };
320 Ok(format!("{rewrite}{}", "?".repeat(self.tries)))
321 }
322}
323
324impl ChainItem {
325 fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
326 let (kind, span) =
327 ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
328 ChainItem { kind, tries, span }
329 }
330
331 fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem {
332 ChainItem {
333 kind: ChainItemKind::Comment(comment, pos),
334 tries: 0,
335 span,
336 }
337 }
338
339 fn is_comment(&self) -> bool {
340 matches!(self.kind, ChainItemKind::Comment(..))
341 }
342
343 fn rewrite_method_call(
344 method_name: symbol::Ident,
345 types: &[ast::GenericArg],
346 args: &[ptr::P<ast::Expr>],
347 span: Span,
348 context: &RewriteContext<'_>,
349 shape: Shape,
350 ) -> RewriteResult {
351 let type_str = if types.is_empty() {
352 String::new()
353 } else {
354 let type_list = types
355 .iter()
356 .map(|ty| ty.rewrite_result(context, shape))
357 .collect::<Result<Vec<_>, RewriteError>>()?;
358
359 format!("::<{}>", type_list.join(", "))
360 };
361 let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
362 rewrite_call(context, &callee_str, &args, span, shape)
363 }
364}
365
366#[derive(Debug)]
367struct Chain {
368 parent: ChainItem,
369 children: Vec<ChainItem>,
370}
371
372impl Chain {
373 fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain {
374 let subexpr_list = Self::make_subexpr_list(expr, context);
375
376 let mut rev_children = vec![];
378 let mut sub_tries = 0;
379 for subexpr in &subexpr_list {
380 match subexpr.expr.kind {
381 ast::ExprKind::Try(_) => sub_tries += 1,
382 _ => {
383 rev_children.push(ChainItem::new(context, subexpr, sub_tries));
384 sub_tries = 0;
385 }
386 }
387 }
388
389 fn is_tries(s: &str) -> bool {
390 s.chars().all(|c| c == '?')
391 }
392
393 fn is_post_comment(s: &str) -> bool {
394 let comment_start_index = s.chars().position(|c| c == '/');
395 if comment_start_index.is_none() {
396 return false;
397 }
398
399 let newline_index = s.chars().position(|c| c == '\n');
400 if newline_index.is_none() {
401 return true;
402 }
403
404 comment_start_index.unwrap() < newline_index.unwrap()
405 }
406
407 fn handle_post_comment(
408 post_comment_span: Span,
409 post_comment_snippet: &str,
410 prev_span_end: &mut BytePos,
411 children: &mut Vec<ChainItem>,
412 ) {
413 let white_spaces: &[_] = &[' ', '\t'];
414 if post_comment_snippet
415 .trim_matches(white_spaces)
416 .starts_with('\n')
417 {
418 return;
420 }
421 let trimmed_snippet = trim_tries(post_comment_snippet);
422 if is_post_comment(&trimmed_snippet) {
423 children.push(ChainItem::comment(
424 post_comment_span,
425 trimmed_snippet.trim().to_owned(),
426 CommentPosition::Back,
427 ));
428 *prev_span_end = post_comment_span.hi();
429 }
430 }
431
432 let parent = rev_children.pop().unwrap();
433 let mut children = vec![];
434 let mut prev_span_end = parent.span.hi();
435 let mut iter = rev_children.into_iter().rev().peekable();
436 if let Some(first_chain_item) = iter.peek() {
437 let comment_span = mk_sp(prev_span_end, first_chain_item.span.lo());
438 let comment_snippet = context.snippet(comment_span);
439 if !is_tries(comment_snippet.trim()) {
440 handle_post_comment(
441 comment_span,
442 comment_snippet,
443 &mut prev_span_end,
444 &mut children,
445 );
446 }
447 }
448 while let Some(chain_item) = iter.next() {
449 let comment_snippet = context.snippet(chain_item.span);
450 let handle_comment =
452 !(context.config.use_try_shorthand() || is_tries(comment_snippet.trim()));
453
454 if handle_comment {
456 let pre_comment_span = mk_sp(prev_span_end, chain_item.span.lo());
457 let pre_comment_snippet = trim_tries(context.snippet(pre_comment_span));
458 let (pre_comment, _) = extract_pre_comment(&pre_comment_snippet);
459 match pre_comment {
460 Some(ref comment) if !comment.is_empty() => {
461 children.push(ChainItem::comment(
462 pre_comment_span,
463 comment.to_owned(),
464 CommentPosition::Top,
465 ));
466 }
467 _ => (),
468 }
469 }
470
471 prev_span_end = chain_item.span.hi();
472 children.push(chain_item);
473
474 if !handle_comment || iter.peek().is_none() {
476 continue;
477 }
478
479 let next_lo = iter.peek().unwrap().span.lo();
480 let post_comment_span = mk_sp(prev_span_end, next_lo);
481 let post_comment_snippet = context.snippet(post_comment_span);
482 handle_post_comment(
483 post_comment_span,
484 post_comment_snippet,
485 &mut prev_span_end,
486 &mut children,
487 );
488 }
489
490 Chain { parent, children }
491 }
492
493 fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
496 let mut subexpr_list = vec![SubExpr {
497 expr: expr.clone(),
498 is_method_call_receiver: false,
499 }];
500
501 while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
502 subexpr_list.push(subexpr);
503 }
504
505 subexpr_list
506 }
507
508 fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
511 match expr.expr.kind {
512 ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
513 expr: Self::convert_try(&call.receiver, context),
514 is_method_call_receiver: true,
515 }),
516 ast::ExprKind::Field(ref subexpr, _)
517 | ast::ExprKind::Try(ref subexpr)
518 | ast::ExprKind::Await(ref subexpr, _)
519 | ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr {
520 expr: Self::convert_try(subexpr, context),
521 is_method_call_receiver: false,
522 }),
523 _ => None,
524 }
525 }
526
527 fn convert_try(expr: &ast::Expr, context: &RewriteContext<'_>) -> ast::Expr {
528 match expr.kind {
529 ast::ExprKind::MacCall(ref mac) if context.config.use_try_shorthand() => {
530 if let Some(subexpr) = convert_try_mac(mac, context) {
531 subexpr
532 } else {
533 expr.clone()
534 }
535 }
536 _ => expr.clone(),
537 }
538 }
539}
540
541impl Rewrite for Chain {
542 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
543 self.rewrite_result(context, shape).ok()
544 }
545
546 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
547 debug!("rewrite chain {:?} {:?}", self, shape);
548
549 let mut formatter = match context.config.indent_style() {
550 IndentStyle::Block => {
551 Box::new(ChainFormatterBlock::new(self)) as Box<dyn ChainFormatter>
552 }
553 IndentStyle::Visual => {
554 Box::new(ChainFormatterVisual::new(self)) as Box<dyn ChainFormatter>
555 }
556 };
557
558 formatter.format_root(&self.parent, context, shape)?;
559 if let Some(result) = formatter.pure_root() {
560 return wrap_str(result, context.config.max_width(), shape)
561 .max_width_error(shape.width, self.parent.span);
562 }
563
564 let first = self.children.first().unwrap_or(&self.parent);
565 let last = self.children.last().unwrap_or(&self.parent);
566 let children_span = mk_sp(first.span.lo(), last.span.hi());
567 let full_span = self.parent.span.with_hi(children_span.hi());
568
569 let child_shape = formatter
571 .child_shape(context, shape)
572 .max_width_error(shape.width, children_span)?;
573
574 formatter.format_children(context, child_shape)?;
575 formatter.format_last_child(context, shape, child_shape)?;
576
577 let result = formatter.join_rewrites(context, child_shape)?;
578 wrap_str(result, context.config.max_width(), shape).max_width_error(shape.width, full_span)
579 }
580}
581
582trait ChainFormatter {
587 fn format_root(
596 &mut self,
597 parent: &ChainItem,
598 context: &RewriteContext<'_>,
599 shape: Shape,
600 ) -> Result<(), RewriteError>;
601 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape>;
602 fn format_children(
603 &mut self,
604 context: &RewriteContext<'_>,
605 child_shape: Shape,
606 ) -> Result<(), RewriteError>;
607 fn format_last_child(
608 &mut self,
609 context: &RewriteContext<'_>,
610 shape: Shape,
611 child_shape: Shape,
612 ) -> Result<(), RewriteError>;
613 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult;
614 fn pure_root(&mut self) -> Option<String>;
616}
617
618struct ChainFormatterShared<'a> {
621 children: &'a [ChainItem],
623 rewrites: Vec<String>,
626 fits_single_line: bool,
628 child_count: usize,
631 allow_overflow: bool,
633}
634
635impl<'a> ChainFormatterShared<'a> {
636 fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
637 ChainFormatterShared {
638 children: &chain.children,
639 rewrites: Vec::with_capacity(chain.children.len() + 1),
640 fits_single_line: false,
641 child_count: chain.children.len(),
642 allow_overflow: false,
644 }
645 }
646
647 fn pure_root(&mut self) -> Option<String> {
648 if self.children.is_empty() {
649 assert_eq!(self.rewrites.len(), 1);
650 Some(self.rewrites.pop().unwrap())
651 } else {
652 None
653 }
654 }
655
656 fn format_children(
657 &mut self,
658 context: &RewriteContext<'_>,
659 child_shape: Shape,
660 ) -> Result<(), RewriteError> {
661 for item in &self.children[..self.children.len() - 1] {
662 let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
663 self.rewrites.push(rewrite);
664 }
665 Ok(())
666 }
667
668 fn format_last_child(
701 &mut self,
702 may_extend: bool,
703 context: &RewriteContext<'_>,
704 shape: Shape,
705 child_shape: Shape,
706 ) -> Result<(), RewriteError> {
707 let last = self.children.last().unknown_error()?;
708 let extendable = may_extend && last_line_extendable(&self.rewrites[0]);
709 let prev_last_line_width = last_line_width(&self.rewrites[0]);
710
711 let almost_total = if extendable {
713 prev_last_line_width
714 } else {
715 self.rewrites
716 .iter()
717 .map(|rw| utils::unicode_str_width(rw))
718 .sum()
719 } + last.tries;
720 let one_line_budget = if self.child_count == 1 {
721 shape.width
722 } else {
723 min(shape.width, context.config.chain_width())
724 }
725 .saturating_sub(almost_total);
726
727 let all_in_one_line = !self.children.iter().any(ChainItem::is_comment)
728 && self.rewrites.iter().all(|s| !s.contains('\n'))
729 && one_line_budget > 0;
730 let last_shape = if all_in_one_line {
731 shape
732 .sub_width(last.tries)
733 .max_width_error(shape.width, last.span)?
734 } else if extendable {
735 child_shape
736 .sub_width(last.tries)
737 .max_width_error(child_shape.width, last.span)?
738 } else {
739 child_shape
740 .sub_width(shape.rhs_overhead(context.config) + last.tries)
741 .max_width_error(child_shape.width, last.span)?
742 };
743
744 let mut last_subexpr_str = None;
745 if all_in_one_line || extendable {
746 let one_line_shape = if context.use_block_indent() {
749 last_shape.offset_left(almost_total)
750 } else {
751 last_shape
752 .visual_indent(almost_total)
753 .sub_width(almost_total)
754 };
755
756 if let Some(one_line_shape) = one_line_shape {
757 if let Ok(rw) = last.rewrite_result(context, one_line_shape) {
758 let line_count = rw.lines().count();
762 let could_fit_single_line = first_line_width(&rw) <= one_line_budget;
763 if could_fit_single_line && line_count >= 5 {
764 last_subexpr_str = Some(rw);
765 self.fits_single_line = all_in_one_line;
766 } else {
767 let last_shape = child_shape
772 .sub_width(shape.rhs_overhead(context.config) + last.tries)
773 .max_width_error(child_shape.width, last.span)?;
774 match last.rewrite_result(context, last_shape) {
775 Ok(ref new_rw) if !could_fit_single_line => {
776 last_subexpr_str = Some(new_rw.clone());
777 }
778 Ok(ref new_rw) if new_rw.lines().count() >= line_count => {
779 last_subexpr_str = Some(rw);
780 self.fits_single_line = could_fit_single_line && all_in_one_line;
781 }
782 Ok(new_rw) => {
783 last_subexpr_str = Some(new_rw);
784 }
785 _ => {
786 last_subexpr_str = Some(rw);
787 self.fits_single_line = could_fit_single_line && all_in_one_line;
788 }
789 }
790 }
791 }
792 }
793 }
794
795 let last_shape = if context.use_block_indent() {
796 last_shape
797 } else {
798 child_shape
799 .sub_width(shape.rhs_overhead(context.config) + last.tries)
800 .max_width_error(child_shape.width, last.span)?
801 };
802
803 let last_subexpr_str =
804 last_subexpr_str.unwrap_or(last.rewrite_result(context, last_shape)?);
805 self.rewrites.push(last_subexpr_str);
806 Ok(())
807 }
808
809 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
810 let connector = if self.fits_single_line {
811 Cow::from("")
813 } else {
814 if context.force_one_line_chain.get() {
816 return Err(RewriteError::ExceedsMaxWidth {
817 configured_width: child_shape.width,
818 span: self.children.last().unknown_error()?.span,
819 });
820 }
821 child_shape.to_string_with_newline(context.config)
822 };
823
824 let mut rewrite_iter = self.rewrites.iter();
825 let mut result = rewrite_iter.next().unwrap().clone();
826 let children_iter = self.children.iter();
827 let iter = rewrite_iter.zip(children_iter);
828
829 for (rewrite, chain_item) in iter {
830 match chain_item.kind {
831 ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '),
832 ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
833 _ => result.push_str(&connector),
834 }
835 result.push_str(rewrite);
836 }
837
838 Ok(result)
839 }
840}
841
842struct ChainFormatterBlock<'a> {
844 shared: ChainFormatterShared<'a>,
845 root_ends_with_block: bool,
846}
847
848impl<'a> ChainFormatterBlock<'a> {
849 fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> {
850 ChainFormatterBlock {
851 shared: ChainFormatterShared::new(chain),
852 root_ends_with_block: false,
853 }
854 }
855}
856
857impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
858 fn format_root(
859 &mut self,
860 parent: &ChainItem,
861 context: &RewriteContext<'_>,
862 shape: Shape,
863 ) -> Result<(), RewriteError> {
864 let mut root_rewrite: String = parent.rewrite_result(context, shape)?;
865
866 let mut root_ends_with_block = parent.kind.is_block_like(context, &root_rewrite);
867 let tab_width = context.config.tab_spaces().saturating_sub(shape.offset);
868
869 while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
870 let item = &self.shared.children[0];
871 if let ChainItemKind::Comment(..) = item.kind {
872 break;
873 }
874 let shape = shape
875 .offset_left(root_rewrite.len())
876 .max_width_error(shape.width, item.span)?;
877 match &item.rewrite_result(context, shape) {
878 Ok(rewrite) => root_rewrite.push_str(rewrite),
879 Err(_) => break,
880 }
881
882 root_ends_with_block = last_line_extendable(&root_rewrite);
883
884 self.shared.children = &self.shared.children[1..];
885 if self.shared.children.is_empty() {
886 break;
887 }
888 }
889 self.shared.rewrites.push(root_rewrite);
890 self.root_ends_with_block = root_ends_with_block;
891 Ok(())
892 }
893
894 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
895 let block_end = self.root_ends_with_block;
896 Some(get_block_child_shape(block_end, context, shape))
897 }
898
899 fn format_children(
900 &mut self,
901 context: &RewriteContext<'_>,
902 child_shape: Shape,
903 ) -> Result<(), RewriteError> {
904 self.shared.format_children(context, child_shape)
905 }
906
907 fn format_last_child(
908 &mut self,
909 context: &RewriteContext<'_>,
910 shape: Shape,
911 child_shape: Shape,
912 ) -> Result<(), RewriteError> {
913 self.shared
914 .format_last_child(true, context, shape, child_shape)
915 }
916
917 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
918 self.shared.join_rewrites(context, child_shape)
919 }
920
921 fn pure_root(&mut self) -> Option<String> {
922 self.shared.pure_root()
923 }
924}
925
926struct ChainFormatterVisual<'a> {
928 shared: ChainFormatterShared<'a>,
929 offset: usize,
931}
932
933impl<'a> ChainFormatterVisual<'a> {
934 fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> {
935 ChainFormatterVisual {
936 shared: ChainFormatterShared::new(chain),
937 offset: 0,
938 }
939 }
940}
941
942impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
943 fn format_root(
944 &mut self,
945 parent: &ChainItem,
946 context: &RewriteContext<'_>,
947 shape: Shape,
948 ) -> Result<(), RewriteError> {
949 let parent_shape = shape.visual_indent(0);
950 let mut root_rewrite = parent.rewrite_result(context, parent_shape)?;
951 let multiline = root_rewrite.contains('\n');
952 self.offset = if multiline {
953 last_line_width(&root_rewrite).saturating_sub(shape.used_width())
954 } else {
955 trimmed_last_line_width(&root_rewrite)
956 };
957
958 if !multiline || parent.kind.is_block_like(context, &root_rewrite) {
959 let item = &self.shared.children[0];
960 if let ChainItemKind::Comment(..) = item.kind {
961 self.shared.rewrites.push(root_rewrite);
962 return Ok(());
963 }
964 let child_shape = parent_shape
965 .visual_indent(self.offset)
966 .sub_width(self.offset)
967 .max_width_error(parent_shape.width, item.span)?;
968 let rewrite = item.rewrite_result(context, child_shape)?;
969 if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
970 root_rewrite.push_str(&rewrite);
971 } else {
972 let rewrite = item.rewrite_result(context, parent_shape)?;
975 root_rewrite.push_str(&rewrite);
976 self.offset = 0;
977 }
978
979 self.shared.children = &self.shared.children[1..];
980 }
981
982 self.shared.rewrites.push(root_rewrite);
983 Ok(())
984 }
985
986 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
987 get_visual_style_child_shape(
988 context,
989 shape,
990 self.offset,
991 false,
993 )
994 }
995
996 fn format_children(
997 &mut self,
998 context: &RewriteContext<'_>,
999 child_shape: Shape,
1000 ) -> Result<(), RewriteError> {
1001 self.shared.format_children(context, child_shape)
1002 }
1003
1004 fn format_last_child(
1005 &mut self,
1006 context: &RewriteContext<'_>,
1007 shape: Shape,
1008 child_shape: Shape,
1009 ) -> Result<(), RewriteError> {
1010 self.shared
1011 .format_last_child(false, context, shape, child_shape)
1012 }
1013
1014 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
1015 self.shared.join_rewrites(context, child_shape)
1016 }
1017
1018 fn pure_root(&mut self) -> Option<String> {
1019 self.shared.pure_root()
1020 }
1021}
1022
1023fn trim_tries(s: &str) -> String {
1027 let mut result = String::with_capacity(s.len());
1028 let mut line_buffer = String::with_capacity(s.len());
1029 for (kind, rich_char) in CharClasses::new(s.chars()) {
1030 match rich_char.get_char() {
1031 '\n' => {
1032 if result.is_empty() || !line_buffer.trim().is_empty() {
1033 result.push_str(&line_buffer);
1034 result.push('\n')
1035 }
1036 line_buffer.clear();
1037 }
1038 '?' if kind == FullCodeCharKind::Normal => continue,
1039 c => line_buffer.push(c),
1040 }
1041 }
1042 if !line_buffer.trim().is_empty() {
1043 result.push_str(&line_buffer);
1044 }
1045 result
1046}
1047
1048fn should_add_parens(expr: &ast::Expr) -> bool {
1056 match expr.kind {
1057 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
1058 ast::ExprKind::Closure(ref cl) => match cl.body.kind {
1059 ast::ExprKind::Range(_, _, ast::RangeLimits::HalfOpen) => true,
1060 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
1061 _ => false,
1062 },
1063 _ => false,
1064 }
1065}