Making move to code action appear less often (#198864)

taking code from other pr
This commit is contained in:
Aiday Marlen Kyzy 2023-11-29 02:00:19 +01:00 committed by GitHub
parent 13075044a0
commit 30ac9a452d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 10 deletions

View file

@ -21,6 +21,8 @@ import { nulToken } from '../utils/cancellation';
import FormattingOptionsManager from './fileConfigurationManager';
import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration';
import { EditorChatFollowUp, EditorChatFollowUp_Args, CompositeCommand } from './util/copilot';
import * as PConst from '../tsServer/protocol/protocol.const';
import { CachedResponse } from '../tsServer/cachedResponse';
function toWorkspaceEdit(client: ITypeScriptServiceClient, edits: readonly Proto.FileCodeEdits[]): vscode.WorkspaceEdit {
const workspaceEdit = new vscode.WorkspaceEdit();
@ -455,8 +457,44 @@ type TsCodeAction = InlinedCodeAction | MoveToFileCodeAction | SelectCodeAction;
class TypeScriptRefactorProvider implements vscode.CodeActionProvider<TsCodeAction> {
private static readonly _declarationKinds = new Set([
PConst.Kind.module,
PConst.Kind.class,
PConst.Kind.interface,
PConst.Kind.function,
PConst.Kind.enum,
PConst.Kind.type,
PConst.Kind.const,
PConst.Kind.variable,
PConst.Kind.let,
]);
private static isOnSignatureName(node: Proto.NavigationTree, range: vscode.Range): boolean {
if (this._declarationKinds.has(node.kind)) {
// Show when on the name span
if (node.nameSpan) {
const convertedSpan = typeConverters.Range.fromTextSpan(node.nameSpan);
if (range.intersection(convertedSpan)) {
return true;
}
}
// Show when on the same line as an exported symbols without a name (handles default exports)
if (!node.nameSpan && /\bexport\b/.test(node.kindModifiers) && node.spans.length) {
const convertedSpan = typeConverters.Range.fromTextSpan(node.spans[0]);
if (range.intersection(new vscode.Range(convertedSpan.start.line, 0, convertedSpan.start.line, Number.MAX_SAFE_INTEGER))) {
return true;
}
}
}
// Show if on the signature of any children
return node.childItems?.some(child => this.isOnSignatureName(child, range)) ?? false;
}
constructor(
private readonly client: ITypeScriptServiceClient,
private readonly cachedNavTree: CachedResponse<Proto.NavTreeResponse>,
private readonly formattingOptionsManager: FormattingOptionsManager,
commandManager: CommandManager,
telemetryReporter: TelemetryReporter
@ -516,20 +554,38 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider<TsCodeActi
return undefined;
}
const actions = Array.from(this.convertApplicableRefactors(document, response.body, rangeOrSelection)).filter(action => {
const applicableRefactors = this.convertApplicableRefactors(document, response.body, rangeOrSelection);
const actions = coalesce(await Promise.all(Array.from(applicableRefactors, async action => {
if (this.client.apiVersion.lt(API.v430)) {
// Don't show 'infer return type' refactoring unless it has been explicitly requested
// https://github.com/microsoft/TypeScript/issues/42993
if (!context.only && action.kind?.value === 'refactor.rewrite.function.returnType') {
return false;
return undefined;
}
}
return true;
});
// Don't include move actions on auto light bulb unless you are on a declaration name
if (this.client.apiVersion.lt(API.v540) && context.triggerKind === vscode.CodeActionTriggerKind.Automatic) {
if (action.kind?.value === Move_NewFile.kind.value || action.kind?.value === Move_File.kind.value) {
const file = this.client.toOpenTsFilePath(document);
if (!file) {
return undefined;
}
const navTree = await this.cachedNavTree.execute(document, () => this.client.execute('navtree', { file }, token));
if (navTree.type !== 'response' || !navTree.body || !TypeScriptRefactorProvider.isOnSignatureName(navTree.body, rangeOrSelection)) {
return undefined;
}
}
}
return action;
})));
if (!context.only) {
return actions;
}
return this.pruneInvalidActions(this.appendInvalidActions(actions), context.only, /* numberOfInvalid = */ 5);
}
@ -719,6 +775,7 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider<TsCodeActi
export function register(
selector: DocumentSelector,
client: ITypeScriptServiceClient,
cachedNavTree: CachedResponse<Proto.NavTreeResponse>,
formattingOptionsManager: FormattingOptionsManager,
commandManager: CommandManager,
telemetryReporter: TelemetryReporter,
@ -727,7 +784,7 @@ export function register(
requireSomeCapability(client, ClientCapability.Semantic),
], () => {
return vscode.languages.registerCodeActionsProvider(selector.semantic,
new TypeScriptRefactorProvider(client, formattingOptionsManager, commandManager, telemetryReporter),
new TypeScriptRefactorProvider(client, cachedNavTree, formattingOptionsManager, commandManager, telemetryReporter),
TypeScriptRefactorProvider.metadata);
});
}

View file

@ -57,17 +57,17 @@ export default class LanguageProvider extends Disposable {
private async registerProviders(): Promise<void> {
const selector = this.documentSelector;
const cachedResponse = new CachedResponse();
const cachedNavTreeResponse = new CachedResponse();
await Promise.all([
import('./languageFeatures/callHierarchy').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/codeLens/implementationsCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedResponse))),
import('./languageFeatures/codeLens/referencesCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedResponse))),
import('./languageFeatures/codeLens/implementationsCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedNavTreeResponse))),
import('./languageFeatures/codeLens/referencesCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedNavTreeResponse))),
import('./languageFeatures/completions').then(provider => this._register(provider.register(selector, this.description, this.client, this.typingsStatus, this.fileConfigurationManager, this.commandManager, this.telemetryReporter, this.onCompletionAccepted))),
import('./languageFeatures/definitions').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/directiveCommentCompletions').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/documentHighlight').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/documentSymbol').then(provider => this._register(provider.register(selector, this.client, cachedResponse))),
import('./languageFeatures/documentSymbol').then(provider => this._register(provider.register(selector, this.client, cachedNavTreeResponse))),
import('./languageFeatures/fileReferences').then(provider => this._register(provider.register(this.client, this.commandManager))),
import('./languageFeatures/fixAll').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.client.diagnosticsManager))),
import('./languageFeatures/folding').then(provider => this._register(provider.register(selector, this.client))),
@ -80,7 +80,7 @@ export default class LanguageProvider extends Disposable {
import('./languageFeatures/mappedCodeEditProvider').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/organizeImports').then(provider => this._register(provider.register(selector, this.client, this.commandManager, this.fileConfigurationManager, this.telemetryReporter))),
import('./languageFeatures/quickFix').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter))),
import('./languageFeatures/refactor').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))),
import('./languageFeatures/refactor').then(provider => this._register(provider.register(selector, this.client, cachedNavTreeResponse, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))),
import('./languageFeatures/references').then(provider => this._register(provider.register(selector, this.client))),
import('./languageFeatures/rename').then(provider => this._register(provider.register(selector, this.description, this.client, this.fileConfigurationManager))),
import('./languageFeatures/semanticTokens').then(provider => this._register(provider.register(selector, this.client))),