Skip to content

Commit

Permalink
Implement CodeAction protocol conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
dbaeumer committed May 17, 2018
1 parent 692bfa9 commit 58f353b
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 17 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
"vscode": "^1.22"
"vscode": "^1.23"
},
"repository": {
"type": "git",
Expand Down
45 changes: 36 additions & 9 deletions client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
FileSystemWatcher as VFileSystemWatcher, DiagnosticCollection, Diagnostic as VDiagnostic, Uri, ProviderResult,
CancellationToken, Position as VPosition, Location as VLocation, Range as VRange,
CompletionItem as VCompletionItem, CompletionList as VCompletionList, SignatureHelp as VSignatureHelp, Definition as VDefinition, DocumentHighlight as VDocumentHighlight,
SymbolInformation as VSymbolInformation, CodeActionContext as VCodeActionContext, Command as VCommand, CodeLens as VCodeLens,
SymbolInformation as VSymbolInformation, CodeActionContext as VCodeActionContext, Command as VCommand, CodeLens as VCodeLens, CodeActionKind as VCodeActionKind,
FormattingOptions as VFormattingOptions, TextEdit as VTextEdit, WorkspaceEdit as VWorkspaceEdit, MessageItem,
Hover as VHover,
Hover as VHover, CodeAction as VCodeAction,
DocumentLink as VDocumentLink, TextDocumentWillSaveEvent,
WorkspaceFolder as VWorkspaceFolder, CompletionContext as VCompletionContext
} from 'vscode';
Expand Down Expand Up @@ -53,7 +53,7 @@ import {
DocumentLinkRequest, DocumentLinkResolveRequest, DocumentLinkRegistrationOptions,
ExecuteCommandRequest, ExecuteCommandParams, ExecuteCommandRegistrationOptions,
ApplyWorkspaceEditRequest, ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse,
MarkupKind, SymbolKind, CompletionItemKind
MarkupKind, SymbolKind, CompletionItemKind, Command
} from 'vscode-languageserver-protocol';

import { ColorProviderMiddleware } from './colorProvider';
Expand Down Expand Up @@ -359,7 +359,7 @@ export interface ProvideWorkspaceSymbolsSignature {
}

export interface ProvideCodeActionsSignature {
(document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): ProviderResult<VCommand[]>;
(document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): ProviderResult<(VCommand | VCodeAction)[]>;
}

