aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r--crates/ide_assists/src/handlers/convert_comment_block.rs105
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 @@
1use ast::{Comment, CommentShape};
2use itertools::Itertools; 1use itertools::Itertools;
3use std::convert::identity; 2use std::convert::identity;
4use syntax::{ 3use 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
44fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { 50fn 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.
162fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { 174fn 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
173fn trim_one(text: &str) -> &str {
174 if text.starts_with(' ') {
175 &text[1..]
176 } else {
177 text
178 }
179}
180
181fn comment_kind_prefix(ck: ast::CommentKind) -> &'static str { 186fn 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)) => "///",