]> git.lizzy.rs Git - rust.git/commitdiff
Put comment between chain elements on its original position
authorSeiichi Uchida <seuchida@gmail.com>
Sun, 5 Aug 2018 10:34:22 +0000 (19:34 +0900)
committerSeiichi Uchida <seuchida@gmail.com>
Sun, 5 Aug 2018 10:55:22 +0000 (19:55 +0900)
src/chains.rs

index 1937bfa1960acdd9437598684d94f7f1da231f79..99d943c494ac2541826c0f3359a3ae3fbb3f772e 100644 (file)
@@ -69,6 +69,7 @@
 use comment::rewrite_comment;
 use config::IndentStyle;
 use expr::rewrite_call;
+use lists::{extract_post_comment, extract_pre_comment, get_comment_end};
 use macros::convert_try_mac;
 use rewrite::{Rewrite, RewriteContext};
 use shape::Shape;
@@ -81,7 +82,7 @@
 use std::cmp::min;
 use std::iter;
 
-use syntax::codemap::Span;
+use syntax::codemap::{BytePos, Span};
 use syntax::{ast, ptr};
 
 pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option<String> {
@@ -97,6 +98,12 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
     chain.rewrite(context, shape)
 }
 
+#[derive(Debug)]
+enum CommentPosition {
+    Back,
+    Top,
+}
+
 // An expression plus trailing `?`s to be formatted together.
 #[derive(Debug)]
 struct ChainItem {
@@ -118,7 +125,7 @@ enum ChainItemKind {
     ),
     StructField(ast::Ident),
     TupleField(ast::Ident, bool),
-    Comment,
+    Comment(String, CommentPosition),
 }
 
 impl ChainItemKind {
@@ -128,7 +135,7 @@ fn is_block_like(&self, context: &RewriteContext, reps: &str) -> bool {
             ChainItemKind::MethodCall(..) => reps.contains('\n'),
             ChainItemKind::StructField(..)
             | ChainItemKind::TupleField(..)
-            | ChainItemKind::Comment => false,
+            | ChainItemKind::Comment(..) => false,
         }
     }
 
@@ -187,12 +194,9 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             ChainItemKind::TupleField(ident, nested) => {
                 format!("{}.{}", if nested { " " } else { "" }, ident.name)
             }
-            ChainItemKind::Comment => rewrite_comment(
-                context.snippet(self.span).trim(),
-                false,
-                shape,
-                context.config,
-            )?,
+            ChainItemKind::Comment(ref comment, _) => {
+                rewrite_comment(comment, false, shape, context.config)?
+            }
         };
         Some(format!("{}{}", rewrite, "?".repeat(self.tries)))
     }
@@ -204,9 +208,9 @@ fn new(context: &RewriteContext, expr: &ast::Expr, tries: usize) -> ChainItem {
         ChainItem { kind, tries, span }
     }
 
-    fn comment(span: Span) -> ChainItem {
+    fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem {
         ChainItem {
-            kind: ChainItemKind::Comment,
+            kind: ChainItemKind::Comment(comment, pos),
             tries: 0,
             span,
         }
@@ -214,7 +218,7 @@ fn comment(span: Span) -> ChainItem {
 
     fn is_comment(&self) -> bool {
         match self.kind {
-            ChainItemKind::Comment => true,
+            ChainItemKind::Comment(..) => true,
             _ => false,
         }
     }
@@ -269,21 +273,98 @@ fn is_tries(s: &str) -> bool {
             s.chars().all(|c| c == '?')
         }
 
+        fn handle_post_comment(
+            post_comment_span: Span,
+            post_comment_snippet: &str,
+            prev_span_end: &mut BytePos,
+            children: &mut Vec<ChainItem>,
+        ) {
+            let white_spaces: &[_] = &[' ', '\t'];
+            if post_comment_snippet
+                .trim_matches(white_spaces)
+                .starts_with('\n')
+            {
+                // 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 {
+                children.push(ChainItem::comment(
+                    post_comment_span,
+                    post_comment,
+                    CommentPosition::Back,
+                ));
+                *prev_span_end = *prev_span_end + BytePos(comment_end as u32);
+            }
+        }
+
         let parent = rev_children.pop().unwrap();
         let mut children = vec![];
-        let mut prev_hi = parent.span.hi();
-        for chain_item in rev_children.into_iter().rev() {
-            let comment_span = mk_sp(prev_hi, chain_item.span.lo());
+        let mut prev_span_end = parent.span.hi();
+        let mut iter = rev_children.into_iter().rev().peekable();
+        if let Some(first_chain_item) = iter.peek() {
+            let comment_span = mk_sp(prev_span_end, first_chain_item.span.lo());
             let comment_snippet = context.snippet(comment_span);
+            if !is_tries(comment_snippet.trim()) {
+                handle_post_comment(
+                    comment_span,
+                    comment_snippet,
+                    &mut prev_span_end,
+                    &mut children,
+                );
+            }
+        }
+        while let Some(chain_item) = iter.next() {
+            let comment_snippet = context.snippet(chain_item.span);
             // FIXME: Figure out the way to get a correct span when converting `try!` to `?`.
-            if !(context.config.use_try_shorthand()
-                || comment_snippet.trim().is_empty()
-                || is_tries(comment_snippet.trim()))
-            {
-                children.push(ChainItem::comment(comment_span));
+            let handle_comment =
+                !(context.config.use_try_shorthand() || is_tries(comment_snippet.trim()));
+
+            // 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, _) = extract_pre_comment(pre_comment_snippet);
+                match pre_comment {
+                    Some(ref comment) if !comment.is_empty() => {
+                        children.push(ChainItem::comment(
+                            pre_comment_span,
+                            comment.to_owned(),
+                            CommentPosition::Top,
+                        ));
+                    }
+                    _ => (),
+                }
             }
-            prev_hi = chain_item.span.hi();
+
+            prev_span_end = chain_item.span.hi();
             children.push(chain_item);
+
+            // Post-comment
+            if !handle_comment || iter.peek().is_none() {
+                continue;
+            }
+
+            let next_lo = iter.peek().unwrap().span.lo();
+            let post_comment_span = mk_sp(prev_span_end, next_lo);
+            let post_comment_snippet = context.snippet(post_comment_span);
+            handle_post_comment(
+                post_comment_span,
+                post_comment_snippet,
+                &mut prev_span_end,
+                &mut children,
+            );
         }
 
         Chain { parent, children }
@@ -552,13 +633,18 @@ 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);
 
-        for (rewrite, prev_is_block_like) in rewrite_iter.zip(block_like_iter) {
-            if !prev_is_block_like {
-                result.push_str(&connector);
-            } else if rewrite.starts_with('/') {
-                // This is comment, add a space before it.
-                result.push(' ');
+        for ((rewrite, prev_is_block_like), 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(&rewrite);
         }
@@ -597,7 +683,7 @@ fn format_root(
 
         while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
             let item = &self.shared.children[0];
-            if let ChainItemKind::Comment = item.kind {
+            if let ChainItemKind::Comment(..) = item.kind {
                 break;
             }
             let shape = shape.offset_left(root_rewrite.len())?;
@@ -692,7 +778,7 @@ fn format_root(
 
         if !multiline || parent.kind.is_block_like(context, &root_rewrite) {
             let item = &self.shared.children[0];
-            if let ChainItemKind::Comment = item.kind {
+            if let ChainItemKind::Comment(..) = item.kind {
                 self.shared.rewrites.push(root_rewrite);
                 return Some(());
             }