X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fchains.rs;h=b7619c0a18af49a65bee7bc253211cad1d9817fe;hb=bb7442802abe354a0ed844ec237cd20969789224;hp=3f5ff75a722880916ed7b91a7d8841099a46b930;hpb=fc1909d311cebd2920b968b8fe161267c12c5fe1;p=rust.git diff --git a/src/chains.rs b/src/chains.rs index 3f5ff75a722..b7619c0a18a 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -65,22 +65,21 @@ //! .qux //! ``` -use comment::rewrite_comment; +use comment::{rewrite_comment, CharClasses, FullCodeCharKind, RichChar}; use config::IndentStyle; use expr::rewrite_call; -use lists::{extract_post_comment, extract_pre_comment, get_comment_end}; +use lists::extract_pre_comment; use macros::convert_try_mac; use rewrite::{Rewrite, RewriteContext}; use shape::Shape; use source_map::SpanUtils; use utils::{ - first_line_width, last_line_extendable, last_line_width, mk_sp, trimmed_last_line_width, - wrap_str, + first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, + trimmed_last_line_width, wrap_str, }; use std::borrow::Cow; use std::cmp::min; -use std::iter; use syntax::source_map::{BytePos, Span}; use syntax::{ast, ptr}; @@ -132,8 +131,8 @@ impl ChainItemKind { fn is_block_like(&self, context: &RewriteContext, reps: &str) -> bool { match self { ChainItemKind::Parent(ref expr) => is_block_expr(context, expr, reps), - ChainItemKind::MethodCall(..) => reps.contains('\n'), - ChainItemKind::StructField(..) + ChainItemKind::MethodCall(..) + | ChainItemKind::StructField(..) | ChainItemKind::TupleField(..) | ChainItemKind::Comment(..) => false, } @@ -190,10 +189,12 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => { Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)? } - ChainItemKind::StructField(ident) => format!(".{}", ident.name), - ChainItemKind::TupleField(ident, nested) => { - format!("{}.{}", if nested { " " } else { "" }, ident.name) - } + ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)), + ChainItemKind::TupleField(ident, nested) => format!( + "{}.{}", + if nested { " " } else { "" }, + rewrite_ident(context, ident) + ), ChainItemKind::Comment(ref comment, _) => { rewrite_comment(comment, false, shape, context.config)? } @@ -241,7 +242,7 @@ fn rewrite_method_call( format!("::<{}>", type_list.join(", ")) }; - let callee_str = format!(".{}{}", method_name, type_str); + let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str); rewrite_call(context, &callee_str, &args[1..], span, shape) } } @@ -273,6 +274,20 @@ fn is_tries(s: &str) -> bool { s.chars().all(|c| c == '?') } + fn is_post_comment(s: &str) -> bool { + let comment_start_index = s.chars().position(|c| c == '/'); + if comment_start_index.is_none() { + return false; + } + + let newline_index = s.chars().position(|c| c == '\n'); + if newline_index.is_none() { + return true; + } + + comment_start_index.unwrap() < newline_index.unwrap() + } + fn handle_post_comment( post_comment_span: Span, post_comment_snippet: &str, @@ -287,25 +302,14 @@ fn handle_post_comment( // No post comment. return; } - // HACK: Treat `?`s as separators. - let trimmed_snippet = post_comment_snippet.trim_matches('?'); - let comment_end = get_comment_end(trimmed_snippet, "?", "", false); - let maybe_post_comment = extract_post_comment(trimmed_snippet, comment_end, "?") - .and_then(|comment| { - if comment.is_empty() { - None - } else { - Some((comment, comment_end)) - } - }); - - if let Some((post_comment, comment_end)) = maybe_post_comment { + let trimmed_snippet = trim_tries(post_comment_snippet); + if is_post_comment(&trimmed_snippet) { children.push(ChainItem::comment( post_comment_span, - post_comment, + trimmed_snippet.trim().to_owned(), CommentPosition::Back, )); - *prev_span_end = *prev_span_end + BytePos(comment_end as u32); + *prev_span_end = post_comment_span.hi(); } } @@ -334,9 +338,8 @@ fn handle_post_comment( // Pre-comment if handle_comment { let pre_comment_span = mk_sp(prev_span_end, chain_item.span.lo()); - let pre_comment_snippet = context.snippet(pre_comment_span); - let pre_comment_snippet = pre_comment_snippet.trim().trim_matches('?'); - let (pre_comment, _) = extract_pre_comment(pre_comment_snippet); + let pre_comment_snippet = trim_tries(context.snippet(pre_comment_span)); + let (pre_comment, _) = extract_pre_comment(&pre_comment_snippet); match pre_comment { Some(ref comment) if !comment.is_empty() => { children.push(ChainItem::comment( @@ -555,7 +558,8 @@ fn format_last_child( shape.width } else { min(shape.width, context.config.width_heuristics().chain_width) - }.saturating_sub(almost_total); + } + .saturating_sub(almost_total); let all_in_one_line = !self.children.iter().any(ChainItem::is_comment) && self.rewrites.iter().all(|s| !s.contains('\n')) @@ -572,7 +576,15 @@ fn format_last_child( if all_in_one_line || extendable { // First we try to 'overflow' the last child and see if it looks better than using // vertical layout. - if let Some(one_line_shape) = last_shape.offset_left(almost_total) { + let one_line_shape = if context.use_block_indent() { + last_shape.offset_left(almost_total) + } else { + last_shape + .visual_indent(almost_total) + .sub_width(almost_total) + }; + + if let Some(one_line_shape) = one_line_shape { if let Some(rw) = last.rewrite(context, one_line_shape) { // We allow overflowing here only if both of the following conditions match: // 1. The entire chain fits in a single line except the last child. @@ -610,17 +622,18 @@ fn format_last_child( } } + let last_shape = if context.use_block_indent() { + last_shape + } else { + child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)? + }; + last_subexpr_str = last_subexpr_str.or_else(|| last.rewrite(context, last_shape)); self.rewrites.push(last_subexpr_str?); Some(()) } - fn join_rewrites( - &self, - context: &RewriteContext, - child_shape: Shape, - block_like_iter: impl Iterator, - ) -> Option { + fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { let connector = if self.fits_single_line { // Yay, we can put everything on one line. Cow::from("") @@ -635,17 +648,13 @@ fn join_rewrites( let mut rewrite_iter = self.rewrites.iter(); let mut result = rewrite_iter.next().unwrap().clone(); let children_iter = self.children.iter(); - let iter = rewrite_iter.zip(block_like_iter).zip(children_iter); + let iter = rewrite_iter.zip(children_iter); - for ((rewrite, prev_is_block_like), chain_item) in iter { + for (rewrite, chain_item) in iter { match chain_item.kind { ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '), ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector), - _ => { - if !prev_is_block_like { - result.push_str(&connector); - } - } + _ => result.push_str(&connector), } result.push_str(&rewrite); } @@ -657,15 +666,14 @@ fn join_rewrites( // Formats a chain using block indent. struct ChainFormatterBlock<'a> { shared: ChainFormatterShared<'a>, - // For each rewrite, whether the corresponding item is block-like. - is_block_like: Vec, + root_ends_with_block: bool, } impl<'a> ChainFormatterBlock<'a> { fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> { ChainFormatterBlock { shared: ChainFormatterShared::new(chain), - is_block_like: Vec::with_capacity(chain.children.len() + 1), + root_ends_with_block: false, } } } @@ -693,33 +701,32 @@ fn format_root( None => break, } - root_ends_with_block = item.kind.is_block_like(context, &root_rewrite); + root_ends_with_block = last_line_extendable(&root_rewrite); self.shared.children = &self.shared.children[1..]; if self.shared.children.is_empty() { break; } } - self.is_block_like.push(root_ends_with_block); self.shared.rewrites.push(root_rewrite); + self.root_ends_with_block = root_ends_with_block; Some(()) } fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option { Some( - if self.is_block_like[0] { + if self.root_ends_with_block { shape.block_indent(0) } else { shape.block_indent(context.config.tab_spaces()) - }.with_max_width(context.config), + } + .with_max_width(context.config), ) } fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> { for item in &self.shared.children[..self.shared.children.len() - 1] { let rewrite = item.rewrite(context, child_shape)?; - self.is_block_like - .push(item.kind.is_block_like(context, &rewrite)); self.shared.rewrites.push(rewrite); } Some(()) @@ -736,8 +743,7 @@ fn format_last_child( } fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { - self.shared - .join_rewrites(context, child_shape, self.is_block_like.iter().cloned()) + self.shared.join_rewrites(context, child_shape) } fn pure_root(&mut self) -> Option { @@ -831,8 +837,7 @@ fn format_last_child( } fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { - self.shared - .join_rewrites(context, child_shape, iter::repeat(false)) + self.shared.join_rewrites(context, child_shape) } fn pure_root(&mut self) -> Option { @@ -847,6 +852,7 @@ fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool ast::ExprKind::Mac(..) | ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) + | ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) | ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) @@ -870,3 +876,28 @@ fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool _ => false, } } + +/// Remove try operators (`?`s) that appear in the given string. If removing +/// them leaves an empty line, remove that line as well unless it is the first +/// line (we need the first newline for detecting pre/post comment). +fn trim_tries(s: &str) -> String { + let mut result = String::with_capacity(s.len()); + let mut line_buffer = String::with_capacity(s.len()); + for (kind, rich_char) in CharClasses::new(s.chars()) { + match rich_char.get_char() { + '\n' => { + if result.is_empty() || !line_buffer.trim().is_empty() { + result.push_str(&line_buffer); + result.push('\n') + } + line_buffer.clear(); + } + '?' if kind == FullCodeCharKind::Normal => continue, + c => line_buffer.push(c), + } + } + if !line_buffer.trim().is_empty() { + result.push_str(&line_buffer); + } + result +}