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 Comment(String, CommentPosition),
196}
197
198impl ChainItemKind {
199 fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
200 match self {
201 ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
202 ChainItemKind::MethodCall(..)
203 | ChainItemKind::StructField(..)
204 | ChainItemKind::TupleField(..)
205 | ChainItemKind::Await
206 | ChainItemKind::Comment(..) => false,
207 }
208 }
209
210 fn is_tup_field_access(expr: &ast::Expr) -> bool {
211 match expr.kind {
212 ast::ExprKind::Field(_, ref field) => {
213 field.name.as_str().chars().all(|c| c.is_digit(10))
214 }
215 _ => false,
216 }
217 }
218
219 fn from_ast(
220 context: &RewriteContext<'_>,
221 expr: &ast::Expr,
222 is_method_call_receiver: bool,
223 ) -> (ChainItemKind, Span) {
224 let (kind, span) = match expr.kind {
225 ast::ExprKind::MethodCall(ref call) => {
226 let types = if let Some(ref generic_args) = call.seg.args {
227 if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
228 data.args
229 .iter()
230 .filter_map(|x| match x {
231 ast::AngleBracketedArg::Arg(ref generic_arg) => {
232 Some(generic_arg.clone())
233 }
234 _ => None,
235 })
236 .collect::<Vec<_>>()
237 } else {
238 vec![]
239 }
240 } else {
241 vec![]
242 };
243 let span = mk_sp(call.receiver.span.hi(), expr.span.hi());
244 let kind = ChainItemKind::MethodCall(call.seg.clone(), types, call.args.clone());
245 (kind, span)
246 }
247 ast::ExprKind::Field(ref nested, field) => {
248 let kind = if Self::is_tup_field_access(expr) {
249 ChainItemKind::TupleField(field, Self::is_tup_field_access(nested))
250 } else {
251 ChainItemKind::StructField(field)
252 };
253 let span = mk_sp(nested.span.hi(), field.span.hi());
254 (kind, span)
255 }
256 ast::ExprKind::Await(ref nested, _) => {
257 let span = mk_sp(nested.span.hi(), expr.span.hi());
258 (ChainItemKind::Await, span)
259 }
260 _ => {
261 return (
262 ChainItemKind::Parent {
263 expr: expr.clone(),
264 parens: is_method_call_receiver && should_add_parens(expr),
265 },
266 expr.span,
267 );
268 }
269 };
270
271 let lo = context.snippet_provider.span_before(span, ".");
273 (kind, mk_sp(lo, span.hi()))
274 }
275}
276
277impl Rewrite for ChainItem {
278 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
279 self.rewrite_result(context, shape).ok()
280 }
281
282 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
283 let shape = shape
284 .sub_width(self.tries)
285 .max_width_error(shape.width, self.span)?;
286 let rewrite = match self.kind {
287 ChainItemKind::Parent {
288 ref expr,
289 parens: true,
290 } => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
291 ChainItemKind::Parent {
292 ref expr,
293 parens: false,
294 } => expr.rewrite_result(context, shape)?,
295 ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
296 Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
297 }
298 ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)),
299 ChainItemKind::TupleField(ident, nested) => format!(
300 "{}.{}",
301 if nested && context.config.style_edition() <= StyleEdition::Edition2021 {
302 " "
303 } else {
304 ""
305 },
306 rewrite_ident(context, ident)
307 ),
308 ChainItemKind::Await => ".await".to_owned(),
309 ChainItemKind::Comment(ref comment, _) => {
310 rewrite_comment(comment, false, shape, context.config)?
311 }
312 };
313 Ok(format!("{rewrite}{}", "?".repeat(self.tries)))
314 }
315}
316
317impl ChainItem {
318 fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
319 let (kind, span) =
320 ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
321 ChainItem { kind, tries, span }
322 }
323
324 fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem {
325 ChainItem {
326 kind: ChainItemKind::Comment(comment, pos),
327 tries: 0,
328 span,
329 }
330 }
331
332 fn is_comment(&self) -> bool {
333 matches!(self.kind, ChainItemKind::Comment(..))
334 }
335
336 fn rewrite_method_call(
337 method_name: symbol::Ident,
338 types: &[ast::GenericArg],
339 args: &[ptr::P<ast::Expr>],
340 span: Span,
341 context: &RewriteContext<'_>,
342 shape: Shape,
343 ) -> RewriteResult {
344 let type_str = if types.is_empty() {
345 String::new()
346 } else {
347 let type_list = types
348 .iter()
349 .map(|ty| ty.rewrite_result(context, shape))
350 .collect::<Result<Vec<_>, RewriteError>>()?;
351
352 format!("::<{}>", type_list.join(", "))
353 };
354 let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
355 rewrite_call(context, &callee_str, &args, span, shape)
356 }
357}
358
359#[derive(Debug)]
360struct Chain {
361 parent: ChainItem,
362 children: Vec<ChainItem>,
363}
364
365impl Chain {
366 fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain {
367 let subexpr_list = Self::make_subexpr_list(expr, context);
368
369 let mut rev_children = vec![];
371 let mut sub_tries = 0;
372 for subexpr in &subexpr_list {
373 match subexpr.expr.kind {
374 ast::ExprKind::Try(_) => sub_tries += 1,
375 _ => {
376 rev_children.push(ChainItem::new(context, subexpr, sub_tries));
377 sub_tries = 0;
378 }
379 }
380 }
381
382 fn is_tries(s: &str) -> bool {
383 s.chars().all(|c| c == '?')
384 }
385
386 fn is_post_comment(s: &str) -> bool {
387 let comment_start_index = s.chars().position(|c| c == '/');
388 if comment_start_index.is_none() {
389 return false;
390 }
391
392 let newline_index = s.chars().position(|c| c == '\n');
393 if newline_index.is_none() {
394 return true;
395 }
396
397 comment_start_index.unwrap() < newline_index.unwrap()
398 }
399
400 fn handle_post_comment(
401 post_comment_span: Span,
402 post_comment_snippet: &str,
403 prev_span_end: &mut BytePos,
404 children: &mut Vec<ChainItem>,
405 ) {
406 let white_spaces: &[_] = &[' ', '\t'];
407 if post_comment_snippet
408 .trim_matches(white_spaces)
409 .starts_with('\n')
410 {
411 return;
413 }
414 let trimmed_snippet = trim_tries(post_comment_snippet);
415 if is_post_comment(&trimmed_snippet) {
416 children.push(ChainItem::comment(
417 post_comment_span,
418 trimmed_snippet.trim().to_owned(),
419 CommentPosition::Back,
420 ));
421 *prev_span_end = post_comment_span.hi();
422 }
423 }
424
425 let parent = rev_children.pop().unwrap();
426 let mut children = vec![];
427 let mut prev_span_end = parent.span.hi();
428 let mut iter = rev_children.into_iter().rev().peekable();
429 if let Some(first_chain_item) = iter.peek() {
430 let comment_span = mk_sp(prev_span_end, first_chain_item.span.lo());
431 let comment_snippet = context.snippet(comment_span);
432 if !is_tries(comment_snippet.trim()) {
433 handle_post_comment(
434 comment_span,
435 comment_snippet,
436 &mut prev_span_end,
437 &mut children,
438 );
439 }
440 }
441 while let Some(chain_item) = iter.next() {
442 let comment_snippet = context.snippet(chain_item.span);
443 let handle_comment =
445 !(context.config.use_try_shorthand() || is_tries(comment_snippet.trim()));
446
447 if handle_comment {
449 let pre_comment_span = mk_sp(prev_span_end, chain_item.span.lo());
450 let pre_comment_snippet = trim_tries(context.snippet(pre_comment_span));
451 let (pre_comment, _) = extract_pre_comment(&pre_comment_snippet);
452 match pre_comment {
453 Some(ref comment) if !comment.is_empty() => {
454 children.push(ChainItem::comment(
455 pre_comment_span,
456 comment.to_owned(),
457 CommentPosition::Top,
458 ));
459 }
460 _ => (),
461 }
462 }
463
464 prev_span_end = chain_item.span.hi();
465 children.push(chain_item);
466
467 if !handle_comment || iter.peek().is_none() {
469 continue;
470 }
471
472 let next_lo = iter.peek().unwrap().span.lo();
473 let post_comment_span = mk_sp(prev_span_end, next_lo);
474 let post_comment_snippet = context.snippet(post_comment_span);
475 handle_post_comment(
476 post_comment_span,
477 post_comment_snippet,
478 &mut prev_span_end,
479 &mut children,
480 );
481 }
482
483 Chain { parent, children }
484 }
485
486 fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
489 let mut subexpr_list = vec![SubExpr {
490 expr: expr.clone(),
491 is_method_call_receiver: false,
492 }];
493
494 while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
495 subexpr_list.push(subexpr);
496 }
497
498 subexpr_list
499 }
500
501 fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
504 match expr.expr.kind {
505 ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
506 expr: Self::convert_try(&call.receiver, context),
507 is_method_call_receiver: true,
508 }),
509 ast::ExprKind::Field(ref subexpr, _)
510 | ast::ExprKind::Try(ref subexpr)
511 | ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
512 expr: Self::convert_try(subexpr, context),
513 is_method_call_receiver: false,
514 }),
515 _ => None,
516 }
517 }
518
519 fn convert_try(expr: &ast::Expr, context: &RewriteContext<'_>) -> ast::Expr {
520 match expr.kind {
521 ast::ExprKind::MacCall(ref mac) if context.config.use_try_shorthand() => {
522 if let Some(subexpr) = convert_try_mac(mac, context) {
523 subexpr
524 } else {
525 expr.clone()
526 }
527 }
528 _ => expr.clone(),
529 }
530 }
531}
532
533impl Rewrite for Chain {
534 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
535 self.rewrite_result(context, shape).ok()
536 }
537
538 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
539 debug!("rewrite chain {:?} {:?}", self, shape);
540
541 let mut formatter = match context.config.indent_style() {
542 IndentStyle::Block => {
543 Box::new(ChainFormatterBlock::new(self)) as Box<dyn ChainFormatter>
544 }
545 IndentStyle::Visual => {
546 Box::new(ChainFormatterVisual::new(self)) as Box<dyn ChainFormatter>
547 }
548 };
549
550 formatter.format_root(&self.parent, context, shape)?;
551 if let Some(result) = formatter.pure_root() {
552 return wrap_str(result, context.config.max_width(), shape)
553 .max_width_error(shape.width, self.parent.span);
554 }
555
556 let first = self.children.first().unwrap_or(&self.parent);
557 let last = self.children.last().unwrap_or(&self.parent);
558 let children_span = mk_sp(first.span.lo(), last.span.hi());
559 let full_span = self.parent.span.with_hi(children_span.hi());
560
561 let child_shape = formatter
563 .child_shape(context, shape)
564 .max_width_error(shape.width, children_span)?;
565
566 formatter.format_children(context, child_shape)?;
567 formatter.format_last_child(context, shape, child_shape)?;
568
569 let result = formatter.join_rewrites(context, child_shape)?;
570 wrap_str(result, context.config.max_width(), shape).max_width_error(shape.width, full_span)
571 }
572}
573
574trait ChainFormatter {
579 fn format_root(
588 &mut self,
589 parent: &ChainItem,
590 context: &RewriteContext<'_>,
591 shape: Shape,
592 ) -> Result<(), RewriteError>;
593 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape>;
594 fn format_children(
595 &mut self,
596 context: &RewriteContext<'_>,
597 child_shape: Shape,
598 ) -> Result<(), RewriteError>;
599 fn format_last_child(
600 &mut self,
601 context: &RewriteContext<'_>,
602 shape: Shape,
603 child_shape: Shape,
604 ) -> Result<(), RewriteError>;
605 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult;
606 fn pure_root(&mut self) -> Option<String>;
608}
609
610struct ChainFormatterShared<'a> {
613 children: &'a [ChainItem],
615 rewrites: Vec<String>,
618 fits_single_line: bool,
620 child_count: usize,
623 allow_overflow: bool,
625}
626
627impl<'a> ChainFormatterShared<'a> {
628 fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
629 ChainFormatterShared {
630 children: &chain.children,
631 rewrites: Vec::with_capacity(chain.children.len() + 1),
632 fits_single_line: false,
633 child_count: chain.children.len(),
634 allow_overflow: false,
636 }
637 }
638
639 fn pure_root(&mut self) -> Option<String> {
640 if self.children.is_empty() {
641 assert_eq!(self.rewrites.len(), 1);
642 Some(self.rewrites.pop().unwrap())
643 } else {
644 None
645 }
646 }
647
648 fn format_children(
649 &mut self,
650 context: &RewriteContext<'_>,
651 child_shape: Shape,
652 ) -> Result<(), RewriteError> {
653 for item in &self.children[..self.children.len() - 1] {
654 let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
655 self.rewrites.push(rewrite);
656 }
657 Ok(())
658 }
659
660 fn format_last_child(
693 &mut self,
694 may_extend: bool,
695 context: &RewriteContext<'_>,
696 shape: Shape,
697 child_shape: Shape,
698 ) -> Result<(), RewriteError> {
699 let last = self.children.last().unknown_error()?;
700 let extendable = may_extend && last_line_extendable(&self.rewrites[0]);
701 let prev_last_line_width = last_line_width(&self.rewrites[0]);
702
703 let almost_total = if extendable {
705 prev_last_line_width
706 } else {
707 self.rewrites
708 .iter()
709 .map(|rw| utils::unicode_str_width(rw))
710 .sum()
711 } + last.tries;
712 let one_line_budget = if self.child_count == 1 {
713 shape.width
714 } else {
715 min(shape.width, context.config.chain_width())
716 }
717 .saturating_sub(almost_total);
718
719 let all_in_one_line = !self.children.iter().any(ChainItem::is_comment)
720 && self.rewrites.iter().all(|s| !s.contains('\n'))
721 && one_line_budget > 0;
722 let last_shape = if all_in_one_line {
723 shape
724 .sub_width(last.tries)
725 .max_width_error(shape.width, last.span)?
726 } else if extendable {
727 child_shape
728 .sub_width(last.tries)
729 .max_width_error(child_shape.width, last.span)?
730 } else {
731 child_shape
732 .sub_width(shape.rhs_overhead(context.config) + last.tries)
733 .max_width_error(child_shape.width, last.span)?
734 };
735
736 let mut last_subexpr_str = None;
737 if all_in_one_line || extendable {
738 let one_line_shape = if context.use_block_indent() {
741 last_shape.offset_left(almost_total)
742 } else {
743 last_shape
744 .visual_indent(almost_total)
745 .sub_width(almost_total)
746 };
747
748 if let Some(one_line_shape) = one_line_shape {
749 if let Ok(rw) = last.rewrite_result(context, one_line_shape) {
750 let line_count = rw.lines().count();
754 let could_fit_single_line = first_line_width(&rw) <= one_line_budget;
755 if could_fit_single_line && line_count >= 5 {
756 last_subexpr_str = Some(rw);
757 self.fits_single_line = all_in_one_line;
758 } else {
759 let last_shape = child_shape
764 .sub_width(shape.rhs_overhead(context.config) + last.tries)
765 .max_width_error(child_shape.width, last.span)?;
766 match last.rewrite_result(context, last_shape) {
767 Ok(ref new_rw) if !could_fit_single_line => {
768 last_subexpr_str = Some(new_rw.clone());
769 }
770 Ok(ref new_rw) if new_rw.lines().count() >= line_count => {
771 last_subexpr_str = Some(rw);
772 self.fits_single_line = could_fit_single_line && all_in_one_line;
773 }
774 Ok(new_rw) => {
775 last_subexpr_str = Some(new_rw);
776 }
777 _ => {
778 last_subexpr_str = Some(rw);
779 self.fits_single_line = could_fit_single_line && all_in_one_line;
780 }
781 }
782 }
783 }
784 }
785 }
786
787 let last_shape = if context.use_block_indent() {
788 last_shape
789 } else {
790 child_shape
791 .sub_width(shape.rhs_overhead(context.config) + last.tries)
792 .max_width_error(child_shape.width, last.span)?
793 };
794
795 let last_subexpr_str =
796 last_subexpr_str.unwrap_or(last.rewrite_result(context, last_shape)?);
797 self.rewrites.push(last_subexpr_str);
798 Ok(())
799 }
800
801 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
802 let connector = if self.fits_single_line {
803 Cow::from("")
805 } else {
806 if context.force_one_line_chain.get() {
808 return Err(RewriteError::ExceedsMaxWidth {
809 configured_width: child_shape.width,
810 span: self.children.last().unknown_error()?.span,
811 });
812 }
813 child_shape.to_string_with_newline(context.config)
814 };
815
816 let mut rewrite_iter = self.rewrites.iter();
817 let mut result = rewrite_iter.next().unwrap().clone();
818 let children_iter = self.children.iter();
819 let iter = rewrite_iter.zip(children_iter);
820
821 for (rewrite, chain_item) in iter {
822 match chain_item.kind {
823 ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '),
824 ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
825 _ => result.push_str(&connector),
826 }
827 result.push_str(rewrite);
828 }
829
830 Ok(result)
831 }
832}
833
834struct ChainFormatterBlock<'a> {
836 shared: ChainFormatterShared<'a>,
837 root_ends_with_block: bool,
838}
839
840impl<'a> ChainFormatterBlock<'a> {
841 fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> {
842 ChainFormatterBlock {
843 shared: ChainFormatterShared::new(chain),
844 root_ends_with_block: false,
845 }
846 }
847}
848
849impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
850 fn format_root(
851 &mut self,
852 parent: &ChainItem,
853 context: &RewriteContext<'_>,
854 shape: Shape,
855 ) -> Result<(), RewriteError> {
856 let mut root_rewrite: String = parent.rewrite_result(context, shape)?;
857
858 let mut root_ends_with_block = parent.kind.is_block_like(context, &root_rewrite);
859 let tab_width = context.config.tab_spaces().saturating_sub(shape.offset);
860
861 while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
862 let item = &self.shared.children[0];
863 if let ChainItemKind::Comment(..) = item.kind {
864 break;
865 }
866 let shape = shape
867 .offset_left(root_rewrite.len())
868 .max_width_error(shape.width, item.span)?;
869 match &item.rewrite_result(context, shape) {
870 Ok(rewrite) => root_rewrite.push_str(rewrite),
871 Err(_) => break,
872 }
873
874 root_ends_with_block = last_line_extendable(&root_rewrite);
875
876 self.shared.children = &self.shared.children[1..];
877 if self.shared.children.is_empty() {
878 break;
879 }
880 }
881 self.shared.rewrites.push(root_rewrite);
882 self.root_ends_with_block = root_ends_with_block;
883 Ok(())
884 }
885
886 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
887 let block_end = self.root_ends_with_block;
888 Some(get_block_child_shape(block_end, context, shape))
889 }
890
891 fn format_children(
892 &mut self,
893 context: &RewriteContext<'_>,
894 child_shape: Shape,
895 ) -> Result<(), RewriteError> {
896 self.shared.format_children(context, child_shape)
897 }
898
899 fn format_last_child(
900 &mut self,
901 context: &RewriteContext<'_>,
902 shape: Shape,
903 child_shape: Shape,
904 ) -> Result<(), RewriteError> {
905 self.shared
906 .format_last_child(true, context, shape, child_shape)
907 }
908
909 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
910 self.shared.join_rewrites(context, child_shape)
911 }
912
913 fn pure_root(&mut self) -> Option<String> {
914 self.shared.pure_root()
915 }
916}
917
918struct ChainFormatterVisual<'a> {
920 shared: ChainFormatterShared<'a>,
921 offset: usize,
923}
924
925impl<'a> ChainFormatterVisual<'a> {
926 fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> {
927 ChainFormatterVisual {
928 shared: ChainFormatterShared::new(chain),
929 offset: 0,
930 }
931 }
932}
933
934impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
935 fn format_root(
936 &mut self,
937 parent: &ChainItem,
938 context: &RewriteContext<'_>,
939 shape: Shape,
940 ) -> Result<(), RewriteError> {
941 let parent_shape = shape.visual_indent(0);
942 let mut root_rewrite = parent.rewrite_result(context, parent_shape)?;
943 let multiline = root_rewrite.contains('\n');
944 self.offset = if multiline {
945 last_line_width(&root_rewrite).saturating_sub(shape.used_width())
946 } else {
947 trimmed_last_line_width(&root_rewrite)
948 };
949
950 if !multiline || parent.kind.is_block_like(context, &root_rewrite) {
951 let item = &self.shared.children[0];
952 if let ChainItemKind::Comment(..) = item.kind {
953 self.shared.rewrites.push(root_rewrite);
954 return Ok(());
955 }
956 let child_shape = parent_shape
957 .visual_indent(self.offset)
958 .sub_width(self.offset)
959 .max_width_error(parent_shape.width, item.span)?;
960 let rewrite = item.rewrite_result(context, child_shape)?;
961 if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
962 root_rewrite.push_str(&rewrite);
963 } else {
964 let rewrite = item.rewrite_result(context, parent_shape)?;
967 root_rewrite.push_str(&rewrite);
968 self.offset = 0;
969 }
970
971 self.shared.children = &self.shared.children[1..];
972 }
973
974 self.shared.rewrites.push(root_rewrite);
975 Ok(())
976 }
977
978 fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
979 get_visual_style_child_shape(
980 context,
981 shape,
982 self.offset,
983 false,
985 )
986 }
987
988 fn format_children(
989 &mut self,
990 context: &RewriteContext<'_>,
991 child_shape: Shape,
992 ) -> Result<(), RewriteError> {
993 self.shared.format_children(context, child_shape)
994 }
995
996 fn format_last_child(
997 &mut self,
998 context: &RewriteContext<'_>,
999 shape: Shape,
1000 child_shape: Shape,
1001 ) -> Result<(), RewriteError> {
1002 self.shared
1003 .format_last_child(false, context, shape, child_shape)
1004 }
1005
1006 fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> RewriteResult {
1007 self.shared.join_rewrites(context, child_shape)
1008 }
1009
1010 fn pure_root(&mut self) -> Option<String> {
1011 self.shared.pure_root()
1012 }
1013}
1014
1015fn trim_tries(s: &str) -> String {
1019 let mut result = String::with_capacity(s.len());
1020 let mut line_buffer = String::with_capacity(s.len());
1021 for (kind, rich_char) in CharClasses::new(s.chars()) {
1022 match rich_char.get_char() {
1023 '\n' => {
1024 if result.is_empty() || !line_buffer.trim().is_empty() {
1025 result.push_str(&line_buffer);
1026 result.push('\n')
1027 }
1028 line_buffer.clear();
1029 }
1030 '?' if kind == FullCodeCharKind::Normal => continue,
1031 c => line_buffer.push(c),
1032 }
1033 }
1034 if !line_buffer.trim().is_empty() {
1035 result.push_str(&line_buffer);
1036 }
1037 result
1038}
1039
1040fn should_add_parens(expr: &ast::Expr) -> bool {
1048 match expr.kind {
1049 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
1050 ast::ExprKind::Closure(ref cl) => match cl.body.kind {
1051 ast::ExprKind::Range(_, _, ast::RangeLimits::HalfOpen) => true,
1052 ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
1053 _ => false,
1054 },
1055 _ => false,
1056 }
1057}