aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAdolfo OchagavĂ­a <[email protected]>2018-10-11 15:25:35 +0100
committerAdolfo OchagavĂ­a <[email protected]>2018-10-11 15:25:35 +0100
commitf88e13f5393c75b02c3619ec432675c3316ee6e5 (patch)
tree9a4d2611dec98a083ae2f6b99a04f68962bf2f01 /crates
parent27a86cb7df5e1764c85f5eeb8bb85885072f782e (diff)
Use Comment wrapper
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_editor/src/typing.rs52
-rw-r--r--crates/ra_syntax/src/ast/generated.rs18
-rw-r--r--crates/ra_syntax/src/ast/mod.rs43
-rw-r--r--crates/ra_syntax/src/grammar.ron1
4 files changed, 78 insertions, 36 deletions
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 6c1a91ffb..ae82ff89b 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -58,14 +58,19 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
58} 58}
59 59
60pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { 60pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
61 let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().filter(|it| it.kind() == COMMENT)?; 61 let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(|it| ast::Comment::cast(it))?;
62 let prefix = comment_preffix(comment)?; 62
63 if offset < comment.range().start() + TextUnit::of_str(prefix) { 63 if let ast::CommentFlavor::Multiline = comment.flavor() {
64 return None;
65 }
66
67 let prefix = comment.prefix();
68 if offset < comment.syntax().range().start() + TextUnit::of_str(prefix) + TextUnit::from(1) {
64 return None; 69 return None;
65 } 70 }
66 71
67 let indent = node_indent(file, comment)?; 72 let indent = node_indent(file, comment.syntax())?;
68 let inserted = format!("\n{}{}", indent, prefix); 73 let inserted = format!("\n{}{} ", indent, prefix);
69 let cursor_position = offset + TextUnit::of_str(&inserted); 74 let cursor_position = offset + TextUnit::of_str(&inserted);
70 let mut edit = EditBuilder::new(); 75 let mut edit = EditBuilder::new();
71 edit.insert(offset, inserted); 76 edit.insert(offset, inserted);
@@ -75,20 +80,6 @@ pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
75 }) 80 })
76} 81}
77 82
78fn comment_preffix(comment: SyntaxNodeRef) -> Option<&'static str> {
79 let text = comment.leaf_text().unwrap();
80 let res = if text.starts_with("///") {
81 "/// "
82 } else if text.starts_with("//!") {
83 "//! "
84 } else if text.starts_with("//") {
85 "// "
86 } else {
87 return None;
88 };
89 Some(res)
90}
91
92fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> { 83fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
93 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) { 84 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
94 LeafAtOffset::Between(l, r) => { 85 LeafAtOffset::Between(l, r) => {
@@ -166,31 +157,27 @@ fn remove_newline(
166 // Removes: comma, newline (incl. surrounding whitespace) 157 // Removes: comma, newline (incl. surrounding whitespace)
167 // Adds: a single whitespace 158 // Adds: a single whitespace
168 edit.replace(range, " ".to_string()); 159 edit.replace(range, " ".to_string());
169 } else if prev.kind() == COMMENT && next.kind() == COMMENT { 160 } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) {
170 // Removes: newline (incl. surrounding whitespace), start of the next comment 161 // Removes: newline (incl. surrounding whitespace), start of the next comment
171 162 let comment_text = next.text();
172 // FIXME: I guess it is safe to unwrap here? A comment always has text, right?
173 let comment_text = next.leaf_text().unwrap().as_str();
174 let comment_start_length = comment_start_length(comment_text);
175
176 if let Some(newline_pos) = comment_text.find('\n') { 163 if let Some(newline_pos) = comment_text.find('\n') {
177 // Special case for multi-line c-like comments: join the comment content but 164 // Special case for multi-line c-like comments: join the comment content but
178 // keep the leading `/*` 165 // keep the leading `/*`
179 166
180 let newline_offset = next.range().start() 167 let newline_offset = next.syntax().range().start()
181 + TextUnit::from(newline_pos as u32) 168 + TextUnit::from(newline_pos as u32)
182 + TextUnit::of_char('\n'); 169 + TextUnit::of_char('\n');
183 170
184 edit.insert(newline_offset, "/*".to_string()); 171 edit.insert(newline_offset, "/*".to_string());
185 edit.delete(TextRange::from_to( 172 edit.delete(TextRange::from_to(
186 node.range().start(), 173 node.range().start(),
187 next.range().start() + comment_start_length 174 next.syntax().range().start() + TextUnit::of_str(next.prefix())
188 )); 175 ));
189 } else { 176 } else {
190 // Single-line comments 177 // Single-line comments
191 edit.delete(TextRange::from_to( 178 edit.delete(TextRange::from_to(
192 node.range().start(), 179 node.range().start(),
193 next.range().start() + comment_start_length 180 next.syntax().range().start() + TextUnit::of_str(next.prefix())
194 )); 181 ));
195 } 182 }
196 } else { 183 } else {
@@ -205,7 +192,7 @@ fn remove_newline(
205 } 192 }
206 } 193 }
207 194
208 // FIXME: do we ever reach this point? What does it mean to be here? I think we should document it 195 // The node is either the first or the last in the file
209 let suff = &node_text[TextRange::from_to( 196 let suff = &node_text[TextRange::from_to(
210 offset - node.range().start() + TextUnit::of_char('\n'), 197 offset - node.range().start() + TextUnit::of_char('\n'),
211 TextUnit::of_str(node_text), 198 TextUnit::of_str(node_text),
@@ -218,13 +205,6 @@ fn remove_newline(
218 ); 205 );
219} 206}
220 207
221// Return the start length of the comment (e.g. 2 for `//` and 3 for `//!`)
222fn comment_start_length(_text: &str) -> TextUnit {
223 // TODO: use the parser here instead of reimplementing comment parsing?
224 // Otherwise, reimplement comment parsing :)
225 return TextUnit::from(2);
226}
227
228fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { 208fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
229 match (left, right) { 209 match (left, right) {
230 (COMMA, R_PAREN) | (COMMA, R_BRACK) => true, 210 (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 2db6dff1b..b0b855eb4 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -227,6 +227,24 @@ impl<'a> AstNode<'a> for CastExpr<'a> {
227 227
228impl<'a> CastExpr<'a> {} 228impl<'a> CastExpr<'a> {}
229 229
230// Comment
231#[derive(Debug, Clone, Copy)]
232pub struct Comment<'a> {
233 syntax: SyntaxNodeRef<'a>,
234}
235
236impl<'a> AstNode<'a> for Comment<'a> {
237 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
238 match syntax.kind() {
239 COMMENT => Some(Comment { syntax }),
240 _ => None,
241 }
242 }
243 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
244}
245
246impl<'a> Comment<'a> {}
247
230// Condition 248// Condition
231#[derive(Debug, Clone, Copy)] 249#[derive(Debug, Clone, Copy)]
232pub struct Condition<'a> { 250pub struct Condition<'a> {
diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast/mod.rs
index c1570b868..10dac72e5 100644
--- a/crates/ra_syntax/src/ast/mod.rs
+++ b/crates/ra_syntax/src/ast/mod.rs
@@ -99,6 +99,49 @@ impl<'a> Lifetime<'a> {
99 } 99 }
100} 100}
101 101
102impl<'a> Comment<'a> {
103 pub fn text(&self) -> SmolStr {
104 self.syntax().leaf_text().unwrap().clone()
105 }
106
107 pub fn flavor(&self) -> CommentFlavor {
108 let text = self.text();
109 if text.starts_with("///") {
110 CommentFlavor::Doc
111 } else if text.starts_with("//!") {
112 CommentFlavor::ModuleDoc
113 } else if text.starts_with("//") {
114 CommentFlavor::Line
115 } else {
116 CommentFlavor::Multiline
117 }
118 }
119
120 pub fn prefix(&self) -> &'static str {
121 self.flavor().prefix()
122 }
123}
124
125#[derive(Debug)]
126pub enum CommentFlavor {
127 Line,
128 Doc,
129 ModuleDoc,
130 Multiline
131}
132
133impl CommentFlavor {
134 pub fn prefix(&self) -> &'static str {
135 use self::CommentFlavor::*;
136 match *self {
137 Line => "//",
138 Doc => "///",
139 ModuleDoc => "//!",
140 Multiline => "/*"
141 }
142 }
143}
144
102impl<'a> Name<'a> { 145impl<'a> Name<'a> {
103 pub fn text(&self) -> SmolStr { 146 pub fn text(&self) -> SmolStr {
104 let ident = self.syntax().first_child() 147 let ident = self.syntax().first_child()
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 4b990fd8d..9da0c2c13 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -537,5 +537,6 @@ Grammar(
537 "PathSegment": ( 537 "PathSegment": (
538 options: [ "NameRef" ] 538 options: [ "NameRef" ]
539 ), 539 ),
540 "Comment": (),
540 }, 541 },
541) 542)