X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcomment.rs;h=8b8112618b4a8c948ae616846cd74cdc5c2a57b0;hb=16184d3e165018fa5b78f5f99cfc844e5af33bd6;hp=a236c2699a6fcfdf4dd205fd5299c3f2a34bf22b;hpb=9e963b87fced64c0df49f263da2e577153480944;p=rust.git diff --git a/src/comment.rs b/src/comment.rs index a236c2699a6..8b8112618b4 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -64,10 +64,10 @@ pub fn opener(&self) -> &'a str { pub fn closer(&self) -> &'a str { match *self { - CommentStyle::DoubleSlash | - CommentStyle::TripleSlash | - CommentStyle::Custom(..) | - CommentStyle::Doc => "", + CommentStyle::DoubleSlash + | CommentStyle::TripleSlash + | CommentStyle::Custom(..) + | CommentStyle::Doc => "", CommentStyle::DoubleBullet => " **/", CommentStyle::SingleBullet | CommentStyle::Exclamation => " */", } @@ -152,7 +152,7 @@ pub fn combine_strs_with_missing_comments( last_line_width(prev_str) + first_line_width(next_str) + first_sep.len(); let indent_str = shape.indent.to_string(context.config); - let missing_comment = try_opt!(rewrite_missing_comment(span, shape, context)); + let missing_comment = rewrite_missing_comment(span, shape, context)?; if missing_comment.is_empty() { if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width { @@ -170,7 +170,7 @@ pub fn combine_strs_with_missing_comments( // We have a missing comment between the first expression and the second expression. // Peek the the original source code and find out whether there is a newline between the first - // expression and the second expression or the missing comment. We will preserve the orginal + // expression and the second expression or the missing comment. We will preserve the original // layout whenever possible. let original_snippet = context.snippet(span); let prefer_same_line = if let Some(pos) = original_snippet.chars().position(|c| c == '/') { @@ -205,11 +205,7 @@ pub fn combine_strs_with_missing_comments( }; Some(format!( "{}{}{}{}{}", - prev_str, - first_sep, - missing_comment, - second_sep, - next_str, + prev_str, first_sep, missing_comment, second_sep, next_str, )) } @@ -224,9 +220,7 @@ pub fn rewrite_comment( // we should stop now. let num_bare_lines = orig.lines() .map(|line| line.trim()) - .filter(|l| { - !(l.starts_with('*') || l.starts_with("//") || l.starts_with("/*")) - }) + .filter(|l| !(l.starts_with('*') || l.starts_with("//") || l.starts_with("/*"))) .count(); if num_bare_lines > 0 && !config.normalize_comments() { return Some(orig.to_owned()); @@ -254,13 +248,7 @@ fn identify_comment( .collect::>() .join("\n"); - let first_group_str = try_opt!(rewrite_comment_inner( - &first_group, - block_style, - style, - shape, - config, - )); + let first_group_str = rewrite_comment_inner(&first_group, block_style, style, shape, config)?; if rest.is_empty() { Some(first_group_str) } else { @@ -293,12 +281,13 @@ fn rewrite_comment_inner( .checked_sub(closer.len() + opener.len()) .unwrap_or(1); let indent_str = shape.indent.to_string(config); - let fmt = StringFormat { + let fmt_indent = shape.indent + (opener.len() - line_start.len()); + let mut fmt = StringFormat { opener: "", closer: "", line_start: line_start, line_end: "", - shape: Shape::legacy(max_chars, shape.indent + (opener.len() - line_start.len())), + shape: Shape::legacy(max_chars, fmt_indent), trim_end: true, config: config, }; @@ -316,33 +305,85 @@ fn rewrite_comment_inner( line }) .map(|s| left_trim_comment_line(s, &style)) - .map(|line| if orig.starts_with("/*") && line_breaks == 0 { - line.trim_left() - } else { - line + .map(|line| { + if orig.starts_with("/*") && line_breaks == 0 { + line.trim_left() + } else { + line + } }); let mut result = opener.to_owned(); + let mut is_prev_line_multi_line = false; + let mut inside_code_block = false; + let comment_line_separator = format!("\n{}{}", indent_str, line_start); for line in lines { if result == opener { if line.is_empty() { continue; } + } else if is_prev_line_multi_line && !line.is_empty() { + result.push(' ') } else { - result.push('\n'); - result.push_str(&indent_str); - result.push_str(line_start); + result.push_str(&comment_line_separator); + } + + if line.starts_with("```") { + inside_code_block = !inside_code_block; + } + if inside_code_block { + result.push_str(line); + continue; } - if config.wrap_comments() && line.len() > max_chars { - let rewrite = rewrite_string(line, &fmt).unwrap_or_else(|| line.to_owned()); - result.push_str(&rewrite); + if config.wrap_comments() && line.len() > fmt.shape.width && !has_url(line) { + match rewrite_string(line, &fmt, Some(max_chars)) { + Some(ref s) => { + is_prev_line_multi_line = s.contains('\n'); + result.push_str(s); + } + None if is_prev_line_multi_line => { + // We failed to put the current `line` next to the previous `line`. + // Remove the trailing space, then start rewrite on the next line. + result.pop(); + result.push_str(&comment_line_separator); + fmt.shape = Shape::legacy(max_chars, fmt_indent); + match rewrite_string(line, &fmt, Some(max_chars)) { + Some(ref s) => { + is_prev_line_multi_line = s.contains('\n'); + result.push_str(s); + } + None => { + is_prev_line_multi_line = false; + result.push_str(line); + } + } + } + None => { + is_prev_line_multi_line = false; + result.push_str(line); + } + } + + fmt.shape = if is_prev_line_multi_line { + // 1 = " " + let offset = 1 + last_line_width(&result) - line_start.len(); + Shape { + width: max_chars.checked_sub(offset).unwrap_or(0), + indent: fmt_indent, + offset: fmt.shape.offset + offset, + } + } else { + Shape::legacy(max_chars, fmt_indent) + }; } else { if line.is_empty() && result.ends_with(' ') { // Remove space if this is an empty comment or a doc comment. result.pop(); } result.push_str(line); + fmt.shape = Shape::legacy(max_chars, fmt_indent); + is_prev_line_multi_line = false; } } @@ -355,6 +396,12 @@ fn rewrite_comment_inner( Some(result) } +/// Returns true if the given string MAY include URLs or alike. +fn has_url(s: &str) -> bool { + // This function may return false positive, but should get its job done in most cases. + s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://") +} + /// Given the span, rewrite the missing comment inside it if available. /// Note that the given span must only include comments (or leading/trailing whitespaces). pub fn rewrite_missing_comment( @@ -380,7 +427,7 @@ pub fn recover_missing_comment_in_span( context: &RewriteContext, used_width: usize, ) -> Option { - let missing_comment = try_opt!(rewrite_missing_comment(span, shape, context)); + let missing_comment = rewrite_missing_comment(span, shape, context)?; if missing_comment.is_empty() { Some(String::new()) } else { @@ -505,6 +552,35 @@ pub fn contains_comment(text: &str) -> bool { CharClasses::new(text.chars()).any(|(kind, _)| kind.is_comment()) } +/// Remove trailing spaces from the specified snippet. We do not remove spaces +/// inside strings or comments. +pub fn remove_trailing_white_spaces(text: &str) -> String { + let mut buffer = String::with_capacity(text.len()); + let mut space_buffer = String::with_capacity(128); + for (char_kind, c) in CharClasses::new(text.chars()) { + match c { + '\n' => { + if char_kind == FullCodeCharKind::InString { + buffer.push_str(&space_buffer); + } + space_buffer.clear(); + buffer.push('\n'); + } + _ if c.is_whitespace() => { + space_buffer.push(c); + } + _ => { + if !space_buffer.is_empty() { + buffer.push_str(&space_buffer); + space_buffer.clear(); + } + buffer.push(c); + } + } + } + buffer +} + struct CharClasses where T: Iterator, @@ -575,9 +651,9 @@ enum FullCodeCharKind { impl FullCodeCharKind { fn is_comment(&self) -> bool { match *self { - FullCodeCharKind::StartComment | - FullCodeCharKind::InComment | - FullCodeCharKind::EndComment => true, + FullCodeCharKind::StartComment + | FullCodeCharKind::InComment + | FullCodeCharKind::EndComment => true, _ => false, } } @@ -612,7 +688,7 @@ impl Iterator for CharClasses type Item = (FullCodeCharKind, T::Item); fn next(&mut self) -> Option<(FullCodeCharKind, T::Item)> { - let item = try_opt!(self.base.next()); + let item = self.base.next()?; let chr = item.get_char(); let mut char_kind = FullCodeCharKind::Normal; self.status = match self.status { @@ -720,7 +796,7 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> { type Item = (CodeCharKind, usize, &'a str); fn next(&mut self) -> Option { - let (kind, (start_idx, _)) = try_opt!(self.iter.next()); + let (kind, (start_idx, _)) = self.iter.next()?; match kind { FullCodeCharKind::Normal | FullCodeCharKind::InString => { // Consume all the Normal code @@ -904,14 +980,14 @@ impl<'a> Iterator for CommentReducer<'a> { type Item = char; fn next(&mut self) -> Option { loop { - let mut c = try_opt!(self.iter.next()); + let mut c = self.iter.next()?; if self.is_block && self.at_start_line { while c.is_whitespace() { - c = try_opt!(self.iter.next()); + c = self.iter.next()?; } // Ignore leading '*' if c == '*' { - c = try_opt!(self.iter.next()); + c = self.iter.next()?; } } else if c == '\n' { self.at_start_line = true;