export interface ProvideCodeLensesSignature {
Expand Down Expand Up @@ -430,7 +430,7 @@ export interface _Middleware {
provideDocumentHighlights?: (this: void, document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideDocumentHighlightsSignature) => ProviderResult<VDocumentHighlight[]>;
provideDocumentSymbols?: (this: void, document: TextDocument, token: CancellationToken, next: ProvideDocumentSymbolsSignature) => ProviderResult<VSymbolInformation[]>;
provideWorkspaceSymbols?: (this: void, query: string, token: CancellationToken, next: ProvideWorkspaceSymbolsSignature) => ProviderResult<VSymbolInformation[]>;
provideCodeActions?: (this: void, document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken, next: ProvideCodeActionsSignature) => ProviderResult<VCommand[]>;
provideCodeActions?: (this: void, document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken, next: ProvideCodeActionsSignature) => ProviderResult<(VCommand | VCodeAction)[]>;
provideCodeLenses?: (this: void, document: TextDocument, token: CancellationToken, next: ProvideCodeLensesSignature) => ProviderResult<VCodeLens[]>;
resolveCodeLens?: (this: void, codeLens: VCodeLens, token: CancellationToken, next: ResolveCodeLensSignature) => ProviderResult<VCodeLens>;
provideDocumentFormattingEdits?: (this: void, document: TextDocument, options: VFormattingOptions, token: CancellationToken, next: ProvideDocumentFormattingEditsSignature) => ProviderResult<VTextEdit[]>;
Expand Down Expand Up @@ -1671,7 +1671,22 @@ class CodeActionFeature extends TextDocumentFeature<TextDocumentRegistrationOpti
}

public fillClientCapabilities(capabilites: ClientCapabilities): void {
ensure(ensure(capabilites, 'textDocument')!, 'codeAction')!.dynamicRegistration = true;

This comment has been minimized.

Copy link
@thatb96

thatb96 Dec 20, 2018

True

const cap = ensure(ensure(capabilites, 'textDocument')!, 'codeAction')!;
cap.dynamicRegistration = true;
cap.codeActionLiteralSupport = {
codeActionKind: {
valueSet: [
VCodeActionKind.Empty.value!,
VCodeActionKind.QuickFix.value!,
VCodeActionKind.Refactor.value!,
VCodeActionKind.RefactorExtract.value!,
VCodeActionKind.RefactorInline.value!,
VCodeActionKind.RefactorRewrite.value!,
VCodeActionKind.Source.value!,
VCodeActionKind.SourceOrganizeImports.value!
]
}
};
}

public initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void {
Expand All @@ -1692,8 +1707,20 @@ class CodeActionFeature extends TextDocumentFeature<TextDocumentRegistrationOpti
range: client.code2ProtocolConverter.asRange(range),
context: client.code2ProtocolConverter.asCodeActionContext(context)
};
return client.sendRequest(CodeActionRequest.type, params, token).then(
client.protocol2CodeConverter.asCommands,
return client.sendRequest(CodeActionRequest.type, params, token).then((values) => {
if (values === null) {
return undefined;
}
let result: (VCommand | VCodeAction)[] = [];
for (let item of values) {
if (Command.is(item)) {
result.push(client.protocol2CodeConverter.asCommand(item))
} else {
result.push(client.protocol2CodeConverter.asCodeAction(item));
};
}
return result;
},
(error) => {
client.logFailedRequest(CodeActionRequest.type, error);
return Promise.resolve([]);
Expand All @@ -1702,7 +1729,7 @@ class CodeActionFeature extends TextDocumentFeature<TextDocumentRegistrationOpti
}
let middleware = client.clientOptions.middleware!;
return Languages.registerCodeActionsProvider(options.documentSelector!, {
provideCodeActions: (document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): ProviderResult<VCommand[]> => {
provideCodeActions: (document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): ProviderResult<(VCommand | VCodeAction)[]> => {
return middleware.provideCodeActions
? middleware.provideCodeActions(document, range, context, token, provideCodeActions)
: provideCodeActions(document, range, context, token);
Expand Down
49 changes: 49 additions & 0 deletions client/src/protocolConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export interface Converter {
asCommands(items: undefined | null): undefined
asCommands(items: ls.Command[] | undefined | null): code.Command[] | undefined;

asCodeAction(item: ls.CodeAction): code.CodeAction;
asCodeAction(item: undefined | null): undefined;
asCodeAction(item: ls.CodeAction | undefined | null): code.CodeAction | undefined;

asCodeLens(item: ls.CodeLens): code.CodeLens;
asCodeLens(item: undefined | null): undefined;
asCodeLens(item: ls.CodeLens | undefined | null): code.CodeLens | undefined;
Expand Down Expand Up @@ -494,6 +498,50 @@ export function createConverter(uriConverter?: URIConverter): Converter {
return items.map(asCommand);
}

const kindMapping: Map<ls.CodeActionKind, code.CodeActionKind> = new Map();
kindMapping.set('', code.CodeActionKind.Empty);
kindMapping.set(ls.CodeActionKind.QuickFix, code.CodeActionKind.QuickFix);
kindMapping.set(ls.CodeActionKind.Refactor, code.CodeActionKind.Refactor);
kindMapping.set(ls.CodeActionKind.RefactorExtract, code.CodeActionKind.RefactorExtract);
kindMapping.set(ls.CodeActionKind.RefactorInline, code.CodeActionKind.RefactorInline);
kindMapping.set(ls.CodeActionKind.RefactorRewrite, code.CodeActionKind.RefactorRewrite);
kindMapping.set(ls.CodeActionKind.Source, code.CodeActionKind.Source);
kindMapping.set(ls.CodeActionKind.SourceOrganizeImports, code.CodeActionKind.SourceOrganizeImports);

function asCodeActionKind(item: null | undefined): undefined;
function asCodeActionKind(item: ls.CodeActionKind): code.CodeActionKind;
function asCodeActionKind(item: ls.CodeActionKind | null | undefined): code.CodeActionKind | undefined;
function asCodeActionKind(item: ls.CodeActionKind | null | undefined): code.CodeActionKind | undefined {
if (item === void 0 || item === null) {
return undefined
}
let result: code.CodeActionKind | undefined = kindMapping.get(item);
if (result) {
return result;
}
let parts = item.split('.');
result = code.CodeActionKind.Empty;
for (let part of parts) {
result = result.append(part);
}
return result;
}

function asCodeAction(item: ls.CodeAction): code.CodeAction;
function asCodeAction(item: undefined | null): undefined;
function asCodeAction(item: ls.CodeAction | undefined | null): code.CodeAction | undefined;
function asCodeAction(item: ls.CodeAction | undefined | null): code.CodeAction | undefined {
if (item === void 0 || item === null) {
return undefined;
}
let result = new code.CodeAction(item.title);
if (item.kind !== void 0) { result.kind = asCodeActionKind(item.kind); }
if (item.diagnostics) { result.diagnostics = asDiagnostics(item.diagnostics); }
if (item.edit) { result.edit = asWorkspaceEdit(item.edit); }
if (item.command) { result.command = asCommand(item.command); }
return result;
}

function asCodeLens(item: ls.CodeLens): code.CodeLens;
function asCodeLens(item: undefined | null): undefined;
function asCodeLens(item: ls.CodeLens | undefined | null): code.CodeLens | undefined;
Expand Down Expand Up @@ -583,6 +631,7 @@ export function createConverter(uriConverter?: URIConverter): Converter {
asSymbolInformation,
asCommand,
asCommands,
asCodeAction,
asCodeLens,
asCodeLenses,
asWorkspaceEdit,
Expand Down
25 changes: 23 additions & 2 deletions protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
CompletionItem, CompletionList, Hover, SignatureHelp,
Definition, ReferenceContext, DocumentHighlight, DocumentSymbolParams,
SymbolInformation, CodeLens, CodeActionContext, FormattingOptions, DocumentLink, MarkupKind,
SymbolKind, CompletionItemKind
SymbolKind, CompletionItemKind, CodeAction, CodeActionKind
} from 'vscode-languageserver-types';

import { ImplementationRequest, ImplementationClientCapabilities, ImplementationServerCapabilities } from './protocol.implementation';
Expand Down Expand Up @@ -460,6 +460,27 @@ export interface TextDocumentClientCapabilities {
* Whether code action supports dynamic registration.
*/
dynamicRegistration?: boolean;

/**
* The client support code action literals as a valid
* response of the `textDocument/codeAction` request.
*/
codeActionLiteralSupport?: {
/**
* The code action kind is support with the following value
* set.
*/
codeActionKind: {

/**
* The code action kind values the client supports. When this
* property exists the client also guarantees that it will
* handle values outside its set gracefully and falls back
* to a default value when unknown.
*/
valueSet: CodeActionKind[];
};
};
};

/**
Expand Down Expand Up @@ -1522,7 +1543,7 @@ export interface CodeActionParams {
* A request to provide commands for the given text document and range.
*/
export namespace CodeActionRequest {
export const type = new RequestType<CodeActionParams, Command[] | null, void, TextDocumentRegistrationOptions>('textDocument/codeAction');
export const type = new RequestType<CodeActionParams, (Command | CodeAction)[] | null, void, TextDocumentRegistrationOptions>('textDocument/codeAction');
}

//---- Code Lens Provider -------------------------------------------
Expand Down
31 changes: 26 additions & 5 deletions types/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,15 @@ export interface WorkspaceEdit {
documentChanges?: TextDocumentEdit[];
}

export namespace WorkspaceEdit {
export function is(value: any): value is WorkspaceEdit {
let candidate: WorkspaceEdit = value;
return candidate &&
(candidate.changes !== void 0 || candidate.documentChanges !== void 0) &&
(candidate.documentChanges === void 0 || Is.typedArray(candidate.documentChanges, TextDocumentEdit.is));
}
}

/**
* A change to capture text edits for existing resources.
*/
Expand Down Expand Up @@ -1467,7 +1476,7 @@ export namespace CodeActionContext {
*
* A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed.
*/
export interface CodeAction {
export type CodeAction = {

/**
* A short, human-readable, title for this code action.
Expand All @@ -1481,6 +1490,11 @@ export interface CodeAction {
*/
kind?: CodeActionKind;

/**
* The diagnostics that this code action resolves.
*/
diagnostics?: Diagnostic[];

/**
* The workspace edit this code action performs.
*/
Expand All @@ -1492,11 +1506,18 @@ export interface CodeAction {
* executed and then the command.
*/
command?: Command;
}

/**
* The diagnostics that this code action resolves.
*/
diagnostics?: Diagnostic[];
export namespace CodeAction {
export function is(value: any): value is CodeAction {
let candidate: CodeAction = value;
return candidate && Is.string(candidate.title) &&
(candidate.diagnostics === void 0 || Is.typedArray(candidate.diagnostics, Diagnostic.is)) &&
(candidate.kind === void 0 || Is.string(candidate.kind)) &&
(candidate.edit !== void 0 || candidate.command !== void 0) &&
(candidate.command === void 0 || Command.is(candidate.command)) &&
(candidate.edit === void 0 || WorkspaceEdit.is(candidate.edit));
}
}

/**
Expand Down

0 comments on commit 58f353b

Please sign in to comment.