]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide/src/typing/on_enter.rs
Merge #11433
[rust.git] / crates / ide / src / typing / on_enter.rs
index 7d2db201a0e935ae88802550664fca47f538c4d6..48c1713270b6c5c46c42deb7553ca98ac66384d3 100644 (file)
 //
 // This action needs to be assigned to shortcut explicitly.
 //
+// Note that, depending on the other installed extensions, this feature can visibly slow down typing.
+// Similarly, if rust-analyzer crashes or stops responding, `Enter` might not work.
+// In that case, you can still press `Shift-Enter` to insert a newline.
+//
 // VS Code::
 //
 // Add the following to `keybindings.json`:
 // }
 // ----
 //
+// When using the Vim plugin:
+// [source,json]
+// ----
+// {
+//   "key": "Enter",
+//   "command": "rust-analyzer.onEnter",
+//   "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && vim.mode == 'Insert'"
+// }
+// ----
+//
 // image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
 pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
     let parse = db.parse(position.file_id);
@@ -54,6 +68,14 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
             cov_mark::hit!(indent_block_contents);
             return Some(edit);
         }
+
+        // Typing enter after the `{` of a use tree list.
+        if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
+            .and_then(|list| on_enter_in_use_tree_list(list, position))
+        {
+            cov_mark::hit!(indent_block_contents);
+            return Some(edit);
+        }
     }
 
     None
@@ -80,12 +102,12 @@ fn on_enter_in_comment(
         if comment.text().ends_with(' ') {
             cov_mark::hit!(continues_end_of_line_comment_with_space);
             remove_trailing_whitespace = true;
-        } else if !followed_by_comment(&comment) {
+        } else if !followed_by_comment(comment) {
             return None;
         }
     }
 
-    let indent = node_indent(&file, comment.syntax())?;
+    let indent = node_indent(file, comment.syntax())?;
     let inserted = format!("\n{}{} $0", indent, prefix);
     let delete = if remove_trailing_whitespace {
         let trimmed_len = comment.text().trim_end().len() as u32;
@@ -111,6 +133,21 @@ fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option<Te
     Some(edit)
 }
 
+fn on_enter_in_use_tree_list(list: ast::UseTreeList, position: FilePosition) -> Option<TextEdit> {
+    if list.syntax().text().contains_char('\n') {
+        return None;
+    }
+
+    let indent = IndentLevel::from_node(list.syntax());
+    let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
+    edit.union(TextEdit::insert(
+        list.r_curly_token()?.text_range().start(),
+        format!("\n{}", indent),
+    ))
+    .ok()?;
+    Some(edit)
+}
+
 fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> {
     let mut node = block.tail_expr().map(|e| e.syntax().clone());
 
@@ -165,7 +202,7 @@ mod tests {
     use crate::fixture;
 
     fn apply_on_enter(before: &str) -> Option<String> {
-        let (analysis, position) = fixture::position(&before);
+        let (analysis, position) = fixture::position(before);
         let result = analysis.on_enter(position).unwrap()?;
 
         let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
@@ -484,4 +521,96 @@ fn f() {$0
         "#,
         );
     }
+
+    #[test]
+    fn indents_use_tree_list() {
+        do_check(
+            r#"
+use crate::{$0};
+            "#,
+            r#"
+use crate::{
+    $0
+};
+            "#,
+        );
+        do_check(
+            r#"
+use crate::{$0Object, path::to::OtherThing};
+            "#,
+            r#"
+use crate::{
+    $0Object, path::to::OtherThing
+};
+            "#,
+        );
+        do_check(
+            r#"
+use {crate::{$0Object, path::to::OtherThing}};
+            "#,
+            r#"
+use {crate::{
+    $0Object, path::to::OtherThing
+}};
+            "#,
+        );
+        do_check(
+            r#"
+use {
+    crate::{$0Object, path::to::OtherThing}
+};
+            "#,
+            r#"
+use {
+    crate::{
+        $0Object, path::to::OtherThing
+    }
+};
+            "#,
+        );
+    }
+
+    #[test]
+    fn does_not_indent_use_tree_list_when_not_at_curly_brace() {
+        do_check_noop(
+            r#"
+use path::{Thing$0};
+            "#,
+        );
+    }
+
+    #[test]
+    fn does_not_indent_use_tree_list_without_curly_braces() {
+        do_check_noop(
+            r#"
+use path::Thing$0;
+            "#,
+        );
+        do_check_noop(
+            r#"
+use path::$0Thing;
+            "#,
+        );
+        do_check_noop(
+            r#"
+use path::Thing$0};
+            "#,
+        );
+        do_check_noop(
+            r#"
+use path::{$0Thing;
+            "#,
+        );
+    }
+
+    #[test]
+    fn does_not_indent_multiline_use_tree_list() {
+        do_check_noop(
+            r#"
+use path::{$0
+    Thing
+};
+            "#,
+        );
+    }
 }