-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Add reason for a disabled code action #37871
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 reason for a disabled code action #37871
Conversation
Overall looks good so far. Do we intend to also include the Diagnostic messages from |
if (!usedFunctionNames.has(description)) { | ||
usedFunctionNames.set(description, true); | ||
functionActions.push({ | ||
description, | ||
name: `function_scope_${i}` | ||
}); | ||
} | ||
} else if (!innermostErrorFunctionAction) { |
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 guess the "innermost" error is the only one we care about?
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.
Yep, this is probably the most relevant since it's lexically closest to problem.
microsoft/vscode@f3ceb33 in VS Code adds support for an You'll just need to make sure that |
Are these messages intended to be shown to a user? If so, they need to go in Also, I realize this came from @mjbvz’s proposal so if the editor folks have a strong opinion you can disregard—but the terminology |
src/compiler/diagnosticMessages.json
Outdated
"category": "Message", | ||
"code": 95136 | ||
}, | ||
"Property_has_invalid_accessibility": { |
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 property needs to have any accessibility modifier or static
or readonly
right? If so, does it make sense to say "Can only convert property with modifier"?
} | ||
|
||
if (!(nodeOverlapsWithStartEnd(declaration.name, file, start, end) || cursorRequest)) { | ||
return 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.
This should just check that the span is in a sensible place to offer the refactor. Should we return the "Could not find property" message here?
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 have a couple of comments about the messages themselves but otherwise looks good.
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.
Mostly nitpicking
@@ -70,28 +98,45 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { | |||
return { renameFilename: undefined, renameLocation: undefined, edits }; | |||
} | |||
|
|||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true): Info | undefined { | |||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true): InfoOrError | 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.
Can this still return undefined
? When?
@@ -15,33 +15,61 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { | |||
addBraces: boolean; | |||
} | |||
|
|||
type InfoOrError = { |
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.
Maybe this type should be generic and reused?
info?: never, | ||
error: string | ||
}; | ||
|
||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] { | ||
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.
Personally, I'd take the hit and rename the outer info
so we don't have info.info
everywhere. Maybe result
?
|
||
if (!func) { | ||
return { | ||
error: getLocaleSpecificMessage(Diagnostics.Could_not_find_a_containing_arrow_function) |
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.
Or any other sort of containing function?
error?: never | ||
} | { | ||
info?: never, | ||
error: 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.
Would DiagnosticMessage
be narrower and lazier than string
?
actions: [{ | ||
name: addBracesActionName, | ||
description: addBracesActionDescription, | ||
notApplicableReason: info.error |
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.
Without having read the code in detail, it seems intuitively unlikely to me that add-braces and remove-braces would fail for the same reason.
|
||
if (context.preferences.provideRefactorNotApplicableReason) { | ||
return [ | ||
{ name: refactorName, description: Diagnostics.Convert_namespace_import_to_named_imports.message, actions: [{ name: actionNameNamespaceToNamed, description: Diagnostics.Convert_namespace_import_to_named_imports.message, notApplicableReason: i.error }] }, |
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.
How is .message
different from getLocaleSpecificMessage
?
const { file } = context; | ||
const span = getRefactorContextSpan(context); | ||
const token = getTokenAtPosition(file, span.start); | ||
const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) : getParentNodeInSpan(token, file, span); | ||
if (!importDecl || !isImportDeclaration(importDecl) || (importDecl.getEnd() < span.start + span.length)) return undefined; | ||
if (!importDecl || !isImportDeclaration(importDecl)) return { error: "Selection is not an import declaration." }; | ||
if (importDecl.getEnd() < span.start + span.length) return 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.
Why no error in this case?
}); | ||
} | ||
|
||
return infos.length ? infos : emptyArray; | ||
|
||
function getStringError(errors: readonly Diagnostic[]) { |
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.
What does this do? I thought all refactoring errors were strings.
@@ -3789,6 +3789,7 @@ declare namespace ts { | |||
readonly importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js"; | |||
readonly allowTextChangesInNewFiles?: boolean; | |||
readonly providePrefixAndSuffixTextForRename?: boolean; | |||
readonly provideRefactorNotApplicableReason?: boolean; |
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 feel like I'm missing something obvious, but shouldn't there also be a protocol change for this?
* upstream/master: (58 commits) Variadic tuple types (microsoft#39094) chore: resolve suggestions Expand auto-import to all package.json dependencies (microsoft#38923) inline local functions Update bigint declaration file (microsoft#38526) Update user baselines (microsoft#39077) LEGO: check in for master to temporary branch. Add missing index.ts files to user projects (microsoft#39163) Add reason for a disabled code action (microsoft#37871) Minor fix for assertion predicates (microsoft#38710) Update LKG (microsoft#39173) Reparse top level 'await' in modules (microsoft#39084) change chore: more change chore: resolve review chore: save space fix: lint error test: add test for it chore: make isJsxAttr required chore: revert change in checker ... # Conflicts: # src/compiler/binder.ts # src/compiler/checker.ts # src/compiler/parser.ts # src/compiler/types.ts
* add reason for a disabled code action * add addOrRemoveBracesToArrowFunction * use user preferences * add error reason * accept baseline changes * fix lint rules * move messages to diagnosticMessages.json * rename 'error' to 'notApplicableReason' * accept baseline change * address comments
Adopts changes from microsoft/TypeScript#37871
Fixes #35098
This PR adds the error property on refactors so that the editor can consume it and show the user why a refactor does not apply in the case. The extract symbol refactor already has error messages so that's already wired up but these are the other refactors that need messages:
Refactors that currently have too simple or too complex error messages:
Starting this as a draft PR because of these 2 questions:
The messages in the extractSymbol.ts have this comment:
// Move these into diagnostic messages if they become user-facing
Is this just moving it into
src\compiler\diagnosticMessages.json
?The errors are
Diagnostic
s. Is there a standard way to stringify aDiagnostic
?