Skip to content

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

Conversation

PranavSenthilnathan
Copy link
Member

@PranavSenthilnathan PranavSenthilnathan commented Apr 9, 2020

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:

  • addOrRemoveBracesToArrowFunction
  • convertExport
  • convertImport
  • extractSymbol
  • extractType
  • generateGetAccessorAndSetAccessor

Refactors that currently have too simple or too complex error messages:

  • convertParamsToDestructuredObject
  • moveToNewFile

Starting this as a draft PR because of these 2 questions:

  1. 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?

  2. The errors are Diagnostics. Is there a standard way to stringify a Diagnostic?

@jessetrinity
Copy link
Contributor

jessetrinity commented Apr 9, 2020

Overall looks good so far.

Do we intend to also include the Diagnostic messages from getRangeToExtract? Not sure if they would be useful, but they might be if we have requests for specific refactors.

if (!usedFunctionNames.has(description)) {
usedFunctionNames.set(description, true);
functionActions.push({
description,
name: `function_scope_${i}`
});
}
} else if (!innermostErrorFunctionAction) {
Copy link
Contributor

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?

Copy link
Member Author

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.

mjbvz added a commit to microsoft/vscode that referenced this pull request Apr 11, 2020
@mjbvz
Copy link
Contributor

mjbvz commented Apr 11, 2020

microsoft/vscode@f3ceb33 in VS Code adds support for an .error property on RefactorActionInfo. This should let you test the UX of this in VS Code

You'll just need to make sure that .error is sent along by the TS Server. The next VS Code insiders should be able to interpret that value

@PranavSenthilnathan PranavSenthilnathan marked this pull request as ready for review June 18, 2020 20:21
@andrewbranch
Copy link
Member

Are these messages intended to be shown to a user? If so, they need to go in diagnostics.json so they can be localized.

Also, I realize this came from @mjbvz’s proposal so if the editor folks have a strong opinion you can disregard—but the terminology error was a little misleading to me in this context, since it has nothing to do with compiler diagnostic errors and it doesn’t indicate that anything went wrong; it’s not like the refactor threw an error and had to abort.

"category": "Message",
"code": 95136
},
"Property_has_invalid_accessibility": {
Copy link
Contributor

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;
Copy link
Contributor

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?

Copy link
Contributor

@jessetrinity jessetrinity left a 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.

@PranavSenthilnathan PranavSenthilnathan merged commit 2f79389 into microsoft:master Jun 22, 2020
Copy link
Member

@amcasey amcasey left a 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 {
Copy link
Member

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 = {
Copy link
Member

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");
Copy link
Member

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)
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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 }] },
Copy link
Member

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;
Copy link
Member

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[]) {
Copy link
Member

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;
Copy link
Member

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?

cangSDARM added a commit to cangSDARM/TypeScript that referenced this pull request Jun 23, 2020
* 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
Jack-Works pushed a commit to Jack-Works/TypeScript that referenced this pull request Jun 24, 2020
* 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
mjbvz added a commit to microsoft/vscode that referenced this pull request Jul 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TS Server: Return description of why a given refactoring cannot be applied
5 participants