Skip to content

Allow LSP code action requests to set the (new) AllowGenerateInHiddenCode option#66917

Closed
davidwengier wants to merge 10 commits intodotnet:mainfrom
davidwengier:CodeActionsInHiddenCode
Closed

Allow LSP code action requests to set the (new) AllowGenerateInHiddenCode option#66917
davidwengier wants to merge 10 commits intodotnet:mainfrom
davidwengier:CodeActionsInHiddenCode

Conversation

@davidwengier
Copy link
Member

@davidwengier davidwengier commented Feb 16, 2023

More background work for dotnet/razor#8204

I've talked to all of you about this, so hopefully this matches your expectations.

It is intentional, for now, that only one of the actual code fixes honour the new setting. I figured going for a slow rollout makes sense, and given its triggered by LSP we don't need to worry about dual insertion nonsense to expand support on the Roslyn sign once Razor is capable enough.

@davidwengier davidwengier requested a review from a team as a code owner February 16, 2023 04:00
@ghost ghost added the Area-IDE label Feb 16, 2023
@davidwengier
Copy link
Member Author

davidwengier commented Feb 16, 2023

Warning: Need to add this ability (to set options) to CodeActionResolve too, because the first thing it does is compute code actions again :( At least there we have CodeActionResolveData I can probably abuse :)

@tmat
Copy link
Member

tmat commented Feb 16, 2023

Could you point to code that sets the option value on an instance of CodeGenerationOptions?

@CyrusNajmabadi
Copy link
Contributor

I'm going to wait on Tomas being ok before looking :)

Copy link
Member

@dibarbet dibarbet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lsp side mostly looks fine to me

Contract.ThrowIfNull(document);

var options = _globalOptions.GetCodeActionOptionsProvider();
var options = new LSPCodeActionOptionsProvider(request.AllowGenerateInHiddenCode, _globalOptions.GetCodeActionOptionsProvider());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget - why do we need a provider here instead of passing in the actual CodeActionOptions? Probably a question for @tmat

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was surprised to find it wasn't a CodeActionOptions myself, though to be honest I'm not sure I would have known how to override the value if it was, so I wasn't unhappy :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably because we call to some code that potentially operates on any document/project in the solution and might need options for a different language than the language of the current document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a test for that scenario.

@davidwengier
Copy link
Member Author

Could you point to code that sets the option value on an instance of CodeGenerationOptions?

For an LSP request the value is set by wrapping the options provider:
https://github.com/dotnet/roslyn/pull/66917/files#diff-93009ab52d3bb3062b613014e84528202206753601dee250968bd7f2dbbbcb22R91

Otherwise the CodeGenerationOptions constructor sets it from the fallbackOptions, which is what makes document.GetCodeGenerationOptionsAsync work, here:
https://github.com/dotnet/roslyn/pull/66917/files#diff-00c9880ecd7bbcfd5d3747b2aaa5c9756260052c0eab6d1a886edaf342250689R40

@davidwengier
Copy link
Member Author

davidwengier commented Feb 17, 2023

On second thought, I think we might need a different approach here. I think we need to do what AddImportPlacementOptions.AllowInHiddenRegions, or perhaps move it to CodeGenerationOptions and reuse it, because this does need to depend on the document in question. Unfortunately it also depends on the request coming from the Razor LSP client. So we need a document based property to know whether to honour the CodeGenerationOptions property :(

The problem is if we have a Foo.razor file and a Goo.cs file that had hidden regions in it, then currently this change will mean code actions requested from Foo.razor will offer to generate in hidden regions of Goo.cs, which we don't want. If we just use the document properties service approach though, code actions requested from Goo.cs will offer to generate in Foo.razor[.g.cs], but nothing will be processing the result of the code action request to actual make those edits valid.

The question is how to tell the document is a razor document. We could add something to DocumentPropertiesService for AllowGenerateInHidden, but I thought we wanted to remove that. We could do what AddImportPlacementOptions.AllowInHiddenRegions does, which is check for a span mapping service, which is disingenuous since its not the span mapping service that will be doing the work here. Or we could do something else. Make AllowGenerateInHiddenCode take a filename pattern? 🤮

Thoughts?

Do we even care about hidden regions for non-asp.net files? As far as I understand from the code comments, thats what it was added for. I would be surprised if people were manually creating them, and were happy not getting code generation offered. Also worth mentioning that we'll eventually be switching to using the razor source generator documents instead of IDynamicFile so all of the document services and document properties bits would need to be replaced with something else anyway.

@tmat
Copy link
Member

tmat commented Feb 17, 2023

we'll eventually be switching to using the razor source generator documents instead of IDynamicFile so all of the document services and document properties bits would need to be replaced with something else anyway.

Right, so that's what troubles me about adding more document services based approach.

It seems like we need to rethink how code actions for Razor should be architected rather than just adding one-off flag.

@davidwengier
Copy link
Member Author

It seems like we need to rethink how code actions for Razor should be architected

I don't disagree, but I also don't want to block this forever. Even if we consider this a temporary hacky fix, it unblocks Generate Method for razor users, and that's the 3rd most used code action in C#. I guess I'll set up a meeting and we can talk about it more.

@davidwengier
Copy link
Member Author

Random thought/realisation: If we separate "Generate Method" and "Generate Method into a different document" into two code fixes, then Razor could just allow-list the former, and this PR would be sufficient. The latter would then be unblocked by the more elaborate re-architecting that we're talking about.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants