diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index e3287aeb7ed..890b6b14584 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1268,8 +1268,10 @@ export interface CommentThread2 { collapsibleState?: CommentThreadCollapsibleState; input: CommentInput; onDidChangeInput: Event; - acceptInputCommands: Command[]; - onDidChangeAcceptInputCommands: Event; + acceptInputCommand?: Command; + additionalCommands: Command[]; + onDidChangeAcceptInputCommand: Event; + onDidChangeAdditionalCommands: Event; onDidChangeRange: Event; onDidChangeLabel: Event; onDidChangeCollasibleState: Event; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6d351bd7d5b..9bd5eb6dbbe 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -771,7 +771,18 @@ declare module 'vscode' { * The ordered comments of the thread. */ comments: Comment[]; - acceptInputCommands?: Command[]; + + /** + * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. + * It will be executed when users submit the comment from keyboard shortcut. + * This action is disabled when the comment editor is empty. + */ + acceptInputCommand?: Command; + + /** + * `additionalCommands` are the secondary actions rendered on Comment Widget. + */ + additionalCommands?: Command[]; /** * Whether the thread should be collapsed or expanded when opening the document. Defaults to Collapsed. diff --git a/src/vs/workbench/api/electron-browser/mainThreadComments.ts b/src/vs/workbench/api/electron-browser/mainThreadComments.ts index 00b060cab7c..7d35473b1e9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadComments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadComments.ts @@ -121,17 +121,29 @@ export class MainThreadCommentThread implements modes.CommentThread2 { private _onDidChangeComments = new Emitter(); get onDidChangeComments(): Event { return this._onDidChangeComments.event; } - set acceptInputCommands(newCommands: modes.Command[]) { - this._acceptInputCommands = newCommands; - this._onDidChangeAcceptInputCommands.fire(this._acceptInputCommands); + set acceptInputCommand(newCommand: modes.Command) { + this._acceptInputCommand = newCommand; + this._onDidChangeAcceptInputCommand.fire(this._acceptInputCommand); } - get acceptInputCommands(): modes.Command[] { - return this._acceptInputCommands; + get acceptInputCommand(): modes.Command { + return this._acceptInputCommand; } - private _onDidChangeAcceptInputCommands = new Emitter(); - get onDidChangeAcceptInputCommands(): Event { return this._onDidChangeAcceptInputCommands.event; } + private _onDidChangeAcceptInputCommand = new Emitter(); + get onDidChangeAcceptInputCommand(): Event { return this._onDidChangeAcceptInputCommand.event; } + + set additionalCommands(newCommands: modes.Command[]) { + this._additionalCommands = newCommands; + this._onDidChangeAdditionalCommands.fire(this._additionalCommands); + } + + get additionalCommands(): modes.Command[] { + return this._additionalCommands; + } + + private _onDidChangeAdditionalCommands = new Emitter(); + get onDidChangeAdditionalCommands(): Event { return this._onDidChangeAdditionalCommands.event; } set range(range: IRange) { this._range = range; @@ -165,7 +177,8 @@ export class MainThreadCommentThread implements modes.CommentThread2 { public resource: string, private _range: IRange, private _comments: modes.Comment[], - private _acceptInputCommands: modes.Command[], + private _acceptInputCommand: modes.Command | undefined, + private _additionalCommands: modes.Command[], private _collapsibleState: modes.CommentThreadCollapsibleState ) { @@ -210,7 +223,7 @@ export class MainThreadCommentController { private readonly _label: string ) { } - createCommentThread(commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], commands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 { + createCommentThread(commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 { let thread = new MainThreadCommentThread( commentThreadHandle, this, @@ -219,7 +232,8 @@ export class MainThreadCommentController { URI.revive(resource).toString(), range, comments, - commands, + acceptInputCommand, + additionalCommands, collapseState ); @@ -260,9 +274,14 @@ export class MainThreadCommentController { }); } - updateAcceptInputCommands(commentThreadHandle: number, acceptInputCommands: modes.Command[]) { + updateAcceptInputCommand(commentThreadHandle: number, acceptInputCommand: modes.Command) { let thread = this._threads.get(commentThreadHandle); - thread.acceptInputCommands = acceptInputCommands; + thread.acceptInputCommand = acceptInputCommand; + } + + updateAdditionalCommands(commentThreadHandle: number, additionalCommands: modes.Command[]) { + let thread = this._threads.get(commentThreadHandle); + thread.additionalCommands = additionalCommands; } updateCollapsibleState(commentThreadHandle: number, collapseState: modes.CommentThreadCollapsibleState) { @@ -392,14 +411,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments this._commentService.setWorkspaceComments(String(handle), []); } - $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], commands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 | undefined { + $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 | undefined { let provider = this._commentControllers.get(handle); if (!provider) { return undefined; } - return provider.createCommentThread(commentThreadHandle, threadId, resource, range, comments, commands, collapseState); + return provider.createCommentThread(commentThreadHandle, threadId, resource, range, comments, acceptInputCommand, additionalCommands, collapseState); } $deleteCommentThread(handle: number, commentThreadHandle: number) { @@ -432,14 +451,24 @@ export class MainThreadComments extends Disposable implements MainThreadComments provider.updateInput(input); } - $updateCommentThreadCommands(handle: number, commentThreadHandle: number, acceptInputCommands: modes.Command[]) { + $updateCommentThreadAcceptInputCommand(handle: number, commentThreadHandle: number, acceptInputCommand: modes.Command) { let provider = this._commentControllers.get(handle); if (!provider) { return; } - provider.updateAcceptInputCommands(commentThreadHandle, acceptInputCommands); + provider.updateAcceptInputCommand(commentThreadHandle, acceptInputCommand); + } + + $updateCommentThreadAdditionalCommands(handle: number, commentThreadHandle: number, additionalCommands: modes.Command[]) { + let provider = this._commentControllers.get(handle); + + if (!provider) { + return; + } + + provider.updateAdditionalCommands(commentThreadHandle, additionalCommands); } $updateCommentThreadCollapsibleState(handle: number, commentThreadHandle: number, collapseState: modes.CommentThreadCollapsibleState): void { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index a6307f6bc46..8be2c244442 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -120,11 +120,12 @@ export interface CommentProviderFeatures { export interface MainThreadCommentsShape extends IDisposable { $registerCommentController(handle: number, id: string, label: string): void; - $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], commands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 | undefined; + $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], acceptInputCommand: modes.Command, additionalCommands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 | undefined; $deleteCommentThread(handle: number, commentThreadHandle: number): void; $updateComments(handle: number, commentThreadHandle: number, comments: modes.Comment[]): void; $setInputValue(handle: number, input: string): void; - $updateCommentThreadCommands(handle: number, commentThreadHandle: number, acceptInputCommands: modes.Command[]): void; + $updateCommentThreadAcceptInputCommand(handle: number, commentThreadHandle: number, acceptInputCommand: modes.Command): void; + $updateCommentThreadAdditionalCommands(handle: number, commentThreadHandle: number, additionalCommands: modes.Command[]): void; $updateCommentThreadCollapsibleState(handle: number, commentThreadHandle: number, collapseState: modes.CommentThreadCollapsibleState): void; $updateCommentThreadRange(handle: number, commentThreadHandle: number, range: IRange): void; $updateCommentThreadLabel(handle: number, commentThreadHandle: number, label: string): void; diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index 6b2f275329e..f2741c012c1 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -330,16 +330,28 @@ export class ExtHostCommentThread implements vscode.CommentThread { this._comments = newComments; } - private _acceptInputCommands: vscode.Command[] = []; - get acceptInputCommands(): vscode.Command[] { - return this._acceptInputCommands; + private _acceptInputCommand: vscode.Command; + get acceptInputCommand(): vscode.Command { + return this._acceptInputCommand; } - set acceptInputCommands(replyCommands: vscode.Command[]) { - this._acceptInputCommands = replyCommands; + set acceptInputCommand(acceptInputCommand: vscode.Command) { + this._acceptInputCommand = acceptInputCommand; - const internals = replyCommands.map(this._commandsConverter.toInternal.bind(this._commandsConverter)); - this._proxy.$updateCommentThreadCommands(this._commentControlHandle, this.handle, internals); + const internal = this._commandsConverter.toInternal(acceptInputCommand); + this._proxy.$updateCommentThreadAcceptInputCommand(this._commentControlHandle, this.handle, internal); + } + + private _additionalCommands: vscode.Command[] = []; + get additionalCommands(): vscode.Command[] { + return this._additionalCommands; + } + + set additionalCommands(additionalCommands: vscode.Command[]) { + this._additionalCommands = additionalCommands; + + const internals = additionalCommands.map(this._commandsConverter.toInternal.bind(this._commandsConverter)); + this._proxy.$updateCommentThreadAdditionalCommands(this._commentControlHandle, this.handle, internals); } private _collapseState?: vscode.CommentThreadCollapsibleState; @@ -368,7 +380,8 @@ export class ExtHostCommentThread implements vscode.CommentThread { this._resource, extHostTypeConverter.Range.from(this._range), this._comments.map(comment => { return convertToModeComment(comment, this._commandsConverter); }), - this._acceptInputCommands ? this._acceptInputCommands.map(this._commandsConverter.toInternal.bind(this._commandsConverter)) : [], + this._acceptInputCommand ? this._commandsConverter.toInternal(this._acceptInputCommand) : undefined, + this._additionalCommands ? this._additionalCommands.map(this._commandsConverter.toInternal.bind(this._commandsConverter)) : [], this._collapseState ); } diff --git a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts index 1e98be9ea34..dcaab6107d8 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts @@ -417,7 +417,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) { this.createCommentWidgetActions2(this._formActions, model); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommands(_ => { + this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => { + dom.clearNode(this._formActions); + this.createCommentWidgetActions2(this._formActions, model); + })); + + this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => { dom.clearNode(this._formActions); this.createCommentWidgetActions2(this._formActions, model); })); @@ -583,7 +588,11 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget private createCommentWidgetActions2(container: HTMLElement, model: ITextModel) { let commentThread = this._commentThread as modes.CommentThread2; - commentThread.acceptInputCommands.reverse().forEach(command => { + [commentThread.acceptInputCommand, ...commentThread.additionalCommands.reverse()].forEach(command => { + if (!command) { + return; + } + const button = new Button(container); this._disposables.push(attachButtonStyler(button, this.themeService)); @@ -638,7 +647,24 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget async submitComment(): Promise { const activeComment = this.getActiveComment(); if (activeComment instanceof ReviewZoneWidget) { - this.createComment(); + if ((this._commentThread as modes.CommentThread2).commentThreadHandle) { + let commentThread = this._commentThread as modes.CommentThread2; + + if (commentThread.acceptInputCommand) { + commentThread.input = { + uri: this._commentEditor.getModel().uri, + value: this._commentEditor.getValue() + }; + this.commentService.setActiveCommentThread(this._commentThread); + let commandId = commentThread.acceptInputCommand.id; + let args = commentThread.acceptInputCommand.arguments || []; + + await this.commandService.executeCommand(commandId, ...args); + return; + } + } else { + this.createComment(); + } } if (activeComment instanceof CommentNode) {