Skip to content
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

Introduce CodeActions #499

Merged

Conversation

chadhietala
Copy link
Contributor

@chadhietala chadhietala commented Dec 15, 2022

What Does This Do?

In practice Glint is language server that translates Ember templates and concepts into TypeScript code that then is typechecked using the off shelf TypeScript typechecker. If there are errors during the checking, text offsets of those errors are translated back into the original text offsets (in Ember templates and concepts) so that the developer can resolve the type errors.

This PR starts to plumb through more capabilities for the Glint language server, specifically we're starting with CodeActions. CodeActions Requests are sent from the client to server to get for fixes for problems in code including type fixes. Since Glint utilizes the underlying TypeScript infrastructure we can leverage it to ask for CodeFixes that can then be applied to Ember code. This PR addresses 3 tricky areas:

  1. The TS Server does not use Language Server Protocol despite that is where LSP originated from so we must convert between ts.CodeFix and lsp.CodeAction
  2. Translation of the fixes must occur before they are applied
  3. We should leverage existing formatters that extension is aware of

This PR sets the ground work for these 3 areas.

Copy link
Member

@dfreeman dfreeman left a comment

Choose a reason for hiding this comment

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

I haven't gone deep into the implementation details yet since it's still WIP, but I've left a few comments/questions about the high level approach here. Thank you so much for taking this on, @chadhietala!

.vscode/launch.json Outdated Show resolved Hide resolved
packages/core/src/common/config-manager.ts Outdated Show resolved Hide resolved
packages/core/src/common/config-manager.ts Outdated Show resolved Hide resolved
packages/core/src/common/document-manager.ts Outdated Show resolved Hide resolved
packages/core/src/common/config-manager.ts Outdated Show resolved Hide resolved
packages/core/src/common/config-manager.ts Outdated Show resolved Hide resolved
@chadhietala chadhietala force-pushed the chietala/ts-lang-server-plumbing branch from 2e1f128 to e64241a Compare January 6, 2023 22:14
@chadhietala chadhietala marked this pull request as ready for review January 6, 2023 22:16
@chadhietala chadhietala force-pushed the chietala/ts-lang-server-plumbing branch 2 times, most recently from 1b6e779 to c9a07b4 Compare January 6, 2023 22:21
@chadhietala
Copy link
Contributor Author

@dfreeman I think this is ready for review now. I ended up removing all the prettier things, simplified the config manager, consolidated the document related stuff.

I wrote smoke tests for all the environments except loose mode. It isn't clear to me if its even possible to correctly apply the text changes due to how transformation works.

Screen.Recording.2023-01-06.at.5.25.57.PM.mov

@dfreeman
Copy link
Member

Great, thank you! I should have time to give this a review tomorrow.

Copy link
Member

@dfreeman dfreeman left a comment

Choose a reason for hiding this comment

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

I wrote smoke tests for all the environments except loose mode. It isn't clear to me if its even possible to correctly apply the text changes due to how transformation works.

Can you say more about what it is that makes actions for loose-mode templates complex? Is it that they're (usually) in a separate file from their backing class?

My uneducated guess would have been that doing things like inserting a {{! @glint-ignore }} would be possible, even if there are reasons that more complex actions like "add missing field bar" may be more difficult to account for.

packages/core/package.json Outdated Show resolved Hide resolved
packages/core/src/common/document-cache.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/binding.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/binding.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/code-action-provider.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/glint-language-server.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/code-action-provider.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/code-action-provider.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/code-action-provider.ts Outdated Show resolved Hide resolved
packages/core/src/language-server/glint-language-server.ts Outdated Show resolved Hide resolved
@dfreeman dfreeman added the enhancement New feature or request label Jan 13, 2023
@dfreeman
Copy link
Member

@chadhietala I want to reiterate that I'm excited to see this land, and I'm super grateful for your work on it! 🙏

If there's anything here you want to talk through, feel free to ping me on Discord as well if that's easier 🙂

@chadhietala chadhietala force-pushed the chietala/ts-lang-server-plumbing branch 8 times, most recently from 1b207a8 to 01b0771 Compare January 14, 2023 16:03
This introduces CodeActions to the GlintLanguageServer. It is
responsible for translating LSP requests into TS lanaguage server
CodeFixActions and then back CodeActions
@chadhietala chadhietala force-pushed the chietala/ts-lang-server-plumbing branch 3 times, most recently from 90b3324 to c361d88 Compare January 14, 2023 16:52
@chadhietala chadhietala force-pushed the chietala/ts-lang-server-plumbing branch from c361d88 to 7789876 Compare January 14, 2023 17:15
Copy link
Contributor Author

@chadhietala chadhietala left a comment

Choose a reason for hiding this comment

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

@dfreeman Sorry for the back and forth on this. I went back over all your comments and I think I've landed pretty close to what you had in mind. I was also able to get loose mode working. I have noted a couple areas that I think require your thoughts.


// The ConfigManager holds TypeScript/JS formating and user preferences.
// It is only needed for the vscode binding
export class ConfigManager {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is now just used for the binding. I noticed that this could be used for completions as well but it would need to be pulled through.


return server.getCodeActions(
textDocument.uri,
type,
CodeActionKind.QuickFix,
Copy link
Contributor Author

@chadhietala chadhietala Jan 15, 2023

Choose a reason for hiding this comment

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

Generally curious about your thoughts here about passing the kind. For the vscode binding we only let QuickFixs requests but I'm trying to balance the fact that you can call getCodeActions programmatically. Since we don't support all codefix types it seems like we need something like this. Over time this can be dynamic.

Copy link
Member

Choose a reason for hiding this comment

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

If I'm reading this right, this means that when the editor sends a request for any kind of code actions, we'll always respond with quickfixes?

You've spent a lot more time thinking about this than I have, so I'm probably missing something, but my kneejerk reaction would be to say it's better to return an empty response for an action request we don't support than to give back something that the editor didn't ask for. Why doesn't the short-circuit you have in the language server already handle this the way we'd want?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dfreeman we solicit to vscode that we will only support QuickFix so we should only get requests we can fulfill. The short circuit is there in the event you're using the server from analyzeProject directly.

Copy link
Member

Choose a reason for hiding this comment

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

If a well-behaved editor will only ever ask us for quickfixes, why do we need to hard-code QuickFix here?

Copy link
Contributor Author

@chadhietala chadhietala Jan 24, 2023

Choose a reason for hiding this comment

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

I spent a day looking as to why context.only is optional and not always passed for CodeFix requests but found nothing. All implementations of language servers that I found (Svelte, Vue), that provide codefixes do a narrowing like:

let kind = '';

if (context.only === undefined) {
  kind = CodeActionKind.QuickFix;
} else if (context.only.includes(CodeActionKind.QuickFix)) {
  kind = CodeActionKind.QuickFix;
}

I can add this if you think it will be clearer.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, that's super helpful context! I think something along those lines would help make it clearer for anyone (read: me in the future when I've forgotten this conversation 😅) who comes along and reads it later

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good. I pushed another commit that does ^ and explains whats going on with context.only

@dfreeman
Copy link
Member

I think once we get #499 (comment) settled this will be ready to go. I should have better availability for a while from here forward, so hopefully we can land this in the next day or two—apologies again for how long it's taken!

@dfreeman dfreeman merged commit 1241b42 into typed-ember:main Jan 25, 2023
@dfreeman
Copy link
Member

🎉 Thank you again for all your hard work here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants