Description
In #11397 I started refactoring the completions crate a bit and I haven't gotten back to finishing this up, so the crate is in a weird state where we use 3 differnt things to determine where certain completions apply. So with this I'll write down what I had in mind and where we are currently at in regards to that plan.
Completions are generated by fist calculating a CompletionContext
which analyzes the surrounding context of the cursor position which we can then derive the completions from. Following that we just execute a bunch of functions that fill the completions accumulator with completions.
rust-analyzer/crates/ide-completion/src/lib.rs
Lines 150 to 173 in 0ee4e6a
The here was to have a function calculating completions for a specific "thing", this "thing" varies widely as to what it applies though. My goal with the refactor was to make this "thing" more consistent in what it covers.
We can group the things we actually complete into roughly the following:
- keywords
Name
sLifetime
sNameRef
s (paths and a few exceptios)- snippets
- very specialized things (string literals, fmt strings, ...)
Obviously grouping the completion generation by just these is too rough, we want to do it differently. Completing by Name
s and NameRef
s alone is messy, as we need to know about the context of where we are completing in (are we inside a type position, expression position, function return type, etc...), but this is what we kind of are doing right now if you take a look at the unqualified path module or the qualfied path module (these are practically the NameRef
case). There are a bunch of different checks regarding where we are currently at placed around at various places making the code a mess.
So what I instead envision is for us to split these modules apart according to their position they apply to, with branches for the different thinsg that can be completed there (with a few exceptions for special completions). I've started with this for paths, where I have split out attributes, visibility paths, use paths and pattern paths.
This structure allows one to more easily reason about what completions apply where.
This refactor should get us closer to do "perfect completions".
I'll fully fill out the list of finer grained tasks here later this week:
- Split apart [unqualfied path]https://github.com/rust-lang/rust-analyzer/blob/0ee4e6a22d79f58b6b459dbc874d6b90a4495d83/crates/ide-completion/src/completions/unqualified_path.rs) and qualfied path into the remaining variants
- Expressions / Statements
- Type
- Derive
- Attribute
- Visibility
- Pattern
- Use
- ItemList / AssocItemList (module and sourcefile / trait and impl, macro calls can appear there)
- Split up keyword module
- Implement proper keyword completions for items, respecting their order and similar. That is in
unsafe const $0
we should only proposefn
, notconst
orunsafe
again.
- Implement proper keyword completions for items, respecting their order and similar. That is in
- Properly handle completions in generic argument position, currently its offered via type path completions with some special cases...
- Split flyimport into the corresponding modules, this should probably be done last. We need to verify that the modules doing flyimport are disjoint so we don't do this multiple times.
- Remove
is_path_disallowed
and otherCompletionContext
functions that look like temporary hacks.