Unnamed repository; edit this file 'description' to name the repository.
Provide a config to control auto-insertion of `await` and `iter()`
Chayim Refael Friedman 2025-01-21
parent 2c040c0 · commit 47f4f3f
-rw-r--r--crates/ide-completion/src/completions/dot.rs121
-rw-r--r--crates/ide-completion/src/config.rs2
-rw-r--r--crates/ide-completion/src/tests.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs6
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs6
-rw-r--r--docs/user/generated_config.adoc10
-rw-r--r--editors/code/package.json20
7 files changed, 111 insertions, 56 deletions
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 7679d9076d..0d1765a7b7 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
item.detail("expr.await");
item.add_to(acc, ctx.db);
- // Completions that skip `.await`, e.g. `.await.foo()`.
- let dot_access_kind = match &dot_access.kind {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
- }
- it @ DotAccessKind::Method { .. } => *it,
- };
- let dot_access = DotAccess {
- receiver: dot_access.receiver.clone(),
- receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
- kind: dot_access_kind,
- ctx: dot_access.ctx,
- };
- complete_fields(
- acc,
- ctx,
- &future_output,
- |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
- |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
- is_field_access,
- is_method_access_with_parens,
- );
- complete_methods(ctx, &future_output, &traits_in_scope, |func| {
- acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
- });
+ if ctx.config.enable_auto_await {
+ // Completions that skip `.await`, e.g. `.await.foo()`.
+ let dot_access_kind = match &dot_access.kind {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+ }
+ it @ DotAccessKind::Method { .. } => *it,
+ };
+ let dot_access = DotAccess {
+ receiver: dot_access.receiver.clone(),
+ receiver_ty: Some(hir::TypeInfo {
+ original: future_output.clone(),
+ adjusted: None,
+ }),
+ kind: dot_access_kind,
+ ctx: dot_access.ctx,
+ };
+ complete_fields(
+ acc,
+ ctx,
+ &future_output,
+ |acc, field, ty| {
+ acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
+ },
+ |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
+ is_field_access,
+ is_method_access_with_parens,
+ );
+ complete_methods(ctx, &future_output, &traits_in_scope, |func| {
+ acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
+ });
+ }
}
complete_fields(
@@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
acc.add_method(ctx, dot_access, func, None, None)
});
- // FIXME:
- // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
- // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
- // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
- let iter = receiver_ty
- .strip_references()
- .add_reference(hir::Mutability::Shared)
- .into_iterator_iter(ctx.db)
- .map(|ty| (ty, SmolStr::new_static("iter()")));
- // Does <receiver_ty as IntoIterator>::IntoIter` exist?
- let into_iter = || {
- receiver_ty
- .clone()
+ if ctx.config.enable_auto_iter {
+ // FIXME:
+ // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
+ // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
+ // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
+ let iter = receiver_ty
+ .strip_references()
+ .add_reference(hir::Mutability::Shared)
.into_iterator_iter(ctx.db)
- .map(|ty| (ty, SmolStr::new_static("into_iter()")))
- };
- if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
- // Skip iterators, e.g. complete `.iter().filter_map()`.
- let dot_access_kind = match &dot_access.kind {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
- }
- it @ DotAccessKind::Method { .. } => *it,
+ .map(|ty| (ty, SmolStr::new_static("iter()")));
+ // Does <receiver_ty as IntoIterator>::IntoIter` exist?
+ let into_iter = || {
+ receiver_ty
+ .clone()
+ .into_iterator_iter(ctx.db)
+ .map(|ty| (ty, SmolStr::new_static("into_iter()")))
};
- let dot_access = DotAccess {
- receiver: dot_access.receiver.clone(),
- receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
- kind: dot_access_kind,
- ctx: dot_access.ctx,
- };
- complete_methods(ctx, &iter, &traits_in_scope, |func| {
- acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
- });
+ if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
+ // Skip iterators, e.g. complete `.iter().filter_map()`.
+ let dot_access_kind = match &dot_access.kind {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+ }
+ it @ DotAccessKind::Method { .. } => *it,
+ };
+ let dot_access = DotAccess {
+ receiver: dot_access.receiver.clone(),
+ receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
+ kind: dot_access_kind,
+ ctx: dot_access.ctx,
+ };
+ complete_methods(ctx, &iter, &traits_in_scope, |func| {
+ acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
+ });
+ }
}
}
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index 8b1ce11e8a..c641df38ff 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
pub enable_postfix_completions: bool,
pub enable_imports_on_the_fly: bool,
pub enable_self_on_the_fly: bool,
+ pub enable_auto_iter: bool,
+ pub enable_auto_await: bool,
pub enable_private_editable: bool,
pub enable_term_search: bool,
pub term_search_fuel: u64,
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index b7dbf0a630..9d91f95eb6 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3dc4379258..44325fa1a2 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -453,6 +453,10 @@ config_data! {
///
/// In `match` arms it completes a comma instead.
completion_addSemicolonToUnit: bool = true,
+ /// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+ completion_autoAwait_enable: bool = true,
+ /// Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+ completion_autoIter_enable: bool = true,
/// Toggles the additional completions that automatically add imports when completed.
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
completion_autoimport_enable: bool = true,
@@ -1484,6 +1488,8 @@ impl Config {
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
&& self.caps.completion_item_edit_resolve(),
enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
+ enable_auto_iter: *self.completion_autoIter_enable(source_root),
+ enable_auto_await: *self.completion_autoAwait_enable(source_root),
enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
full_function_signatures: self
.completion_fullFunctionSignatures_enable(source_root)
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index fcfd06679b..5cdc51a1c1 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index bd091db58d..b33de1956b 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -274,6 +274,16 @@ Whether to automatically add a semicolon when completing unit-returning function
In `match` arms it completes a comma instead.
--
+[[rust-analyzer.completion.autoAwait.enable]]rust-analyzer.completion.autoAwait.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+--
+[[rust-analyzer.completion.autoIter.enable]]rust-analyzer.completion.autoIter.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+--
[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
+
--
diff --git a/editors/code/package.json b/editors/code/package.json
index 8b066377f2..f148041ac3 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1146,6 +1146,26 @@
{
"title": "completion",
"properties": {
+ "rust-analyzer.completion.autoAwait.enable": {
+ "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.",
+ "default": true,
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "title": "completion",
+ "properties": {
+ "rust-analyzer.completion.autoIter.enable": {
+ "markdownDescription": "Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.",
+ "default": true,
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "title": "completion",
+ "properties": {
"rust-analyzer.completion.autoimport.enable": {
"markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
"default": true,