diff options
author | Jonas Schievink <[email protected]> | 2021-04-06 22:55:39 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-04-07 15:38:04 +0100 |
commit | 36cd724b7b146c33804db4b110111ad71be9cb72 (patch) | |
tree | c23b6b685a78c92a02d7102f7c5204dd5c16ba47 /crates | |
parent | 8e900cb4a1c5a4faef801518272d56a5683dd488 (diff) |
Autoclose blocks when typing `{`
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/typing.rs | 47 | ||||
-rw-r--r-- | crates/rust-analyzer/src/caps.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 1 |
3 files changed, 47 insertions, 3 deletions
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 11408d445..de65632e3 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -33,7 +33,8 @@ use crate::SourceChange; | |||
33 | 33 | ||
34 | pub(crate) use on_enter::on_enter; | 34 | pub(crate) use on_enter::on_enter; |
35 | 35 | ||
36 | pub(crate) const TRIGGER_CHARS: &str = ".=>"; | 36 | // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. |
37 | pub(crate) const TRIGGER_CHARS: &str = ".=>{"; | ||
37 | 38 | ||
38 | // Feature: On Typing Assists | 39 | // Feature: On Typing Assists |
39 | // | 40 | // |
@@ -70,10 +71,47 @@ fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> | |||
70 | '.' => on_dot_typed(file, offset), | 71 | '.' => on_dot_typed(file, offset), |
71 | '=' => on_eq_typed(file, offset), | 72 | '=' => on_eq_typed(file, offset), |
72 | '>' => on_arrow_typed(file, offset), | 73 | '>' => on_arrow_typed(file, offset), |
74 | '{' => on_opening_brace_typed(file, offset), | ||
73 | _ => unreachable!(), | 75 | _ => unreachable!(), |
74 | } | 76 | } |
75 | } | 77 | } |
76 | 78 | ||
79 | /// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a | ||
80 | /// block. | ||
81 | fn on_opening_brace_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | ||
82 | assert_eq!(file.syntax().text().char_at(offset), Some('{')); | ||
83 | let brace_token = file.syntax().token_at_offset(offset).right_biased()?; | ||
84 | let block = ast::BlockExpr::cast(brace_token.parent()?)?; | ||
85 | |||
86 | // We expect a block expression enclosing exactly 1 preexisting expression. It can be parsed as | ||
87 | // either the trailing expr or an ExprStmt. | ||
88 | let offset = { | ||
89 | match block.tail_expr() { | ||
90 | Some(expr) => { | ||
91 | if block.statements().next().is_some() { | ||
92 | return None; | ||
93 | } | ||
94 | expr.syntax().text_range().end() | ||
95 | } | ||
96 | None => { | ||
97 | if block.statements().count() != 1 { | ||
98 | return None; | ||
99 | } | ||
100 | |||
101 | match block.statements().next()? { | ||
102 | ast::Stmt::ExprStmt(it) => { | ||
103 | // Use the expression span to place `}` before the `;` | ||
104 | it.expr()?.syntax().text_range().end() | ||
105 | } | ||
106 | _ => return None, | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | }; | ||
111 | |||
112 | Some(TextEdit::insert(offset, "}".to_string())) | ||
113 | } | ||
114 | |||
77 | /// Returns an edit which should be applied after `=` was typed. Primarily, | 115 | /// Returns an edit which should be applied after `=` was typed. Primarily, |
78 | /// this works when adding `let =`. | 116 | /// this works when adding `let =`. |
79 | // FIXME: use a snippet completion instead of this hack here. | 117 | // FIXME: use a snippet completion instead of this hack here. |
@@ -373,4 +411,11 @@ fn main() { | |||
373 | fn adds_space_after_return_type() { | 411 | fn adds_space_after_return_type() { |
374 | type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") | 412 | type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") |
375 | } | 413 | } |
414 | |||
415 | #[test] | ||
416 | fn adds_closing_brace() { | ||
417 | type_char('{', r"fn f() { match () { _ => $0() } }", r"fn f() { match () { _ => {()} } }"); | ||
418 | type_char('{', r"fn f() { $0(); }", r"fn f() { {()}; }"); | ||
419 | type_char('{', r"fn f() { let x = $0(); }", r"fn f() { let x = {()}; }"); | ||
420 | } | ||
376 | } | 421 | } |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 7a5bcb8c7..3c87782f2 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -57,7 +57,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
57 | document_range_formatting_provider: None, | 57 | document_range_formatting_provider: None, |
58 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { | 58 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { |
59 | first_trigger_character: "=".to_string(), | 59 | first_trigger_character: "=".to_string(), |
60 | more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), | 60 | more_trigger_character: Some(vec![".".to_string(), ">".to_string(), "{".to_string()]), |
61 | }), | 61 | }), |
62 | selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), | 62 | selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), |
63 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), | 63 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 4d10a2ead..31d8c487b 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -231,7 +231,6 @@ pub(crate) fn handle_on_enter( | |||
231 | Ok(Some(edit)) | 231 | Ok(Some(edit)) |
232 | } | 232 | } |
233 | 233 | ||
234 | // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. | ||
235 | pub(crate) fn handle_on_type_formatting( | 234 | pub(crate) fn handle_on_type_formatting( |
236 | snap: GlobalStateSnapshot, | 235 | snap: GlobalStateSnapshot, |
237 | params: lsp_types::DocumentOnTypeFormattingParams, | 236 | params: lsp_types::DocumentOnTypeFormattingParams, |