Skip to content

Commit

Permalink
Merge pull request #18993 from ChayimFriedman2/iter-config
Browse files Browse the repository at this point in the history
feat: Provide a config to control auto-insertion of `await` and `iter()`
  • Loading branch information
Veykril authored Jan 24, 2025
2 parents 8acea50 + 47f4f3f commit 1329e6b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 56 deletions.
121 changes: 65 additions & 56 deletions crates/ide-completion/src/completions/dot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
});
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/ide-completion/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions crates/ide-completion/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions crates/rust-analyzer/src/integrated_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() };
Expand Down Expand Up @@ -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() };
Expand Down Expand Up @@ -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() };
Expand Down
10 changes: 10 additions & 0 deletions docs/user/generated_config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`)::
+
--
Expand Down
20 changes: 20 additions & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
"properties": {
Expand Down

0 comments on commit 1329e6b

Please sign in to comment.