diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 32b16c00f0f21..f063eb29e340e 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -583,6 +583,7 @@ namespace ts.server.protocol { } export interface ApplyCodeActionCommandRequestArgs extends FileRequestArgs { + /** May also be an array of commands. */ command: {}; } diff --git a/src/server/session.ts b/src/server/session.ts index 5284d38dc0f82..aca131773182a 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1557,9 +1557,12 @@ namespace ts.server { private applyCodeActionCommand(commandName: string, requestSeq: number, args: protocol.ApplyCodeActionCommandRequestArgs): void { const { file, project } = this.getFileAndProject(args); const output = (success: boolean, message: string) => this.doOutput({}, commandName, requestSeq, success, message); - const command = args.command as CodeActionCommand; // They should be sending back the command we sent them. + const command = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them. + project.getLanguageService().applyCodeActionCommand(file, command).then( - ({ successMessage }) => { output(/*success*/ true, successMessage); }, + result => { + output(/*success*/ true, isArray(result) ? result.map(res => res.successMessage).join(`${this.host.newLine}${this.host.newLine}`) : result.successMessage); + }, error => { output(/*success*/ false, error); }); } diff --git a/src/services/services.ts b/src/services/services.ts index 92c06055e8078..a28a8d4bc7d60 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1786,8 +1786,14 @@ namespace ts { }); } - function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise { - fileName = toPath(fileName, currentDirectory, getCanonicalFileName); + function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise; + function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise; + function applyCodeActionCommand(fileName: Path, action: CodeActionCommand | CodeActionCommand[]): Promise { + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(path, a))) : applySingleCodeActionCommand(path, action); + } + + function applySingleCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise { switch (action.type) { case "install package": return host.installPackage diff --git a/src/services/types.ts b/src/services/types.ts index 1ef1c39bc95d6..9b32a42ab4f1b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -290,6 +290,8 @@ namespace ts { getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 2b116eb1cd05c..5c30b14e8a8ba 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -3,6 +3,7 @@ interface PromiseConstructor { new (executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise; reject(reason: any): Promise; + all(values: (T | PromiseLike)[]): Promise; } /* @internal */ declare var Promise: PromiseConstructor; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 40e518afb8dca..ac6a76aa82830 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3946,6 +3946,8 @@ declare namespace ts { getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput; @@ -5239,6 +5241,7 @@ declare namespace ts.server.protocol { errorCodes?: number[]; } interface ApplyCodeActionCommandRequestArgs extends FileRequestArgs { + /** May also be an array of commands. */ command: {}; } /** diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index cef3b185583d7..7fa342e6847ff 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3946,6 +3946,8 @@ declare namespace ts { getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise; + applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput;