]> git.lizzy.rs Git - rust.git/commitdiff
Generalize combine_attr_and_expr
authortopecongiro <seuchida@gmail.com>
Fri, 11 Aug 2017 08:52:13 +0000 (17:52 +0900)
committertopecongiro <seuchida@gmail.com>
Fri, 11 Aug 2017 08:52:13 +0000 (17:52 +0900)
src/comment.rs
src/expr.rs
src/utils.rs

index d332c354b12eac17887f2b9666890ff42bf7399e..0a716aa308c17adff41acb33da32efb3749dea4d 100644 (file)
@@ -18,7 +18,7 @@
 use config::Config;
 use rewrite::RewriteContext;
 use string::{rewrite_string, StringFormat};
-use utils::wrap_str;
+use utils::{first_line_width, last_line_width, wrap_str};
 
 fn is_custom_comment(comment: &str) -> bool {
     if !comment.starts_with("//") {
@@ -136,6 +136,93 @@ fn comment_style(orig: &str, normalize_comments: bool) -> CommentStyle {
     }
 }
 
+pub fn combine_strs_with_missing_comments(
+    context: &RewriteContext,
+    prev_str: &str,
+    next_str: &str,
+    span: Span,
+    shape: Shape,
+    allow_extend: bool,
+) -> Option<String> {
+    let mut allow_one_line = !prev_str.contains('\n') && !next_str.contains('\n');
+    let first_sep = if prev_str.is_empty() || next_str.is_empty() {
+        ""
+    } else {
+        " "
+    };
+    let mut one_line_width =
+        last_line_width(prev_str) + first_line_width(next_str) + first_sep.len();
+
+    let original_snippet = context.snippet(span);
+    let trimmed_snippet = original_snippet.trim();
+    let indent_str = shape.indent.to_string(context.config);
+
+    if trimmed_snippet.is_empty() {
+        if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width {
+            return Some(format!("{}{}{}", prev_str, first_sep, next_str));
+        } else {
+            let sep = if prev_str.is_empty() {
+                String::new()
+            } else {
+                String::from("\n") + &indent_str
+            };
+            return Some(format!("{}{}{}", prev_str, sep, next_str));
+        }
+    }
+
+    // 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
+    // layout whenever possible.
+    let prefer_same_line = if let Some(pos) = original_snippet.chars().position(|c| c == '/') {
+        !original_snippet[..pos].contains('\n')
+    } else {
+        !original_snippet.contains('\n')
+    };
+
+    let missing_comment = try_opt!(rewrite_comment(
+        trimmed_snippet,
+        false,
+        shape,
+        context.config
+    ));
+    one_line_width -= first_sep.len();
+    let first_sep = if prev_str.is_empty() || missing_comment.is_empty() {
+        String::new()
+    } else {
+        let one_line_width = last_line_width(prev_str) + first_line_width(&missing_comment) + 1;
+        if prefer_same_line && one_line_width <= shape.width {
+            String::from(" ")
+        } else {
+            format!("\n{}", indent_str)
+        }
+    };
+    let second_sep = if missing_comment.is_empty() || next_str.is_empty() {
+        String::new()
+    } else {
+        if missing_comment.starts_with("//") {
+            format!("\n{}", indent_str)
+        } else {
+            one_line_width += missing_comment.len() + first_sep.len() + 1;
+            allow_one_line &= !missing_comment.starts_with("//") && !missing_comment.contains('\n');
+            if prefer_same_line && allow_one_line && one_line_width <= shape.width {
+                String::from(" ")
+            } else {
+                format!("\n{}", indent_str)
+            }
+        }
+    };
+    Some(format!(
+        "{}{}{}{}{}",
+        prev_str,
+        first_sep,
+        missing_comment,
+        second_sep,
+        next_str,
+    ))
+}
+
 pub fn rewrite_comment(
     orig: &str,
     block_style: bool,
index d0e5df3abbbad35487cc5e19dd0fef013bcedb05..c785f4883c4e895e6d54eca5c816efc432618d58 100644 (file)
@@ -19,7 +19,8 @@
 use {Indent, Shape, Spanned};
 use chains::rewrite_chain;
 use codemap::{LineRangeUtils, SpanUtils};
-use comment::{contains_comment, recover_comment_removed, rewrite_comment, FindUncommented};
+use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
+              rewrite_comment, FindUncommented};
 use config::{Config, ControlBraceStyle, IndentStyle, MultilineStyle, Style};
 use items::{span_hi_for_arg, span_lo_for_arg};
 use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting,
@@ -49,61 +50,6 @@ pub enum ExprType {
     SubExpression,
 }
 
-fn combine_attr_and_expr(
-    context: &RewriteContext,
-    shape: Shape,
-    expr: &ast::Expr,
-    expr_str: &str,
-) -> Option<String> {
-    let attrs = outer_attributes(&expr.attrs);
-    let attr_str = try_opt!(attrs.rewrite(context, shape));
-    let separator = if attr_str.is_empty() {
-        String::new()
-    } else {
-        // Try to recover comments between the attributes and the expression if available.
-        let missing_snippet = context.snippet(mk_sp(attrs[attrs.len() - 1].span.hi, expr.span.lo));
-        let comment_opening_pos = missing_snippet.chars().position(|c| c == '/');
-        let prefer_same_line = if let Some(pos) = comment_opening_pos {
-            !missing_snippet[..pos].contains('\n')
-        } else {
-            !missing_snippet.contains('\n')
-        };
-
-        let trimmed = missing_snippet.trim();
-        let missing_comment = if trimmed.is_empty() {
-            String::new()
-        } else {
-            try_opt!(rewrite_comment(&trimmed, false, shape, context.config))
-        };
-
-        // 2 = ` ` + ` `
-        let one_line_width =
-            attr_str.len() + missing_comment.len() + 2 + first_line_width(expr_str);
-        let attr_expr_separator = if prefer_same_line && !missing_comment.starts_with("//") &&
-            one_line_width <= shape.width
-        {
-            String::from(" ")
-        } else {
-            format!("\n{}", shape.indent.to_string(context.config))
-        };
-
-        if missing_comment.is_empty() {
-            attr_expr_separator
-        } else {
-            // 1 = ` `
-            let one_line_width =
-                last_line_width(&attr_str) + 1 + first_line_width(&missing_comment);
-            let attr_comment_separator = if prefer_same_line && one_line_width <= shape.width {
-                String::from(" ")
-            } else {
-                format!("\n{}", shape.indent.to_string(context.config))
-            };
-            attr_comment_separator + &missing_comment + &attr_expr_separator
-        }
-    };
-    Some(format!("{}{}{}", attr_str, separator, expr_str))
-}
-
 pub fn format_expr(
     expr: &ast::Expr,
     expr_type: ExprType,
@@ -355,7 +301,13 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool {
             recover_comment_removed(expr_str, expr.span, context, shape)
         })
         .and_then(|expr_str| {
-            combine_attr_and_expr(context, shape, expr, &expr_str)
+            let attrs = outer_attributes(&expr.attrs);
+            let attrs_str = try_opt!(attrs.rewrite(context, shape));
+            let span = mk_sp(
+                attrs.last().map_or(expr.span.lo, |attr| attr.span.hi),
+                expr.span.lo,
+            );
+            combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
         })
 }
 
index c0861b8da20ab9eccd7e4589c5dfa5df3f9ba9ad..9a31289e8eb209729abd5987a6160abadb0928bb 100644 (file)
@@ -116,6 +116,16 @@ pub fn outer_attributes(attrs: &[ast::Attribute]) -> Vec<ast::Attribute> {
     filter_attributes(attrs, ast::AttrStyle::Outer)
 }
 
+#[inline]
+pub fn last_line_contains_single_line_comment(s: &str) -> bool {
+    s.lines().last().map_or(false, |l| l.contains("//"))
+}
+
+#[inline]
+pub fn is_attributes_extendable(attrs_str: &str) -> bool {
+    !attrs_str.contains('\n') && !last_line_contains_single_line_comment(&attrs_str)
+}
+
 // The width of the first line in s.
 #[inline]
 pub fn first_line_width(s: &str) -> usize {