diff --git a/extensions/git-extended/src/commentsProvider.ts b/extensions/git-extended/src/commentsProvider.ts index 5814818ec88..f6372e122de 100644 --- a/extensions/git-extended/src/commentsProvider.ts +++ b/extensions/git-extended/src/commentsProvider.ts @@ -8,6 +8,14 @@ import * as vscode from 'vscode'; import * as _ from 'lodash'; import { Comment } from './common/models/comment'; +class PostCommentCommand { + public static readonly id = 'pr.postComment'; + + public static run(id: string, text: string) { + vscode.window.showInformationMessage(`posty! ${text}`); + } +} + export interface ICommentsProvider { provideComments(uri: vscode.Uri): Promise; } @@ -20,6 +28,8 @@ export class CommentsProvider implements vscode.CommentProvider { this.providers = new Map(); this._id = 0; vscode.workspace.registerCommentProvider(this); + + vscode.commands.registerCommand(PostCommentCommand.id, PostCommentCommand.run); } registerCommentProvider(provider: ICommentsProvider): number { @@ -51,7 +61,7 @@ export class CommentsProvider implements vscode.CommentProvider { } let sections = _.groupBy(matchingComments, comment => comment.position); - let ret = []; + let ret: vscode.CommentThread[] = []; for (let i in sections) { let comments = sections[i]; @@ -63,6 +73,7 @@ export class CommentsProvider implements vscode.CommentProvider { const newCommentEndPos = new vscode.Position(comment.diff_hunk_range.start + comment.diff_hunk_range.length - 1 - 1, 0); ret.push({ + threadId: comment.id, range, newCommentRange: new vscode.Range(newCommentStartPos, newCommentEndPos), comments: comments.map(comment => { @@ -71,7 +82,13 @@ export class CommentsProvider implements vscode.CommentProvider { userName: comment.user.login, gravatar: comment.user.avatar_url }; - }) + }), + actions: [ + { + command: PostCommentCommand.id, + title: 'Post' + } + ] }); } diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 9ea81491be4..6fa682e351d 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -27,11 +27,6 @@ ], "contributes": { "commands": [ - { - "command": "unicorn", - "title": "🦄 unicorn", - "category": "Markdown" - }, { "command": "markdown.showPreview", "title": "%markdown.preview.title%", diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index aa2032733f5..fd0a1f3812d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -939,9 +939,11 @@ export interface Command { export interface CommentThread { + readonly threadId: string; readonly range: IRange; readonly newCommentRange: IRange; readonly comments: Comment[]; + readonly actions: Command[]; } export interface Comment { diff --git a/src/vs/editor/contrib/review/review.ts b/src/vs/editor/contrib/review/review.ts index 09a85c685b3..6663faa6bfa 100644 --- a/src/vs/editor/contrib/review/review.ts +++ b/src/vs/editor/contrib/review/review.ts @@ -28,6 +28,7 @@ import { registerThemingParticipant, ITheme, IThemeService } from 'vs/platform/t import { peekViewEditorBackground, peekViewBorder, } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { Color } from 'vs/base/common/color'; import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export const ctxReviewPanelVisible = new RawContextKey('reviewPanelVisible', false); export const ID = 'editor.contrib.review'; @@ -72,7 +73,10 @@ export class ReviewZoneWidget extends ZoneWidget { private _resizeObserver: any; private _comments: modes.Comment[]; - constructor(@IThemeService private themeService: IThemeService, + constructor( + private readonly themeService: IThemeService, + private readonly commandService: ICommandService, + editor: ICodeEditor, options: IOptions = {}, comments: modes.Comment[]) { super(editor, options); this._resizeObserver = null; @@ -125,7 +129,8 @@ export class ReviewZoneWidget extends ZoneWidget { } - display(comments: modes.Comment[], lineNumber: number) { + display(commentThread: modes.CommentThread, lineNumber: number) { + const comments = commentThread.comments; this.show({ lineNumber: lineNumber, column: 1 }, 2); this._bodyElement.style.display = 'none'; @@ -161,7 +166,19 @@ export class ReviewZoneWidget extends ZoneWidget { body.appendChild(renderMarkdown(md)); this._bodyElement.appendChild(singleCommentContainer); } - // this._domNode.appendChild(document.createElement('textarea')); + + const textArea = document.createElement('textarea'); + this._bodyElement.appendChild(textArea); + + for (const action of commentThread.actions) { + const button = document.createElement('button'); + button.onclick = () => { + this.commandService.executeCommand(action.id, commentThread.threadId, textArea.value); + }; + button.textContent = action.title; + this._bodyElement.appendChild(button); + } + this._resizeObserver = new ResizeObserver(entries => { if (entries[0].target === this._bodyElement) { const lineHeight = this.editor.getConfiguration().lineHeight; @@ -207,7 +224,8 @@ export class ReviewController implements IEditorContribution { constructor( editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, - @IThemeService private themeService: IThemeService + @IThemeService private themeService: IThemeService, + @ICommandService private commandService: ICommandService, ) { this.editor = editor; this.globalToDispose = []; @@ -307,11 +325,11 @@ export class ReviewController implements IEditorContribution { return; } - let comments = this.getComments(lineNumber); - if (comments && comments.length) { + let thread = this.getCommentThread(lineNumber); + if (thread && thread.comments.length) { this._reviewPanelVisible.set(true); - this._zoneWidget = new ReviewZoneWidget(this.themeService, this.editor, {}, comments); - this._zoneWidget.display(this.getComments(lineNumber), lineNumber); + this._zoneWidget = new ReviewZoneWidget(this.themeService, this.commandService, this.editor, {}, thread.comments); + this._zoneWidget.display(this.getCommentThread(lineNumber), lineNumber); } } @@ -371,14 +389,14 @@ export class ReviewController implements IEditorContribution { return true; } - getComments(line: number): modes.Comment[] { + getCommentThread(line: number): modes.CommentThread | undefined { for (let i = 0; i < this._commentThreads.length; i++) { if (this._commentThreads[i].range.startLineNumber === line) { - return this._commentThreads[i].comments; + return this._commentThreads[i]; } } - return []; + return undefined; } setComments(commentThreads: modes.CommentThread[]): void { @@ -396,8 +414,8 @@ export class ReviewController implements IEditorContribution { }); this._commentThreads.forEach(thread => { - let zoneWidget = new ReviewZoneWidget(this.themeService, this.editor, {}, thread.comments); - zoneWidget.display(this.getComments(thread.range.startLineNumber), thread.range.startLineNumber); + let zoneWidget = new ReviewZoneWidget(this.themeService, this.commandService, this.editor, {}, thread.comments); + zoneWidget.display(this.getCommentThread(thread.range.startLineNumber), thread.range.startLineNumber); this._zoneWidgets.push(zoneWidget); }); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 29eb8947e00..23bee5813dc 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5029,9 +5029,11 @@ declare namespace monaco.languages { } export interface CommentThread { + readonly threadId: string; readonly range: IRange; readonly newCommentRange: IRange; readonly comments: Comment[]; + readonly actions: Command[]; } export interface Comment { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 5e679fd39e0..e36d9716ee2 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -771,9 +771,11 @@ declare module 'vscode' { //#endregion interface CommentThread { + threadId: string; range: Range; newCommentRange: Range; comments: Comment[]; + actions?: Command[]; } interface Comment { diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 2136bd733e6..fb249f99481 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -120,7 +120,7 @@ export function createApiFactory( const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol)); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress))); - const exthostCommentProviders = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostDocuments)); + const exthostCommentProviders = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands.converter, extHostDocuments)); // Check that no named customers are missing const expected: ProxyIdentifier[] = Object.keys(ExtHostContext).map((key) => ExtHostContext[key]); diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index 355e56cfe6b..a35c53e13a1 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -11,11 +11,11 @@ import URI, { UriComponents } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import * as modes from 'vs/editor/common/modes'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; +import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters'; import * as vscode from 'vscode'; import { flatten } from '../../../base/common/arrays'; import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol'; - -import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters'; +import { CommandsConverter } from './extHostCommands'; export class ExtHostComments implements ExtHostCommentsShape { @@ -27,6 +27,7 @@ export class ExtHostComments implements ExtHostCommentsShape { constructor( mainContext: IMainContext, + private readonly _commandsConverter: CommandsConverter, private readonly _documents: ExtHostDocuments, ) { this._proxy = mainContext.getProxy(MainContext.MainThreadComments); @@ -58,15 +59,17 @@ export class ExtHostComments implements ExtHostCommentsShape { return TPromise.join(allProviderResults); }) .then(flatten) - .then(comments => comments.map(convertCommentThread)); + .then(comments => comments.map(x => convertCommentThread(x, this._commandsConverter))); } } -function convertCommentThread(vscodeCommentThread: vscode.CommentThread): modes.CommentThread { +function convertCommentThread(vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread { return { + threadId: vscodeCommentThread.threadId, range: extHostTypeConverter.fromRange(vscodeCommentThread.range), newCommentRange: extHostTypeConverter.fromRange(vscodeCommentThread.newCommentRange), - comments: vscodeCommentThread.comments.map(convertComment) + comments: vscodeCommentThread.comments.map(convertComment), + actions: vscodeCommentThread.actions.map(commandsConverter.toInternal) }; }