New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add implementation of extract struct from enum variant #4576
Conversation
|
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
|
||
{}"#, | ||
visibility_string, | ||
variant_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a field_list
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, field list is below, I decompose variant into field list and variant name and in field list I add pub modifiers
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
@matklad Hi! Is it ok to go or should I change something/implement differently? Thanks! |
Ok, I finally got to looking into this! I like it! It's also the first transformation which is done properly, by collecting usages and fixing them up. Though, this awesomeness is exactly what makes me take a pause here... At the moment, we eagerly compute all the assists. That means, that, if you just place the cursor on an enum, we'll kick the search, which I feel might be bad from performance and stability perspective ("find usages" tend to surface latent bugs really quick). So, I have two proposals here:
The second option (which is more interesting) shouldnt' be too hard, but it'll be fiddly, as it requires some client-side tweaks as well. Basically, we'll need to add |
To be less confusing, the lazy-computation is already fully implemented internally, it's just not threaded through to the client, as LSP currently lacks this ability (which is a shame). |
There should definitely be a We could do this lazily though by using a |
It definitely makes sense to do it lazily. Though just to be sure want to clarify the approach. As far as I understand we need enable the author of each respective assists to decide whether he/she wants to provide an edit right away or (if it is expensive) to issue a command Now we would probably need to change that, so the variable Is my understanding correct or am I missing something? |
I guess this is theoretically best solution, but I think it makes sense to start with (and 70% sure that it also makes sense to end with) just making all assists lazy unconditionally. |
Hi! Created a first version of the changes, not sure if had done it the right way though. So what I did is I created an experimental feature Then each time we get the response for Also right now we are calling |
@matklad Friendly ping :-) There are a lot of changes and I am afraid that if this would pile up, I would have to merge/rebase again. Thanks! |
Yeah, sorry, we are in the process of organizing the review process :) I'll look into this later today, but the main thing is that I think it makes sense to split protocol changes into a separate PR. |
Cool, if it is ok, after your review, I will make a separate PR and also will address the changes you think are necessary. |
cc microsoft/language-server-protocol#1008 (comment) for the general discussion of the "resolve" pattern LSP should have had :-) |
It seems that I've done this accordingly, the only thing which is different and should be changed is that we need to provide |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, protocol changes look good to me, let's split them into a separate PR though.
I haven't looked into the actual assist though, at the moment, I am slighlty worried with AsName
reexport, we shouldn't be doing that (which is not really explained anywhere yet....)
crates/rust-analyzer/src/config.rs
Outdated
|
||
let resolve_code_action = | ||
experimental.get("resolveCodeAction").and_then(|it| it.as_bool()) == Some(true); | ||
self.client_caps.resolve_code_action = resolve_code_action |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.client_caps.resolve_code_action = resolve_code_action | |
self.client_caps.resolve_code_action = resolve_code_action; |
crates/ra_ide/src/lib.rs
Outdated
@@ -147,7 +147,7 @@ pub struct Assist { | |||
pub id: AssistId, | |||
pub label: String, | |||
pub group_label: Option<String>, | |||
pub source_change: SourceChange, | |||
pub source_change: Option<SourceChange>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to split SourceChange
out of this struct completely. Than, I think we should be able to just pub use ra_assists::Assist
instead of defining a mirrored struct.
crates/ra_ide/src/lib.rs
Outdated
self.with_db(|db| { | ||
ra_assists::Assist::resolved(db, config, frange) | ||
.into_iter() | ||
.map(|assist| Assist { | ||
id: assist.assist.id, | ||
label: assist.assist.label, | ||
group_label: assist.assist.group.map(|it| it.0), | ||
source_change: assist.source_change, | ||
source_change: Some(assist.source_change), | ||
}) | ||
.collect() | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signatures of these two methods should be -> Cancelable<Vec<Assist>>
and -> Cancelable<Vec<ResolvedAssist>>
crates/rust-analyzer/src/lsp_ext.rs
Outdated
#[serde(rename_all = "camelCase")] | ||
pub struct ResolveCodeActionParams { | ||
pub code_action_params: lsp_types::CodeActionParams, | ||
pub label: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, we should use id
and not the label
. The motivation for this is that (long term) we should be able to select the correct assist by id, without checking even availability.
Ie, label is a custom text which might be influenced by code at the cursor, while ID is known statically.
There might be a sligthly complication in that, with group assists, I think there might be two assits with the same ID (ie, two imports for different types). In this case, I think we should keep id
as a string, but concat an :<number>
on the LSP layer for diambiguation.
crates/rust-analyzer/src/lsp_ext.rs
Outdated
@@ -98,6 +98,22 @@ pub struct JoinLinesParams { | |||
pub ranges: Vec<Range>, | |||
} | |||
|
|||
pub enum ResolveCodeActionRequest {} | |||
|
|||
impl Request for ResolveCodeActionRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also add docs for this to https://github.com/rust-analyzer/rust-analyzer/blob/21132a7a748a70351f5d1ae6d8c51a3a0065013e/docs/dev/lsp-extensions.md?
Also cc https://github.com/rust-analyzer/rust-analyzer/pull/4703/files about the general review process. This PR is actually a great case study, because it hits this "expanding API" case. |
@matklad In the process of making the PR I encountered several questions subject to discussion:
|
f15708c
to
a6d3c77
Compare
@matklad Seems also finished this one, can we merge now, or there is still some things to be checked? Thanks! |
Removed |
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
Outdated
Show resolved
Hide resolved
@matklad Comments resolved :-) |
Hi! Just wondering if any more work needed here? |
bors r+ Seems like a good start! I think we also wan to extend this to handle named structs. And it seems like the whole "search & modify" infrastracture can become, well, and infrastructure somewhere in |
Hi guys! I implemented the extraction functionality including modifying multiple files. The only thing I didn't change the cursor position. I've done it with a previous API, but now snippets have been introduced and I need to figure out how to do it.
Please bear in mind that I am a newcomer in the rust-analyzer (and also Rust) world, so I tried to implement the feature to the best of my knowledge, but the API is very new to me, so I am very welcome to introducing changes etc.