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_postfix_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_postfix_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_postfix_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) = ChainItemKind::from_ast(context, &expr.expr, expr.is_postfix_receiver);
335 ChainItem { kind, tries, span }
336 }
337
338 fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem {
339 ChainItem {
340 kind: ChainItemKind::Comment(comment, pos),
341 tries: 0,
342 span,
343 }
344 }
345
346 fn is_comment(&self) -> bool {
347 matches!(self.kind, ChainItemKind::Comment(..))
348 }
349
350 fn rewrite_method_call(
351 method_name: symbol::Ident,
352 types: &[ast::GenericArg],
353 args: &[Box<ast::Expr>],
354 span: Span,
355 context: &RewriteContext<'_>,
356 shape: Shape,
357 ) -> RewriteResult {
358 let type_str = if types.is_empty() {
359 String::new()
360 } else {
361 let type_list = types
362 .iter()
363 .map(|ty| ty.rewrite_result(context, shape))
364 .collect::<Result<Vec<_>, RewriteError>>()?;
365
366 format!("::<{}>", type_list.join(", "))
367 };
368 let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
369 rewrite_call(context, &callee_str, &args, span, shape)
370 }
371}
372
373#[derive(Debug)]
374struct Chain {
375 parent: ChainItem,
376 children: Vec<ChainItem>,
377}
378
379impl Chain {
380 fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain {
381 let subexpr_list = Self::make_subexpr_list(expr, context);
382
383 let mut rev_children = vec![];
385 let mut sub_tries = 0;
386 for subexpr in &subexpr_list {
387 match subexpr.expr.kind {
388 ast::ExprKind::Try(_) => sub_tries += 1,
389 _ => {
390 rev_children.push(ChainItem::new(context, subexpr, sub_tries));
391 sub_tries = 0;
392 }
393 }
394 }
395
396 fn is_tries(s: &str) -> bool {
397 s.chars().all(|c| c == '?')
398 }
399
400 fn is_post_comment(s: &str) -> bool {
401 let comment_start_index = s.chars().position(|c| c == '/');
402 if comment_start_index.is_none() {
403 return false;
404 }
405
406 let newline_index = s.chars().position(|c| c == '\n');
407 if newline_index.is_none() {
408 return true;
409 }
410
411 comment_start_index.unwrap() < newline_index.unwrap()
412 }
413
414 fn handle_post_comment(
415 post_comment_span: Span,
416 post_comment_snippet: &str,
417 prev_span_end: &mut BytePos,
418 children: &mut Vec<ChainItem>,
419 ) {
420 let white_spaces: &[_] = &[' ', '\t'];
421 if post_comment_snippet
422 .trim_matches(white_spaces)
423 .starts_with('\n')
424 {
425 return;
427 }
428 let trimmed_snippet = trim_tries(post_comment_snippet);
429 if is_post_comment(&trimmed_snippet) {
430 children.push(ChainItem::comment(
431 post_comment_span,
432 trimmed_snippet.trim().to_owned(),
433 CommentPosition::Back,
434 ));
435 *prev_span_end = post_comment_span.hi();
436 }
437 }
438
439 let parent = rev_children.pop().unwrap();
440 let mut children = vec![];
441 let mut prev_span_end = parent.span.hi();
442 let mut iter = rev_children.into_iter().rev().peekable();
443 if let Some(first_chain_item) = iter.peek() {
444 let comment_span = mk_sp(prev_span_end, first_chain_item.span.lo());
445 let comment_snippet = context.snippet(comment_span);
446 if !is_tries(comment_snippet.trim()) {
447 handle_post_comment(
448 comment_span,
449 comment_snippet,
450 &mut prev_span_end,
451 &mut children,
452 );
453 }
454 }
455 while let Some(chain_item) = iter.next() {
456 let comment_snippet = context.snippet(chain_item.span);
457 let handle_comment =
459 !(context.config.use_try_shorthand() || is_tries(comment_snippet.trim()));
460
461 if handle_comment {
463 let pre_comment_span = mk_sp(prev_span_end, chain_item.span.lo());
464 let pre_comment_snippet = trim_tries(context.snippet(pre_comment_span));
465 let (pre_comment, _) = extract_pre_comment(&pre_comment_snippet);
466 match pre_comment {
467 Some(ref comment) if !comment.is_empty() => {
468 children.push(ChainItem::comment(
469 pre_comment_span,
470 comment.to_owned(),
471 CommentPosition::Top,
472 ));
473 }
474 _ => (),
475 }
476 }
477
478 prev_span_end = chain_item.span.hi();
479 children.push(chain_item);
480
481 if !handle_comment || iter.peek().is_none() {
483 continue;
484 }
485
486 let next_lo = iter.peek().unwrap().span.lo();
487 let post_comment_span = mk_sp(prev_span_end, next_lo);
488 let post_comment_snippet = context.snippet(post_comment_span);
489 handle_post_comment(
490 post_comment_span,
491 post_comment_snippet,
492 &mut prev_span_end,
493 &mut children,
494 );
495 }
496
497 Chain { parent, children }
498 }
499
500 fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
503 let mut subexpr_list = vec![SubExpr {
504 expr: expr.clone(),
505 is_postfix_receiver: false,
506 }];
507
508 while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
509 subexpr_list.push(subexpr);
510 }
511
512 subexpr_list
513 }
514
515 fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
518 match expr.expr.kind {
519 ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
520 expr: Self::convert_try(&call.receiver, context),
521 is_postfix_receiver: true,
522 }),
523 ast::ExprKind::Field(ref subexpr, _)
524 | ast::ExprKind::Await(ref subexpr, _)
525 | ast::ExprKind::Use(ref subexpr, _)
526 | ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr {
527 expr: Self::convert_try(subexpr, context),
528 is_postfix_receiver: true,
529 }),
530 ast::ExprKind::Try(ref subexpr) => Some(SubExpr {
531 expr: Self::convert_try(subexpr, context),
532 is_postfix_receiver: false,
533 }),
534 _ => None,
535 }
536 }
537
538 fn convert_try(expr: &ast::Expr, context: &RewriteContext<'_>) -> ast::Expr {
539 match expr.kind {
540 ast::ExprKind::MacCall(ref mac) if context.config.use_try_shorthand() => {
541 if let Some(subexpr) = convert_try_mac(mac, context) {
542 subexpr
543 } else {
544 expr.clone()
545 }
546 }
547 _ => expr.clone(),
548 }
549 }
550}
551
552impl Rewrite for Chain {
553 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
554 self.rewrite_result(context, shape).ok()
555 }
556
557 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
558 debug!("rewrite chain {:?} {:?}", self, shape);
559
560 let mut formatter = match context.config.indent_style() {
561 IndentStyle::Block => {
562 Box::new(ChainFormatterBlock::new(self)) as Box<dyn ChainFormatter>
563 }
564 IndentStyle::Visual => {
565 Box::new(ChainFormatterVisual::new(self)) as Box<dyn ChainFormatter>
566 }
567 };
568
569 formatter.format_root(&self.parent, context, shape)?;
570 if let Some(result) = formatter.pure_root() {
571 return wrap_str(result, context.config.max_width(), shape)
572 .max_width_error(shape.width, self.parent.span);
573 }
574
575 let first = self.children.first().unwrap_or(&self.parent);
576 let last = self.children.last().unwrap_or(&self.parent);
577 let children_span = mk_sp(first.span.lo(), last.span.hi());
578 let full_span = self.parent.span.with_hi(children_span.hi());
579
580 let child_shape = formatter.child_shape(context, shape, children_span)?;
582
583 formatter.format_children(context, child_shape)?;
584 formatter.format_last_child(context, shape, child_shape)?;
585
586 let result = formatter.join_rewrites(context, child_shape)?;
587 wrap_str(result, context.config.max_width(), shape).max_width_error(shape.width, full_span)
588 }
589}
590
591trait ChainFormatter {
596 fn format_root(
605 &mut self,
606 parent: &ChainItem,
607 context: &RewriteContext<'_>,
608 shape: Shape,
609 ) -> Result<(), RewriteError>;
610 fn child_shape(
611 &self,
612 context: &RewriteContext<'_>,
613 shape: Shape,
614 span: Span,
615 ) -> Result<Shape, ExceedsMaxWidthError>;
616 fn format_children(
617 &mut self,
618 context: &RewriteContext<'_>,
619 child_shape: Shape,
620 ) -> Result<(), RewriteError>;
621 fn format_last_child(
622 &mut self,
623 context: &RewriteContext<'_>,
624 shape: Shape,
625 child_shape: Shape,
626 ) -> Result<(), RewriteError>;
627 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult;
628 fn pure_root(&mut self) -> Option<String>;
630}
631
632struct ChainFormatterShared<'a> {
635 children: &'a [ChainItem],
637 rewrites: Vec<String>,
640 fits_single_line: bool,
642 child_count: usize,
645 allow_overflow: bool,
647}
648
649impl<'a> ChainFormatterShared<'a> {
650 fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
651 ChainFormatterShared {
652 children: &chain.children,
653 rewrites: Vec::with_capacity(chain.children.len() + 1),
654 fits_single_line: false,
655 child_count: chain.children.len(),
656 allow_overflow: false,
658 }
659 }
660
661 fn pure_root(&mut self) -> Option<String> {
662 if self.children.is_empty() {
663 assert_eq!(self.rewrites.len(), 1);
664 Some(self.rewrites.pop().unwrap())
665 } else {
666 None
667 }
668 }
669
670 fn format_children(
671 &mut self,
672 context: &RewriteContext<'_>,
673 child_shape: Shape,
674 ) -> Result<(), RewriteError> {
675 for item in &self.children[..self.children.len() - 1] {
676 let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
677 self.rewrites.push(rewrite);
678 }
679 Ok(())
680 }
681
682 fn format_last_child(
715 &mut self,
716 may_extend: bool,
717 context: &RewriteContext<'_>,
718 shape: Shape,
719 child_shape: Shape,
720 ) -> Result<(), RewriteError> {
721 let last = self.children.last().unknown_error()?;
722 let extendable = may_extend && last_line_extendable(&self.rewrites[0]);
723 let prev_last_line_width = last_line_width(&self.rewrites[0]);
724
725 let almost_total = if extendable {
727 prev_last_line_width
728 } else {
729 self.rewrites
730 .iter()
731 .map(|rw| utils::unicode_str_width(rw))
732 .sum()
733 } + last.tries;
734 let one_line_budget = if self.child_count == 1 {
735 shape.width
736 } else {
737 min(shape.width, context.config.chain_width())
738 }
739 .saturating_sub(almost_total);
740
741 let all_in_one_line = !self.children.iter().any(ChainItem::is_comment)
742 && self.rewrites.iter().all(|s| !s.contains('\n'))
743 && one_line_budget > 0;
744 let last_shape = if all_in_one_line {
745 shape.sub_width(last.tries, last.span)?
746 } else if extendable {
747 child_shape.sub_width(last.tries, last.span)?
748 } else {
749 child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries, last.span)?
750 };
751
752 let mut last_subexpr_str = None;
753 if all_in_one_line || extendable {
754 let one_line_shape = if context.use_block_indent() {
757 last_shape.offset_left_opt(almost_total)
758 } else {
759 last_shape
760 .visual_indent(almost_total)
761 .sub_width_opt(almost_total)
762 };
763
764 if let Some(one_line_shape) = one_line_shape {
765 if let Ok(rw) = last.rewrite_result(context, one_line_shape) {
766 let line_count = rw.lines().count();
770 let could_fit_single_line = first_line_width(&rw) <= one_line_budget;
771 if could_fit_single_line && line_count >= 5 {
772 last_subexpr_str = Some(rw);
773 self.fits_single_line = all_in_one_line;
774 } else {
775 let last_shape = child_shape.sub_width(
780 shape.rhs_overhead(context.config) + last.tries,
781 last.span,
782 )?;
783 match last.rewrite_result(context, last_shape) {
784 Ok(ref new_rw) if !could_fit_single_line => {
785 last_subexpr_str = Some(new_rw.clone());
786 }
787 Ok(ref new_rw) if new_rw.lines().count() >= line_count => {
788 last_subexpr_str = Some(rw);
789 self.fits_single_line = could_fit_single_line && all_in_one_line;
790 }
791 Ok(new_rw) => {
792 last_subexpr_str = Some(new_rw);
793 }
794 _ => {
795 last_subexpr_str = Some(rw);
796 self.fits_single_line = could_fit_single_line && all_in_one_line;
797 }
798 }
799 }
800 }
801 }
802 }
803
804 let last_shape = if context.use_block_indent() {
805 last_shape
806 } else {
807 child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries, last.span)?
808 };
809
810 let last_subexpr_str =
811 last_subexpr_str.unwrap_or(last.rewrite_result(context, last_shape)?);
812 self.rewrites.push(last_subexpr_str);
813 Ok(())
814 }
815
816 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
817 let connector = if self.fits_single_line {
818 Cow::from("")
820 } else {
821 if context.force_one_line_chain.get() {
823 return Err(RewriteError::ExceedsMaxWidth {
824 configured_width: child_shape.width,
825 span: self.children.last().unknown_error()?.span,
826 });
827 }
828 child_shape.to_string_with_newline(context.config)
829 };
830
831 let mut rewrite_iter = self.rewrites.iter();
832 let mut result = rewrite_iter.next().unwrap().clone();
833 let children_iter = self.children.iter();
834 let iter = rewrite_iter.zip(children_iter);
835
836 for (rewrite, chain_item) in iter {
837 match chain_item.kind {
838 ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '),
839 ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
840 _ => result.push_str(&connector),
841 }
842 result.push_str(rewrite);
843 }
844
845 Ok(result)
846 }
847}
848
849struct ChainFormatterBlock<'a> {
851 shared: ChainFormatterShared<'a>,
852 root_ends_with_block: bool,
853}
854
855impl<'a> ChainFormatterBlock<'a> {
856 fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> {
857 ChainFormatterBlock {
858 shared: ChainFormatterShared::new(chain),
859 root_ends_with_block: false,
860 }
861 }
862}
863
864impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
865 fn format_root(
866 &mut self,
867 parent: &ChainItem,
868 context: &RewriteContext<'_>,
869 shape: Shape,
870 ) -> Result<(), RewriteError> {
871 let mut root_rewrite: String = parent.rewrite_result(context, shape)?;
872
873 let mut root_ends_with_block = parent.kind.is_block_like(context, &root_rewrite);
874 let tab_width = context.config.tab_spaces().saturating_sub(shape.offset);
875
876 while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
877 let item = &self.shared.children[0];
878 if let ChainItemKind::Comment(..) = item.kind {
879 break;
880 }
881 let shape = shape.offset_left(root_rewrite.len(), item.span)?;
882 match &item.rewrite_result(context, shape) {
883 Ok(rewrite) => root_rewrite.push_str(rewrite),
884 Err(_) => break,
885 }
886
887 root_ends_with_block = last_line_extendable(&root_rewrite);
888
889 self.shared.children = &self.shared.children[1..];
890 if self.shared.children.is_empty() {
891 break;
892 }
893 }
894 self.shared.rewrites.push(root_rewrite);
895 self.root_ends_with_block = root_ends_with_block;
896 Ok(())
897 }
898
899 fn child_shape(
900 &self,
901 context: &RewriteContext<'_>,
902 shape: Shape,
903 _span: Span,
904 ) -> Result<Shape, ExceedsMaxWidthError> {
905 let block_end = self.root_ends_with_block;
906 Ok(get_block_child_shape(block_end, context, shape))
907 }
908
909 fn format_children(
910 &mut self,
911 context: &RewriteContext<'_>,
912 child_shape: Shape,
913 ) -> Result<(), RewriteError> {
914 self.shared.format_children(context, child_shape)
915 }
916
917 fn format_last_child(
918 &mut self,
919 context: &RewriteContext<'_>,
920 shape: Shape,
921 child_shape: Shape,
922 ) -> Result<(), RewriteError> {
923 self.shared
924 .format_last_child(true, context, shape, child_shape)
925 }
926
927 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
928 self.shared.join_rewrites(context, child_shape)
929 }
930
931 fn pure_root(&mut self) -> Option<String> {
932 self.shared.pure_root()
933 }
934}
935
936struct ChainFormatterVisual<'a> {
938 shared: ChainFormatterShared<'a>,
939 offset: usize,
941}
942
943impl<'a> ChainFormatterVisual<'a> {
944 fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> {
945 ChainFormatterVisual {
946 shared: ChainFormatterShared::new(chain),
947 offset: 0,
948 }
949 }
950}
951
952impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
953 fn format_root(
954 &mut self,
955 parent: &ChainItem,
956 context: &RewriteContext<'_>,
957 shape: Shape,
958 ) -> Result<(), RewriteError> {
959 let parent_shape = shape.visual_indent(0);
960 let mut root_rewrite = parent.rewrite_result(context, parent_shape)?;
961 let multiline = root_rewrite.contains('\n');
962 self.offset = if multiline {
963 last_line_width(&root_rewrite).saturating_sub(shape.used_width())
964 } else {
965 trimmed_last_line_width(&root_rewrite)
966 };
967
968 if !multiline || parent.kind.is_block_like(context, &root_rewrite) {
969 let item = &self.shared.children[0];
970 if let ChainItemKind::Comment(..) = item.kind {
971 self.shared.rewrites.push(root_rewrite);
972 return Ok(());
973 }
974 let child_shape = parent_shape
975 .visual_indent(self.offset)
976 .sub_width(self.offset, item.span)?;
977 let rewrite = item.rewrite_result(context, child_shape)?;
978 if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
979 root_rewrite.push_str(&rewrite);
980 } else {
981 let rewrite = item.rewrite_result(context, parent_shape)?;
984 root_rewrite.push_str(&rewrite);
985 self.offset = 0;
986 }
987
988 self.shared.children = &self.shared.children[1..];
989 }
990
991 self.shared.rewrites.push(root_rewrite);
992 Ok(())
993 }
994
995 fn child_shape(
996 &self,
997 context: &RewriteContext<'_>,
998 shape: Shape,
999 span: Span,
1000 ) -> Result<Shape, ExceedsMaxWidthError> {
1001 get_visual_style_child_shape(
1002 context,
1003 shape,
1004 self.offset,
1005 false,
1007 span,
1008 )
1009 }
1010
1011 fn format_children(
1012 &mut self,
1013 context: &RewriteContext<'_>,
1014 child_shape: Shape,
1015 ) -> Result<(), RewriteError> {
1016 self.shared.format_children(context, child_shape)
1017 }
1018
1019 fn format_last_child(
1020 &mut self,
1021 context: &RewriteContext<'_>,
1022 shape: Shape,
1023 child_shape: Shape,
1024 ) -> Result<(), RewriteError> {
1025 self.shared
1026 .format_last_child(false, context, shape, child_shape)
1027 }
1028
1029 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
1030 self.shared.join_rewrites(context, child_shape)
1031 }
1032
1033 fn pure_root(&mut self) -> Option<String> {
1034 self.shared.pure_root()
1035 }
1036}
1037
1038fn trim_tries(s: &str) -> String {
1042 let mut result = String::with_capacity(s.len());
1043 let mut line_buffer = String::with_capacity(s.len());
1044 for (kind, rich_char) in CharClasses::new(s.chars()) {
1045 match rich_char.get_char() {
1046 '\n' => {
1047 if result.is_empty() || !line_buffer.trim().is_empty() {
1048 result.push_str(&line_buffer);
1049 result.push('\n')
1050 }
1051 line_buffer.clear();
1052 }
1053 '?' if kind == FullCodeCharKind::Normal => continue,
1054 c => line_buffer.push(c),
1055 }
1056 }
1057 if !line_buffer.trim().is_empty() {
1058 result.push_str(&line_buffer);
1059 }
1060 result
1061}
1062
1063fn should_add_parens(expr: &ast::Expr, context: &RewriteContext<'_>) -> bool {
1071 match expr.kind {
1072 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit, context),
1073 ast::ExprKind::Closure(ref cl) => match cl.body.kind {
1074 ast::ExprKind::Range(_, _, ast::RangeLimits::HalfOpen) => true,
1075 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit, context),
1076 _ => false,
1077 },
1078 _ => false,
1079 }
1080}