Remove duplicate code for applying a code action

This commit is contained in:
Matt Bierner
2017-10-20 12:07:12 -07:00
parent 8798aa5380
commit 0a0033b855
4 changed files with 71 additions and 46 deletions

View File

@@ -3,12 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit } from 'vscode';
import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands } from 'vscode';
import * as Proto from '../protocol';
import { ITypescriptServiceClient } from '../typescriptService';
import { tsTextSpanToVsRange, vsRangeToTsFileRange } from '../utils/convert';
import { vsRangeToTsFileRange } from '../utils/convert';
import FormattingConfigurationManager from './formattingConfigurationManager';
import { applyCodeAction } from '../utils/codeAction';
interface NumberSet {
[key: number]: boolean;
@@ -87,30 +88,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider
};
}
private async onCodeAction(action: Proto.CodeAction, file: string): Promise<boolean> {
if (action.changes && action.changes.length) {
const workspaceEdit = new WorkspaceEdit();
for (const change of action.changes) {
for (const textChange of change.textChanges) {
workspaceEdit.replace(this.client.asUrl(change.fileName),
tsTextSpanToVsRange(textChange),
textChange.newText);
}
}
if (!(await workspace.applyEdit(workspaceEdit))) {
return false;
}
}
if (action.commands && action.commands.length) {
for (const command of action.commands) {
const response = await this.client.execute('applyCodeActionCommand', { file, command });
if (!response || !response.body) {
return false;
}
}
}
return true;
private onCodeAction(action: Proto.CodeAction, file: string): Promise<boolean> {
return applyCodeAction(this.client, action, file);
}
}

View File

@@ -3,17 +3,18 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext } from 'vscode';
import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext, commands } from 'vscode';
import { ITypescriptServiceClient } from '../typescriptService';
import TypingsStatus from '../utils/typingsStatus';
import * as PConst from '../protocol.const';
import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails } from '../protocol';
import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, CodeAction } from '../protocol';
import * as Previewer from './previewer';
import { tsTextSpanToVsRange, vsPositionToTsFileLocation, tsLocationToVsPosition } from '../utils/convert';
import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert';
import * as nls from 'vscode-nls';
import { applyCodeAction } from '../utils/codeAction';
let localize = nls.loadMessageBundle();
class MyCompletionItem extends CompletionItem {
@@ -132,6 +133,7 @@ namespace Configuration {
}
export default class TypeScriptCompletionItemProvider implements CompletionItemProvider {
private readonly commandId: string;
private config: Configuration = {
useCodeSnippetsOnMethodSuggest: false,
@@ -141,8 +143,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
constructor(
private client: ITypescriptServiceClient,
mode: string,
private typingsStatus: TypingsStatus
) { }
) {
this.commandId = `_typescript.applyCompletionCodeAction.${mode}`;
commands.registerCommand(this.commandId, this.applyCompletionCodeAction, this);
}
public updateConfiguration(): void {
// Use shared setting for js and ts
@@ -280,20 +286,11 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
item.documentation = Previewer.markdownDocumentation(detail.documentation, detail.tags);
if (detail.codeActions && detail.codeActions.length) {
const additionalEdits: TextEdit[] = [];
for (const action of detail.codeActions) {
for (const change of action.changes) {
if (change.fileName !== filepath) {
continue;
}
for (const edit of change.textChanges) {
additionalEdits.push(new TextEdit(
new Range(tsLocationToVsPosition(edit.start), tsLocationToVsPosition(edit.end)),
edit.newText));
}
}
}
item.additionalTextEdits = additionalEdits;
item.command = {
title: '',
command: this.commandId,
arguments: [filepath, detail.codeActions]
};
}
if (detail && this.config.useCodeSnippetsOnMethodSuggest && (item.kind === CompletionItemKind.Function || item.kind === CompletionItemKind.Method)) {
@@ -357,4 +354,13 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
return new SnippetString(codeSnippet);
}
private async applyCompletionCodeAction(file: string, codeActions: CodeAction[]): Promise<boolean> {
for (const action of codeActions) {
if (!(await applyCodeAction(this.client, action, file))) {
return false;
}
}
return true;
}
}

View File

@@ -239,7 +239,7 @@ class LanguageProvider {
const selector = this.description.modeIds;
const config = workspace.getConfiguration(this.id);
const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus);
const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.description.id, this.typingsStatus);
completionItemProvider.updateConfiguration();
this.toUpdateOnConfigurationChanged.push(completionItemProvider);
this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/', '@'));

View File

@@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { WorkspaceEdit, workspace } from 'vscode';
import * as Proto from '../protocol';
import { tsTextSpanToVsRange } from './convert';
import { ITypescriptServiceClient } from '../typescriptService';
export async function applyCodeAction(
client: ITypescriptServiceClient,
action: Proto.CodeAction,
file: string
): Promise<boolean> {
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);
}
}
if (!(await workspace.applyEdit(workspaceEdit))) {
return false;
}
}
if (action.commands && action.commands.length) {
for (const command of action.commands) {
const response = await client.execute('applyCodeActionCommand', { file, command });
if (!response || !response.body) {
return false;
}
}
}
return true;
}