aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/typing.rs1
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs67
2 files changed, 59 insertions, 9 deletions
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs
index 83776d2b6..d3ce744b4 100644
--- a/crates/ra_ide/src/typing.rs
+++ b/crates/ra_ide/src/typing.rs
@@ -39,7 +39,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
39// Some features trigger on typing certain characters: 39// Some features trigger on typing certain characters:
40// 40//
41// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression 41// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
42// - Enter inside comments automatically inserts `///`
43// - typing `.` in a chain method call auto-indents 42// - typing `.` in a chain method call auto-indents
44pub(crate) fn on_char_typed( 43pub(crate) fn on_char_typed(
45 db: &RootDatabase, 44 db: &RootDatabase,
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs
index 2faaa8ff0..143b1ae41 100644
--- a/crates/ra_ide/src/typing/on_enter.rs
+++ b/crates/ra_ide/src/typing/on_enter.rs
@@ -7,10 +7,31 @@ use ra_syntax::{
7 ast::{self, AstToken}, 7 ast::{self, AstToken},
8 AstNode, SmolStr, SourceFile, 8 AstNode, SmolStr, SourceFile,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxToken, TextSize, TokenAtOffset, 10 SyntaxToken, TextRange, TextSize, TokenAtOffset,
11}; 11};
12use ra_text_edit::TextEdit; 12use ra_text_edit::TextEdit;
13use test_utils::mark;
13 14
15// Feature: On Enter
16//
17// rust-analyzer can override kbd:[Enter] key to make it smarter:
18//
19// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
20// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
21//
22// This action needs to be assigned to shortcut explicitly.
23//
24// VS Code::
25//
26// Add the following to `keybindings.json`:
27// [source,json]
28// ----
29// {
30// "key": "Enter",
31// "command": "rust-analyzer.onEnter",
32// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
33// }
34// ----
14pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 35pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
15 let parse = db.parse(position.file_id); 36 let parse = db.parse(position.file_id);
16 let file = parse.tree(); 37 let file = parse.tree();
@@ -30,15 +51,25 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
30 return None; 51 return None;
31 } 52 }
32 53
54 let mut remove_last_space = false;
33 // Continuing single-line non-doc comments (like this one :) ) is annoying 55 // Continuing single-line non-doc comments (like this one :) ) is annoying
34 if prefix == "//" && comment_range.end() == position.offset && !followed_by_comment(&comment) { 56 if prefix == "//" && comment_range.end() == position.offset {
35 return None; 57 if comment.text().ends_with(' ') {
58 mark::hit!(continues_end_of_line_comment_with_space);
59 remove_last_space = true;
60 } else if !followed_by_comment(&comment) {
61 return None;
62 }
36 } 63 }
37 64
38 let indent = node_indent(&file, comment.syntax())?; 65 let indent = node_indent(&file, comment.syntax())?;
39 let inserted = format!("\n{}{} $0", indent, prefix); 66 let inserted = format!("\n{}{} $0", indent, prefix);
40 let edit = TextEdit::insert(position.offset, inserted); 67 let delete = if remove_last_space {
41 68 TextRange::new(position.offset - TextSize::of(' '), position.offset)
69 } else {
70 TextRange::empty(position.offset)
71 };
72 let edit = TextEdit::replace(delete, inserted);
42 Some(edit) 73 Some(edit)
43} 74}
44 75
@@ -75,10 +106,10 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> {
75 106
76#[cfg(test)] 107#[cfg(test)]
77mod tests { 108mod tests {
78 use test_utils::assert_eq_text; 109 use stdx::trim_indent;
110 use test_utils::{assert_eq_text, mark};
79 111
80 use crate::mock_analysis::analysis_and_position; 112 use crate::mock_analysis::analysis_and_position;
81 use stdx::trim_indent;
82 113
83 fn apply_on_enter(before: &str) -> Option<String> { 114 fn apply_on_enter(before: &str) -> Option<String> {
84 let (analysis, position) = analysis_and_position(&before); 115 let (analysis, position) = analysis_and_position(&before);
@@ -192,7 +223,7 @@ fn main() {
192 } 223 }
193 224
194 #[test] 225 #[test]
195 fn does_not_continue_end_of_code_comment() { 226 fn does_not_continue_end_of_line_comment() {
196 do_check_noop( 227 do_check_noop(
197 r" 228 r"
198fn main() { 229fn main() {
@@ -202,4 +233,24 @@ fn main() {
202", 233",
203 ); 234 );
204 } 235 }
236
237 #[test]
238 fn continues_end_of_line_comment_with_space() {
239 mark::check!(continues_end_of_line_comment_with_space);
240 do_check(
241 r#"
242fn main() {
243 // Fix me <|>
244 let x = 1 + 1;
245}
246"#,
247 r#"
248fn main() {
249 // Fix me
250 // $0
251 let x = 1 + 1;
252}
253"#,
254 );
255 }
205} 256}