From 2a89e4a0515e965fd5cf3a5c21260f0763886331 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 15 Jan 2025 09:46:48 +0100 Subject: [PATCH 1/2] Early exit in search properly --- crates/hir/src/semantics.rs | 2 +- crates/ide-db/src/search.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index a1a596675bac..41ec7f3e7a45 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1756,7 +1756,7 @@ impl<'db> SemanticsImpl<'db> { let file_id = self.lookup(&root_node).unwrap_or_else(|| { panic!( "\n\nFailed to lookup {:?} in this Semantics.\n\ - Make sure to use only query nodes, derived from this instance of Semantics.\n\ + Make sure to only query nodes derived from this instance of Semantics.\n\ root node: {:?}\n\ known nodes: {}\n\n", node, diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 68199dd87118..a75aba137be6 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -953,14 +953,19 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the items name for offset in Self::match_indices(&text, finder, search_range) { - tree.token_at_offset(offset).for_each(|token| { - let Some(str_token) = ast::String::cast(token.clone()) else { return }; + let ret = tree.token_at_offset(offset).any(|token| { + let Some(str_token) = ast::String::cast(token.clone()) else { return false }; if let Some((range, Some(nameres))) = sema.check_for_format_args_template(token, offset) { - if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {} + return self + .found_format_args_ref(file_id, range, str_token, nameres, sink); } + false }); + if ret { + return; + } for name in Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast) From 557c467aa9f0b738d171a0a02de9fd78704acf37 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 15 Jan 2025 09:46:48 +0100 Subject: [PATCH 2/2] Flip on typing config to be opt-in, better defaults --- crates/ide/src/lib.rs | 6 ------ crates/rust-analyzer/src/config.rs | 16 ++++++++++++---- crates/rust-analyzer/src/handlers/request.rs | 17 ++++++----------- docs/user/generated_config.adoc | 16 ++++++++++++---- editors/code/package.json | 6 +++--- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 043e8542154a..346e2862b0fd 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -404,17 +404,11 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if let Some(chars_to_exclude) = chars_to_exclude { - if chars_to_exclude.contains(char_typed) { - return Ok(None); - } - } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 72d021db5a82..9d8dbfc7a48c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -326,8 +326,16 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. - typing_excludeChars: Option = Some("|<".to_owned()), + /// Specify the characters allowed to invoke special on typing triggers. + /// - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression + /// - typing `=` between two expressions adds `;` when in statement position + /// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position + /// - typing `.` in a chain method call auto-indents + /// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression + /// - typing `{` in a use item adds a closing `}` in the right place + /// - typing `>` to complete a return type `->` will insert a whitespace after it + /// - typing `<` in a path or type position inserts a closing `>` after the path or type. + typing_triggerChars: Option = Some("=.".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -2251,8 +2259,8 @@ impl Config { } } - pub fn typing_exclude_chars(&self) -> Option { - self.typing_excludeChars().clone() + pub fn typing_trigger_chars(&self) -> &str { + self.typing_triggerChars().as_deref().unwrap_or_default() } // VSCode is our reference implementation, so we allow ourselves to work around issues by diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index d01dc5fba1f7..190015d7faad 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -434,29 +434,24 @@ pub(crate) fn handle_on_type_formatting( params: lsp_types::DocumentOnTypeFormattingParams, ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_on_type_formatting").entered(); + let char_typed = params.ch.chars().next().unwrap_or('\0'); + if !snap.config.typing_trigger_chars().contains(char_typed) { + return Ok(None); + } + let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.file_line_index(position.file_id)?; // in `ide`, the `on_type` invariant is that // `text.char_at(position) == typed_char`. position.offset -= TextSize::of('.'); - let char_typed = params.ch.chars().next().unwrap_or('\0'); let text = snap.analysis.file_text(position.file_id)?; if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) { return Ok(None); } - // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, - // but it requires precise cursor positioning to work, and one can't - // position the cursor with on_type formatting. So, let's just toggle this - // feature off here, hoping that we'll enable it one day, 😿. - if char_typed == '>' { - return Ok(None); - } - let chars_to_exclude = snap.config.typing_exclude_chars(); - - let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; + let edit = snap.analysis.on_char_typed(position, char_typed)?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 45eb38cd4f8d..2b518e060988 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -1051,10 +1051,18 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`):: -+ --- -Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. +[[rust-analyzer.typing.triggerChars]]rust-analyzer.typing.triggerChars (default: `"=."`):: ++ +-- +Specify the characters allowed to invoke special on typing triggers. +- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression +- typing `=` between two expressions adds `;` when in statement position +- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position +- typing `.` in a chain method call auto-indents +- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression +- typing `{` in a use item adds a closing `}` in the right place +- typing `>` to complete a return type `->` will insert a whitespace after it +- typing `<` in a path or type position inserts a closing `>` after the path or type. -- [[rust-analyzer.vfs.extraIncludes]]rust-analyzer.vfs.extraIncludes (default: `[]`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 8da17e7a0a34..48e29a7fe289 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2745,9 +2745,9 @@ { "title": "typing", "properties": { - "rust-analyzer.typing.excludeChars": { - "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", - "default": "|<", + "rust-analyzer.typing.triggerChars": { + "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", + "default": "=.", "type": [ "null", "string"