-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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 RefactorTriggerReason #38378
Add RefactorTriggerReason #38378
Conversation
Thanks for the PR! It looks like you've changed the TSServer protocol in some way. Please ensure that any changes here don't break consumers of the current TSServer API. For some extra review, we'll ping @sheetalkamat, @amcasey, @mjbvz, @minestarks for you. Feel free to loop in other consumers/maintainers if necessary |
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 like the idea but have some thoughts on various stylistic points.
src/server/protocol.ts
Outdated
@@ -546,7 +546,15 @@ namespace ts.server.protocol { | |||
command: CommandTypes.GetApplicableRefactors; | |||
arguments: GetApplicableRefactorsRequestArgs; | |||
} | |||
export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs; | |||
export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs & { | |||
triggerReason?: RefactorTriggerReason; |
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 simplest version of this is a boolean, isUserInvoked
. I can see why we might want to be able to generalize that in the future though, so moving to an enum, { Invoked, Speculative }
, seems reasonable - it gives us the option of addressing more nuances in the future. I'm not sure why we'd go more abstract than that though - it seems unlikely we'll need both an enum and an additional payload.
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.
Switching to an enum
export enum RefactorTriggerReason {
Implicit = "implicit",
Invoked = "invoked",
}
seems fine to me. Curious what you think the value of preemptively adding a Speculative
option would be.
@mjbvz is there potential that VSCode might want to send info in addition to the triggerReason
, such as a request for a specific "refactorKind
"?
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.
My Speculative
is your Implicit
. I'm fine with your name.
tests/cases/fourslash/refactorConvertImport_partialSelection.ts
Outdated
Show resolved
Hide resolved
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.
Server protocol changes look good to me
This reverts commit e28d8a0.
889f270
to
ca58c0e
Compare
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.
LGTM modulo some minor naming comments.
I didn't review the expanded ranges carefully (let me know if that's something you're worried about) but the new tests don't obviously cover the newly supported regions.
@@ -104,12 +104,13 @@ namespace ts.codefix { | |||
return modifierFlags; | |||
} | |||
|
|||
export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, start: number, end: number): Info | undefined { | |||
export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, start: number, end: number, userRequested = true): Info | undefined { |
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 find this a little confusing since the default elsewhere is implicit.
@@ -70,10 +70,12 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { | |||
return { renameFilename: undefined, renameLocation: undefined, edits }; | |||
} | |||
|
|||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number): Info | undefined { | |||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, userRequested = true): Info | undefined { |
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 can see the convenience of having this be called userRequested
in all the different refactorings, but, personally, I think it would be clearer to give it a name that's specific to each function you've added it to. For example, in this case, the parameter could be called something like considerFunctionBodies
- that would be more meaningful both within the function and at the call-sites that aren't part of a flow that can be either implicit or user-requested. As a bonus, it would also address my comment above, that this parameter defaults to explicit, whereas the ones in the protocol default to implicit.
const { file, startPosition } = context; | ||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition); | ||
const { file, startPosition, triggerReason } = context; | ||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition, triggerReason === "invoked"); |
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.
Unfortunately, JS doesn't have named arguments. Instead, when we're passing a boolean, we tend to give the parameter name as a /*comment*/
before the argument (unless the boolean already has a descriptive name, of course).
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.
It wasn't my intention to pass a named argument, but to pass whatever triggerReason === "invoked"
evaluates to (false
if triggerReason
is "implicit"
or undefined
. Did I do that incorrectly?
Adds
RefactorTriggerReason
proposed in #35096. Partially covers cases for refactor discoverability #37895.This change allows the user to send the code action command (
ctrl + .
in VS and VSCode) to request available refactors at a cursor location (empty span) rather than having to select the entire span of the code to be refactored. The intent is to make refactors more discoverable by allowing a user to "ask" if a refactor is available, rather than having to know in advance that a refactor is applicable to a particular span.In the future we may want to offer more refactors when the code action command is sent while non-empty span is selected. This change enables that behavior but intentionally does not implement it.