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