Let the internal API only talk CodeAction, #34664

This commit is contained in:
Johannes Rieken
2017-11-24 10:50:52 +01:00
parent dc88576eb7
commit 5f51de4851
9 changed files with 77 additions and 57 deletions

View File

@@ -581,7 +581,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideHover(handle: number, resource: URI, position: IPosition): TPromise<modes.Hover>;
$provideDocumentHighlights(handle: number, resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]>;
$provideReferences(handle: number, resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]>;
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<(modes.Command | modes.CodeAction)[]>;
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<modes.CodeAction[]>;
$provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;
$provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;
$provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;

View File

@@ -16,6 +16,7 @@ import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures';
export class ExtHostApiCommands {
@@ -392,16 +393,26 @@ export class ExtHostApiCommands {
});
}
private _executeCodeActionProvider(resource: URI, range: types.Range): Thenable<vscode.Command[]> {
private _executeCodeActionProvider(resource: URI, range: types.Range): Thenable<(vscode.CodeAction | vscode.Command)[]> {
const args = {
resource,
range: typeConverters.fromRange(range)
};
return this._commands.executeCommand<modes.Command[]>('_executeCodeActionProvider', args).then(value => {
return this._commands.executeCommand<CustomCodeAction[]>('_executeCodeActionProvider', args).then(value => {
if (!Array.isArray(value)) {
return undefined;
}
return value.map(quickFix => this._commands.converter.fromInternal(quickFix));
return value.map(codeAction => {
if (codeAction._isSynthetic) {
return this._commands.converter.fromInternal(codeAction.command);
} else {
const ret = new types.CodeAction(
codeAction.title,
typeConverters.WorkspaceEdit.to(codeAction.edits)
);
return ret;
}
});
});
}

View File

@@ -255,7 +255,11 @@ class ReferenceAdapter {
}
}
class QuickFixAdapter {
export interface CustomCodeAction extends modes.CodeAction {
_isSynthetic?: boolean;
}
class CodeActionAdapter {
private _documents: ExtHostDocuments;
private _commands: CommandsConverter;
@@ -269,7 +273,7 @@ class QuickFixAdapter {
this._provider = provider;
}
provideCodeActions(resource: URI, range: IRange): TPromise<(modes.CodeAction | modes.Command)[]> {
provideCodeActions(resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
const doc = this._documents.getDocumentData(resource).document;
const ran = <vscode.Range>TypeConverters.toRange(range);
@@ -285,39 +289,45 @@ class QuickFixAdapter {
}
});
return asWinJsPromise(token =>
this._provider.provideCodeActions2
? this._provider.provideCodeActions2(doc, ran, { diagnostics: allDiagnostics }, token)
: this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)
).then(commands => {
if (!Array.isArray(commands)) {
return asWinJsPromise(token => this._provider.provideCodeActions2
? this._provider.provideCodeActions2(doc, ran, { diagnostics: allDiagnostics }, token)
: this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)
).then(commandsOrActions => {
if (isFalsyOrEmpty(commandsOrActions)) {
return undefined;
}
return commands.map((action): modes.CodeAction => {
if (!action) {
return undefined;
const result: CustomCodeAction[] = [];
for (const candidate of commandsOrActions) {
if (!candidate) {
continue;
}
if (typeof action.command === 'string') {
return this._commands.toInternal(action as vscode.Command);
if (CodeActionAdapter._isCommand(candidate)) {
// old school: synthetic code action
result.push({
_isSynthetic: true,
title: candidate.title,
command: this._commands.toInternal(candidate),
});
} else {
// new school: convert code action
result.push({
title: candidate.title,
command: candidate.command && this._commands.toInternal(candidate.command),
diagnostics: candidate.diagnostics && candidate.diagnostics.map(DiagnosticCollection.toMarkerData),
edits: Array.isArray(candidate.edits)
? TypeConverters.WorkspaceEdit.fromTextEdits(resource, candidate.edits)
: candidate.edits && TypeConverters.WorkspaceEdit.from(candidate.edits),
});
}
}
const codeAction = action as vscode.CodeAction;
return {
title: codeAction.title,
command: codeAction.command ? this._commands.toInternal(codeAction.command) : undefined,
edits: codeAction.edits
? Array.isArray(codeAction.edits)
? TypeConverters.WorkspaceEdit.fromTextEdits(resource, codeAction.edits)
: TypeConverters.WorkspaceEdit.from(codeAction.edits)
: undefined,
diagnostics: codeAction.diagnostics
? codeAction.diagnostics.map(DiagnosticCollection.toMarkerData)
: undefined
} as modes.CodeAction;
});
return result;
});
}
private static _isCommand(thing: any): thing is vscode.Command {
return typeof (<vscode.Command>thing).command === 'string' && typeof (<vscode.Command>thing).title === 'string';
}
}
class DocumentFormattingAdapter {
@@ -768,7 +778,7 @@ class ColorProviderAdapter {
}
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | QuickFixAdapter | DocumentFormattingAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter;
@@ -933,13 +943,13 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
this._adapter.set(handle, new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
this._proxy.$registerQuickFixSupport(handle, selector);
return this._createDisposable(handle);
}
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<(modes.Command | modes.CodeAction)[]> {
return this._withAdapter(handle, QuickFixAdapter, adapter => adapter.provideCodeActions(resource, range));
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(resource, range));
}
// --- formatting

View File

@@ -252,6 +252,14 @@ export namespace WorkspaceEdit {
}
return result;
}
export function to(value: modes.WorkspaceEdit) {
const result = new types.WorkspaceEdit();
for (const edit of value.edits) {
result.replace(edit.resource, toRange(edit.range), edit.newText);
}
return result;
}
}
@@ -617,4 +625,4 @@ function doToLanguageSelector(selector: string | vscode.DocumentFilter): string
scheme: selector.scheme,
pattern: toGlobPattern(selector.pattern)
};
}
}