Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for code action literal as a return value of the textDocument/codeAction request #350

Merged
merged 5 commits into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
* text=auto

LICENSE.txt eol=crlf
ThirdPartyNotices.txt eol=crlf

*.bat eol=crlf
*.cmd eol=crlf
*.ps1 eol=lf
*.sh eol=lf
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;
const cap = ensure(ensure(capabilites, 'textDocument')!, 'codeAction')!;
cap.dynamicRegistration = true;
cap.codeActionLiteralSupport = {
codeActionKind: {
valueSet: [
VCodeActionKind.Empty.value!,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The protocol doesn't have a CodeActionKind.Empty declared. Is this an issue? See below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

VCodeActionKind.QuickFix.value!,
VCodeActionKind.Refactor.value!,
VCodeActionKind.RefactorExtract.value!,
VCodeActionKind.RefactorInline.value!,
VCodeActionKind.RefactorRewrite.value!,
VCodeActionKind.Source.value!,
VCodeActionKind.SourceOrganizeImports.value!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to use CodeActionKind from the language server protocol instead of using the VS Code one? That sounds a lot safer and is more agnostic since then we're only using stuff that the protocol explicitly declares.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Will change it.

]
}
};
}

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
4 changes: 2 additions & 2 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
ExecuteCommandRequest, ExecuteCommandParams,
ApplyWorkspaceEditRequest, ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse,
ClientCapabilities, ServerCapabilities, ProtocolConnection, createProtocolConnection, TypeDefinitionRequest, ImplementationRequest,
DocumentColorRequest, DocumentColorParams, ColorInformation, ColorPresentationParams, ColorPresentation, ColorPresentationRequest
DocumentColorRequest, DocumentColorParams, ColorInformation, ColorPresentationParams, ColorPresentation, ColorPresentationRequest, CodeAction
} from 'vscode-languageserver-protocol';

import { Configuration, ConfigurationFeature } from './configuration';
Expand Down Expand Up @@ -1249,7 +1249,7 @@ export interface Connection<PConsole = _, PTracer = _, PTelemetry = _, PClient =
*
* @param handler The corresponding handler.
*/
onCodeAction(handler: RequestHandler<CodeActionParams, Command[] | undefined | null, void>): void;
onCodeAction(handler: RequestHandler<CodeActionParams, (Command | CodeAction)[] | undefined | null, void>): void;

/**
* Compute a list of [lenses](#CodeLens). This call should return as fast as possible and if
Expand Down
Loading