Merge pull request #18993 from ChayimFriedman2/iter-config

feat: Provide a config to control auto-insertion of `await` and `iter()`
This commit is contained in:
Lukas Wirth 2025-01-24 13:31:30 +00:00 committed by GitHub
commit 1329e6be49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 111 additions and 56 deletions

View file

@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
item.detail("expr.await"); item.detail("expr.await");
item.add_to(acc, ctx.db); item.add_to(acc, ctx.db);
// Completions that skip `.await`, e.g. `.await.foo()`. if ctx.config.enable_auto_await {
let dot_access_kind = match &dot_access.kind { // Completions that skip `.await`, e.g. `.await.foo()`.
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { let dot_access_kind = match &dot_access.kind {
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
} DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
it @ DotAccessKind::Method { .. } => *it, }
}; it @ DotAccessKind::Method { .. } => *it,
let dot_access = DotAccess { };
receiver: dot_access.receiver.clone(), let dot_access = DotAccess {
receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }), receiver: dot_access.receiver.clone(),
kind: dot_access_kind, receiver_ty: Some(hir::TypeInfo {
ctx: dot_access.ctx, original: future_output.clone(),
}; adjusted: None,
complete_fields( }),
acc, kind: dot_access_kind,
ctx, ctx: dot_access.ctx,
&future_output, };
|acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty), complete_fields(
|acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty), acc,
is_field_access, ctx,
is_method_access_with_parens, &future_output,
); |acc, field, ty| {
complete_methods(ctx, &future_output, &traits_in_scope, |func| { acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None) },
}); |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( complete_fields(
@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
acc.add_method(ctx, dot_access, func, None, None) acc.add_method(ctx, dot_access, func, None, None)
}); });
// FIXME: if ctx.config.enable_auto_iter {
// Checking for the existence of `iter()` is complicated in our setup, because we need to substitute // FIXME:
// its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`. // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
// Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
let iter = receiver_ty // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
.strip_references() let iter = receiver_ty
.add_reference(hir::Mutability::Shared) .strip_references()
.into_iterator_iter(ctx.db) .add_reference(hir::Mutability::Shared)
.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) .into_iterator_iter(ctx.db)
.map(|ty| (ty, SmolStr::new_static("into_iter()"))) .map(|ty| (ty, SmolStr::new_static("iter()")));
}; // Does <receiver_ty as IntoIterator>::IntoIter` exist?
if let Some((iter, iter_sym)) = iter.or_else(into_iter) { let into_iter = || {
// Skip iterators, e.g. complete `.iter().filter_map()`. receiver_ty
let dot_access_kind = match &dot_access.kind { .clone()
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { .into_iterator_iter(ctx.db)
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } .map(|ty| (ty, SmolStr::new_static("into_iter()")))
}
it @ DotAccessKind::Method { .. } => *it,
}; };
let dot_access = DotAccess { if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
receiver: dot_access.receiver.clone(), // Skip iterators, e.g. complete `.iter().filter_map()`.
receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }), let dot_access_kind = match &dot_access.kind {
kind: dot_access_kind, DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
ctx: dot_access.ctx, DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
}; }
complete_methods(ctx, &iter, &traits_in_scope, |func| { it @ DotAccessKind::Method { .. } => *it,
acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None) };
}); 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)
});
}
} }
} }

View file

@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
pub enable_postfix_completions: bool, pub enable_postfix_completions: bool,
pub enable_imports_on_the_fly: bool, pub enable_imports_on_the_fly: bool,
pub enable_self_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_private_editable: bool,
pub enable_term_search: bool, pub enable_term_search: bool,
pub term_search_fuel: u64, pub term_search_fuel: u64,

View file

@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
fields_to_resolve: CompletionFieldsToResolve::empty(), fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![], exclude_flyimport: vec![],
exclude_traits: &[], exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
}; };
pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {

View file

@ -453,6 +453,10 @@ config_data! {
/// ///
/// In `match` arms it completes a comma instead. /// In `match` arms it completes a comma instead.
completion_addSemicolonToUnit: bool = true, 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. /// 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. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
completion_autoimport_enable: bool = true, completion_autoimport_enable: bool = true,
@ -1484,6 +1488,8 @@ impl Config {
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned() enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
&& self.caps.completion_item_edit_resolve(), && self.caps.completion_item_edit_resolve(),
enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(), 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(), enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
full_function_signatures: self full_function_signatures: self
.completion_fullFunctionSignatures_enable(source_root) .completion_fullFunctionSignatures_enable(source_root)

View file

@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(), fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![], exclude_flyimport: vec![],
exclude_traits: &[], exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
}; };
let position = let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(), fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![], exclude_flyimport: vec![],
exclude_traits: &[], exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
}; };
let position = let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(), fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![], exclude_flyimport: vec![],
exclude_traits: &[], exclude_traits: &[],
enable_auto_await: true,
enable_auto_iter: true,
}; };
let position = let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };

View file

@ -274,6 +274,16 @@ Whether to automatically add a semicolon when completing unit-returning function
In `match` arms it completes a comma instead. 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`):: [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
+ +
-- --

View file

@ -1143,6 +1143,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", "title": "completion",
"properties": { "properties": {