Skip to content

Commit 5059c1a

Browse files
Provide a config to control auto-insertion of await and iter()
1 parent 4308352 commit 5059c1a

File tree

7 files changed

+111
-56
lines changed

7 files changed

+111
-56
lines changed

src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs

+65-56
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
4242
item.detail("expr.await");
4343
item.add_to(acc, ctx.db);
4444

45-
// Completions that skip `.await`, e.g. `.await.foo()`.
46-
let dot_access_kind = match &dot_access.kind {
47-
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
48-
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
49-
}
50-
it @ DotAccessKind::Method { .. } => *it,
51-
};
52-
let dot_access = DotAccess {
53-
receiver: dot_access.receiver.clone(),
54-
receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
55-
kind: dot_access_kind,
56-
ctx: dot_access.ctx,
57-
};
58-
complete_fields(
59-
acc,
60-
ctx,
61-
&future_output,
62-
|acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
63-
|acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
64-
is_field_access,
65-
is_method_access_with_parens,
66-
);
67-
complete_methods(ctx, &future_output, &traits_in_scope, |func| {
68-
acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
69-
});
45+
if ctx.config.enable_auto_await {
46+
// Completions that skip `.await`, e.g. `.await.foo()`.
47+
let dot_access_kind = match &dot_access.kind {
48+
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
49+
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
50+
}
51+
it @ DotAccessKind::Method { .. } => *it,
52+
};
53+
let dot_access = DotAccess {
54+
receiver: dot_access.receiver.clone(),
55+
receiver_ty: Some(hir::TypeInfo {
56+
original: future_output.clone(),
57+
adjusted: None,
58+
}),
59+
kind: dot_access_kind,
60+
ctx: dot_access.ctx,
61+
};
62+
complete_fields(
63+
acc,
64+
ctx,
65+
&future_output,
66+
|acc, field, ty| {
67+
acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
68+
},
69+
|acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
70+
is_field_access,
71+
is_method_access_with_parens,
72+
);
73+
complete_methods(ctx, &future_output, &traits_in_scope, |func| {
74+
acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
75+
});
76+
}
7077
}
7178

7279
complete_fields(
@@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
8289
acc.add_method(ctx, dot_access, func, None, None)
8390
});
8491

85-
// FIXME:
86-
// Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
87-
// its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
88-
// Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
89-
let iter = receiver_ty
90-
.strip_references()
91-
.add_reference(hir::Mutability::Shared)
92-
.into_iterator_iter(ctx.db)
93-
.map(|ty| (ty, SmolStr::new_static("iter()")));
94-
// Does <receiver_ty as IntoIterator>::IntoIter` exist?
95-
let into_iter = || {
96-
receiver_ty
97-
.clone()
92+
if ctx.config.enable_auto_iter {
93+
// FIXME:
94+
// Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
95+
// its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
96+
// Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
97+
let iter = receiver_ty
98+
.strip_references()
99+
.add_reference(hir::Mutability::Shared)
98100
.into_iterator_iter(ctx.db)
99-
.map(|ty| (ty, SmolStr::new_static("into_iter()")))
100-
};
101-
if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
102-
// Skip iterators, e.g. complete `.iter().filter_map()`.
103-
let dot_access_kind = match &dot_access.kind {
104-
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
105-
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
106-
}
107-
it @ DotAccessKind::Method { .. } => *it,
101+
.map(|ty| (ty, SmolStr::new_static("iter()")));
102+
// Does <receiver_ty as IntoIterator>::IntoIter` exist?
103+
let into_iter = || {
104+
receiver_ty
105+
.clone()
106+
.into_iterator_iter(ctx.db)
107+
.map(|ty| (ty, SmolStr::new_static("into_iter()")))
108108
};
109-
let dot_access = DotAccess {
110-
receiver: dot_access.receiver.clone(),
111-
receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
112-
kind: dot_access_kind,
113-
ctx: dot_access.ctx,
114-
};
115-
complete_methods(ctx, &iter, &traits_in_scope, |func| {
116-
acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
117-
});
109+
if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
110+
// Skip iterators, e.g. complete `.iter().filter_map()`.
111+
let dot_access_kind = match &dot_access.kind {
112+
DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
113+
DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
114+
}
115+
it @ DotAccessKind::Method { .. } => *it,
116+
};
117+
let dot_access = DotAccess {
118+
receiver: dot_access.receiver.clone(),
119+
receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
120+
kind: dot_access_kind,
121+
ctx: dot_access.ctx,
122+
};
123+
complete_methods(ctx, &iter, &traits_in_scope, |func| {
124+
acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
125+
});
126+
}
118127
}
119128
}
120129

