mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-02 06:21:50 +01:00
@@ -11,6 +11,10 @@ import { vsRangeToTsFileRange } from '../utils/convert';
|
||||
import FormattingConfigurationManager from './formattingConfigurationManager';
|
||||
import { getEditForCodeAction, applyCodeActionCommands } from '../utils/codeAction';
|
||||
import { Command, CommandManager } from '../utils/commandManager';
|
||||
import { createWorkspaceEditFromFileCodeEdits } from '../utils/workspaceEdit';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
class ApplyCodeActionCommand implements Command {
|
||||
public static readonly ID = '_typescript.applyCodeActionCommand';
|
||||
@@ -87,23 +91,50 @@ export default class TypeScriptQuickFixProvider implements vscode.CodeActionProv
|
||||
|
||||
const results: vscode.CodeAction[] = [];
|
||||
for (const diagnostic of fixableDiagnostics) {
|
||||
const args: Proto.CodeFixRequestArgs = {
|
||||
...vsRangeToTsFileRange(file, diagnostic.range),
|
||||
errorCodes: [+diagnostic.code]
|
||||
};
|
||||
const response = await this.client.execute('getCodeFixes', args, token);
|
||||
if (response.body) {
|
||||
results.push(...response.body.map(action => this.getCommandForAction(diagnostic, action)));
|
||||
}
|
||||
results.push(...await this.getFixesForDiagnostic(file, diagnostic, token));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private getCommandForAction(
|
||||
private async getFixesForDiagnostic(
|
||||
file: string,
|
||||
diagnostic: vscode.Diagnostic,
|
||||
tsAction: Proto.CodeAction
|
||||
token: vscode.CancellationToken
|
||||
): Promise<Iterable<vscode.CodeAction>> {
|
||||
const args: Proto.CodeFixRequestArgs = {
|
||||
...vsRangeToTsFileRange(file, diagnostic.range),
|
||||
errorCodes: [+diagnostic.code]
|
||||
};
|
||||
const codeFixesResponse = await this.client.execute('getCodeFixes', args, token);
|
||||
if (codeFixesResponse.body) {
|
||||
const results: vscode.CodeAction[] = [];
|
||||
for (const tsCodeFix of codeFixesResponse.body) {
|
||||
results.push(...await this.getAllFixesForTsCodeAction(file, diagnostic, tsCodeFix, token));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private async getAllFixesForTsCodeAction(
|
||||
file: string,
|
||||
diagnostic: vscode.Diagnostic,
|
||||
tsAction: Proto.CodeFixAction,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<Iterable<vscode.CodeAction>> {
|
||||
const singleFix = this.getSingleFixForTsCodeAction(diagnostic, tsAction);
|
||||
const fixAll = await this.getFixAllForTsCodeAction(file, diagnostic, tsAction, token);
|
||||
return fixAll ? [singleFix, fixAll] : [singleFix];
|
||||
}
|
||||
|
||||
private getSingleFixForTsCodeAction(
|
||||
diagnostic: vscode.Diagnostic,
|
||||
tsAction: Proto.CodeFixAction
|
||||
): vscode.CodeAction {
|
||||
const codeAction = new vscode.CodeAction(tsAction.description, getEditForCodeAction(this.client, tsAction));
|
||||
const codeAction = new vscode.CodeAction(
|
||||
tsAction.description,
|
||||
getEditForCodeAction(this.client, tsAction));
|
||||
|
||||
codeAction.diagnostics = [diagnostic];
|
||||
if (tsAction.commands) {
|
||||
codeAction.command = {
|
||||
@@ -114,4 +145,45 @@ export default class TypeScriptQuickFixProvider implements vscode.CodeActionProv
|
||||
}
|
||||
return codeAction;
|
||||
}
|
||||
|
||||
private async getFixAllForTsCodeAction(
|
||||
file: string,
|
||||
diagnostic: vscode.Diagnostic,
|
||||
tsAction: Proto.CodeFixAction,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<vscode.CodeAction | undefined> {
|
||||
if (!tsAction.fixId || !this.client.apiVersion.has270Features()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const args: Proto.GetCombinedCodeFixRequestArgs = {
|
||||
scope: {
|
||||
type: 'file',
|
||||
args: { file }
|
||||
},
|
||||
fixId: tsAction.fixId
|
||||
};
|
||||
|
||||
try {
|
||||
const combinedCodeFixesResponse = await this.client.execute('getCombinedCodeFix', args, token);
|
||||
if (!combinedCodeFixesResponse.body) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const codeAction = new vscode.CodeAction(
|
||||
localize('fixAllInFileLabel', '{0} (Fix all in file)', tsAction.description),
|
||||
createWorkspaceEditFromFileCodeEdits(this.client, combinedCodeFixesResponse.body.changes));
|
||||
codeAction.diagnostics = [diagnostic];
|
||||
if (tsAction.commands) {
|
||||
codeAction.command = {
|
||||
command: ApplyCodeActionCommand.ID,
|
||||
arguments: [tsAction],
|
||||
title: tsAction.description
|
||||
};
|
||||
}
|
||||
return codeAction;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface ITypeScriptServiceClient {
|
||||
execute(command: 'navtree', args: Proto.FileRequestArgs, token?: CancellationToken): Promise<Proto.NavTreeResponse>;
|
||||
execute(command: 'getCodeFixes', args: Proto.CodeFixRequestArgs, token?: CancellationToken): Promise<Proto.GetCodeFixesResponse>;
|
||||
execute(command: 'getSupportedCodeFixes', args: null, token?: CancellationToken): Promise<Proto.GetSupportedCodeFixesResponse>;
|
||||
execute(command: 'getCombinedCodeFix', args: Proto.GetCombinedCodeFixRequestArgs, token?: CancellationToken): Promise<Proto.GetCombinedCodeFixResponse>;
|
||||
execute(command: 'docCommentTemplate', args: Proto.FileLocationRequestArgs, token?: CancellationToken): Promise<Proto.DocCommandTemplateResponse>;
|
||||
execute(command: 'getApplicableRefactors', args: Proto.GetApplicableRefactorsRequestArgs, token?: CancellationToken): Promise<Proto.GetApplicableRefactorsResponse>;
|
||||
execute(command: 'getEditsForRefactor', args: Proto.GetEditsForRefactorRequestArgs, token?: CancellationToken): Promise<Proto.GetEditsForRefactorResponse>;
|
||||
|
||||
@@ -91,4 +91,9 @@ export default class API {
|
||||
public has262Features(): boolean {
|
||||
return semver.gte(this.version, '2.6.2');
|
||||
}
|
||||
|
||||
@memoize
|
||||
public has270Features(): boolean {
|
||||
return semver.gte(this.version, '2.7.0');
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,16 @@
|
||||
|
||||
import { WorkspaceEdit, workspace } from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { tsTextSpanToVsRange } from './convert';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import { createWorkspaceEditFromFileCodeEdits } from './workspaceEdit';
|
||||
|
||||
export function getEditForCodeAction(
|
||||
client: ITypeScriptServiceClient,
|
||||
action: Proto.CodeAction
|
||||
): WorkspaceEdit | undefined {
|
||||
if (action.changes && action.changes.length) {
|
||||
const workspaceEdit = new WorkspaceEdit();
|
||||
for (const change of action.changes) {
|
||||
for (const textChange of change.textChanges) {
|
||||
workspaceEdit.replace(client.asUrl(change.fileName),
|
||||
tsTextSpanToVsRange(textChange),
|
||||
textChange.newText);
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceEdit;
|
||||
}
|
||||
return undefined;
|
||||
return action.changes && action.changes.length
|
||||
? createWorkspaceEditFromFileCodeEdits(client, action.changes)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export async function applyCodeAction(
|
||||
|
||||
24
extensions/typescript/src/utils/workspaceEdit.ts
Normal file
24
extensions/typescript/src/utils/workspaceEdit.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import * as Proto from '../protocol';
|
||||
import { tsTextSpanToVsRange } from './convert';
|
||||
|
||||
export function createWorkspaceEditFromFileCodeEdits(
|
||||
client: ITypeScriptServiceClient,
|
||||
edits: Iterable<Proto.FileCodeEdits>
|
||||
): vscode.WorkspaceEdit {
|
||||
const workspaceEdit = new vscode.WorkspaceEdit();
|
||||
for (const edit of edits) {
|
||||
for (const textChange of edit.textChanges) {
|
||||
workspaceEdit.replace(client.asUrl(edit.fileName),
|
||||
tsTextSpanToVsRange(textChange),
|
||||
textChange.newText);
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceEdit;
|
||||
}
|
||||
Reference in New Issue
Block a user