diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/convert_comment_block.rs | 105 |
1 files changed, 54 insertions, 51 deletions
diff --git a/crates/ide_assists/src/handlers/convert_comment_block.rs b/crates/ide_assists/src/handlers/convert_comment_block.rs index 7cf5f3643..cdc45fc42 100644 --- a/crates/ide_assists/src/handlers/convert_comment_block.rs +++ b/crates/ide_assists/src/handlers/convert_comment_block.rs | |||
@@ -1,8 +1,14 @@ | |||
1 | use ast::{Comment, CommentShape}; | ||
2 | use itertools::Itertools; | 1 | use itertools::Itertools; |
3 | use std::convert::identity; | 2 | use std::convert::identity; |
4 | use syntax::{ | 3 | use syntax::{ |
5 | ast::{self, edit::IndentLevel, CommentKind, Whitespace}, | 4 | ast::{ |
5 | self, | ||
6 | edit::IndentLevel, | ||
7 | Comment, CommentKind, | ||
8 | CommentPlacement::{Inner, Outer}, | ||
9 | CommentShape::{self, Block, Line}, | ||
10 | Whitespace, | ||
11 | }, | ||
6 | AstToken, Direction, SyntaxElement, TextRange, | 12 | AstToken, Direction, SyntaxElement, TextRange, |
7 | }; | 13 | }; |
8 | 14 | ||
@@ -42,34 +48,37 @@ pub(crate) fn convert_comment_block(acc: &mut Assists, ctx: &AssistContext) -> O | |||
42 | } | 48 | } |
43 | 49 | ||
44 | fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | 50 | fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { |
45 | let indentation = IndentLevel::from_token(comment.syntax()); | ||
46 | let line_prefix = | ||
47 | comment_kind_prefix(CommentKind { shape: CommentShape::Line, ..comment.kind() }); | ||
48 | |||
49 | let text = comment.text(); | ||
50 | let text = &text[comment.prefix().len()..(text.len() - "*/".len())].trim(); | ||
51 | |||
52 | let lines = text.lines().peekable(); | ||
53 | |||
54 | let indent_spaces = indentation.to_string(); | ||
55 | let output = lines | ||
56 | .map(|l| l.trim_start_matches(&indent_spaces)) | ||
57 | .map(|l| { | ||
58 | // Don't introduce trailing whitespace | ||
59 | if l.is_empty() { | ||
60 | line_prefix.to_string() | ||
61 | } else { | ||
62 | format!("{} {}", line_prefix, l.trim_start_matches(&indent_spaces)) | ||
63 | } | ||
64 | }) | ||
65 | .join(&format!("\n{}", indent_spaces)); | ||
66 | |||
67 | let target = comment.syntax().text_range(); | 51 | let target = comment.syntax().text_range(); |
52 | |||
68 | acc.add( | 53 | acc.add( |
69 | AssistId("block_to_line", AssistKind::RefactorRewrite), | 54 | AssistId("block_to_line", AssistKind::RefactorRewrite), |
70 | "Replace block comment with line comments", | 55 | "Replace block comment with line comments", |
71 | target, | 56 | target, |
72 | |edit| edit.replace(target, output), | 57 | |edit| { |
58 | let indentation = IndentLevel::from_token(comment.syntax()); | ||
59 | let line_prefix = | ||
60 | comment_kind_prefix(CommentKind { shape: CommentShape::Line, ..comment.kind() }); | ||
61 | |||
62 | let text = comment.text(); | ||
63 | let text = &text[comment.prefix().len()..(text.len() - "*/".len())].trim(); | ||
64 | |||
65 | let lines = text.lines().peekable(); | ||
66 | |||
67 | let indent_spaces = indentation.to_string(); | ||
68 | let output = lines | ||
69 | .map(|l| l.trim_start_matches(&indent_spaces)) | ||
70 | .map(|l| { | ||
71 | // Don't introduce trailing whitespace | ||
72 | if l.is_empty() { | ||
73 | line_prefix.to_string() | ||
74 | } else { | ||
75 | format!("{} {}", line_prefix, l.trim_start_matches(&indent_spaces)) | ||
76 | } | ||
77 | }) | ||
78 | .join(&format!("\n{}", indent_spaces)); | ||
79 | |||
80 | edit.replace(target, output) | ||
81 | }, | ||
73 | ) | 82 | ) |
74 | } | 83 | } |
75 | 84 | ||
@@ -83,24 +92,27 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | |||
83 | comments.last().unwrap().syntax().text_range().end(), | 92 | comments.last().unwrap().syntax().text_range().end(), |
84 | ); | 93 | ); |
85 | 94 | ||
86 | // We pick a single indentation level for the whole block comment based on the | ||
87 | // comment where the assist was invoked. This will be prepended to the | ||
88 | // contents of each line comment when they're put into the block comment. | ||
89 | let indentation = IndentLevel::from_token(&comment.syntax()); | ||
90 | |||
91 | let block_comment_body = | ||
92 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); | ||
93 | |||
94 | let block_prefix = | ||
95 | comment_kind_prefix(CommentKind { shape: CommentShape::Block, ..comment.kind() }); | ||
96 | |||
97 | let output = format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation.to_string()); | ||
98 | |||
99 | acc.add( | 95 | acc.add( |
100 | AssistId("line_to_block", AssistKind::RefactorRewrite), | 96 | AssistId("line_to_block", AssistKind::RefactorRewrite), |
101 | "Replace line comments with a single block comment", | 97 | "Replace line comments with a single block comment", |
102 | target, | 98 | target, |
103 | |edit| edit.replace(target, output), | 99 | |edit| { |
100 | // We pick a single indentation level for the whole block comment based on the | ||
101 | // comment where the assist was invoked. This will be prepended to the | ||
102 | // contents of each line comment when they're put into the block comment. | ||
103 | let indentation = IndentLevel::from_token(&comment.syntax()); | ||
104 | |||
105 | let block_comment_body = | ||
106 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); | ||
107 | |||
108 | let block_prefix = | ||
109 | comment_kind_prefix(CommentKind { shape: CommentShape::Block, ..comment.kind() }); | ||
110 | |||
111 | let output = | ||
112 | format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation.to_string()); | ||
113 | |||
114 | edit.replace(target, output) | ||
115 | }, | ||
104 | ) | 116 | ) |
105 | } | 117 | } |
106 | 118 | ||
@@ -160,27 +172,18 @@ fn relevant_line_comments(comment: &ast::Comment) -> Vec<Comment> { | |||
160 | // | 172 | // |
161 | // But since such comments aren't idiomatic we're okay with this. | 173 | // But since such comments aren't idiomatic we're okay with this. |
162 | fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { | 174 | fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { |
163 | let contents = trim_one(comm.text().strip_prefix(comm.prefix()).unwrap()).to_owned(); | 175 | let contents_without_prefix = comm.text().strip_prefix(comm.prefix()).unwrap(); |
176 | let contents = contents_without_prefix.strip_prefix(' ').unwrap_or(contents_without_prefix); | ||
164 | 177 | ||
165 | // Don't add the indentation if the line is empty | 178 | // Don't add the indentation if the line is empty |
166 | if contents.is_empty() { | 179 | if contents.is_empty() { |
167 | contents | 180 | contents.to_owned() |
168 | } else { | 181 | } else { |
169 | indentation.to_string() + &contents | 182 | indentation.to_string() + &contents |
170 | } | 183 | } |
171 | } | 184 | } |
172 | 185 | ||
173 | fn trim_one(text: &str) -> &str { | ||
174 | if text.starts_with(' ') { | ||
175 | &text[1..] | ||
176 | } else { | ||
177 | text | ||
178 | } | ||
179 | } | ||
180 | |||
181 | fn comment_kind_prefix(ck: ast::CommentKind) -> &'static str { | 186 | fn comment_kind_prefix(ck: ast::CommentKind) -> &'static str { |
182 | use ast::CommentPlacement::{Inner, Outer}; | ||
183 | use ast::CommentShape::{Block, Line}; | ||
184 | match (ck.shape, ck.doc) { | 187 | match (ck.shape, ck.doc) { |
185 | (Line, Some(Inner)) => "//!", | 188 | (Line, Some(Inner)) => "//!", |
186 | (Line, Some(Outer)) => "///", | 189 | (Line, Some(Outer)) => "///", |