src/tools/rust-analyzer/crates/ide-completion/src/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
1414
pub enable_postfix_completions: bool,
1515
pub enable_imports_on_the_fly: bool,
1616
pub enable_self_on_the_fly: bool,
17+
pub enable_auto_iter: bool,
18+
pub enable_auto_await: bool,
1719
pub enable_private_editable: bool,
1820
pub enable_term_search: bool,
1921
pub term_search_fuel: u64,

src/tools/rust-analyzer/crates/ide-completion/src/tests.rs

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
8787
fields_to_resolve: CompletionFieldsToResolve::empty(),
8888
exclude_flyimport: vec![],
8989
exclude_traits: &[],
90+
enable_auto_await: true,
91+
enable_auto_iter: true,
9092
};
9193

9294
pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {

src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ config_data! {
453453
///
454454
/// In `match` arms it completes a comma instead.
455455
completion_addSemicolonToUnit: bool = true,
456+
/// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
457+
completion_autoAwait_enable: bool = true,
458+
/// 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.
459+
completion_autoIter_enable: bool = true,
456460
/// Toggles the additional completions that automatically add imports when completed.
457461
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
458462
completion_autoimport_enable: bool = true,
@@ -1484,6 +1488,8 @@ impl Config {
14841488
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
14851489
&& self.caps.completion_item_edit_resolve(),
14861490
enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
1491+
enable_auto_iter: *self.completion_autoIter_enable(source_root),
1492+
enable_auto_await: *self.completion_autoAwait_enable(source_root),
14871493
enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
14881494
full_function_signatures: self
14891495
.completion_fullFunctionSignatures_enable(source_root)

src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs

+6
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
176176
fields_to_resolve: CompletionFieldsToResolve::empty(),
177177
exclude_flyimport: vec![],
178178
exclude_traits: &[],
179+
enable_auto_await: true,
180+
enable_auto_iter: true,
179181
};
180182
let position =
181183
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
226228
fields_to_resolve: CompletionFieldsToResolve::empty(),
227229
exclude_flyimport: vec![],
228230
exclude_traits: &[],
231+
enable_auto_await: true,
232+
enable_auto_iter: true,
229233
};
230234
let position =
231235
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
274278
fields_to_resolve: CompletionFieldsToResolve::empty(),
275279
exclude_flyimport: vec![],
276280
exclude_traits: &[],
281+
enable_auto_await: true,
282+
enable_auto_iter: true,
277283
};
278284
let position =
279285
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };

src/tools/rust-analyzer/docs/user/generated_config.adoc

+10
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,16 @@ Whether to automatically add a semicolon when completing unit-returning function
274274

275275
In `match` arms it completes a comma instead.
276276
--
277+
[[rust-analyzer.completion.autoAwait.enable]]rust-analyzer.completion.autoAwait.enable (default: `true`)::
278+
+
279+
--
280+
Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
281+
--
282+
[[rust-analyzer.completion.autoIter.enable]]rust-analyzer.completion.autoIter.enable (default: `true`)::
283+
+
284+
--
285+
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.
286+
--
277287
[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
278288
+
279289
--

src/tools/rust-analyzer/editors/code/package.json

+20
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,26 @@
11431143
}
11441144
}
11451145
},
1146+
{
1147+
"title": "completion",
1148+
"properties": {
1149+
"rust-analyzer.completion.autoAwait.enable": {
1150+
"markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.",
1151+
"default": true,
1152+
"type": "boolean"
1153+
}
1154+
}
1155+
},
1156+
{
1157+
"title": "completion",
1158+
"properties": {
1159+
"rust-analyzer.completion.autoIter.enable": {
1160+
"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.",
1161+
"default": true,
1162+
"type": "boolean"
1163+
}
1164+
}
1165+
},
11461166
{
11471167
"title": "completion",
11481168
"properties": {

0 commit comments

Comments
 (0)