From 11d48f122e66ad8a4e7fb35ea21434cfa1f23824 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 27 Nov 2018 16:02:39 -0800 Subject: [PATCH] first cut --- src/vs/editor/common/modes.ts | 17 +++++++++ src/vs/vscode.proposed.d.ts | 15 ++++++++ .../electron-browser/mainThreadComments.ts | 16 +++++--- src/vs/workbench/api/node/extHost.protocol.ts | 9 ++++- src/vs/workbench/api/node/extHostComments.ts | 16 +++++++- .../electron-browser/commentService.ts | 37 ++++++++++++++++++- .../electron-browser/commentThreadWidget.ts | 24 ++++++++++++ .../commentsEditorContribution.ts | 18 +++++++-- 8 files changed, 138 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index bb1af92f90d..3b5975f3800 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1145,6 +1145,16 @@ export interface CommentInfo { threads: CommentThread[]; commentingRanges?: IRange[]; reply?: Command; + draftMode: DraftMode; +} + +/** + * @internal + */ +export enum DraftMode { + NotSupported, + InDraft, + NotInDraft } /** @@ -1223,6 +1233,13 @@ export interface DocumentCommentProvider { replyToCommentThread(resource: URI, range: Range, thread: CommentThread, text: string, token: CancellationToken): Promise; editComment(resource: URI, comment: Comment, text: string, token: CancellationToken): Promise; deleteComment(resource: URI, comment: Comment, token: CancellationToken): Promise; + startDraft?(token: CancellationToken): Promise; + deleteDraft?(token: CancellationToken): Promise; + finishDraft?(token: CancellationToken): Promise; + + startDraftLabel?: string; + deleteDraftLabel?: string; + finishDraftLabel?: string; onDidChangeCommentThreads(): Event; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 90eaa4b4f88..72a399991b5 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -809,6 +809,11 @@ declare module 'vscode' { * The ranges of the document which support commenting. */ commentingRanges?: Range[]; + + /** + * If it's in draft mode or not + */ + inDraftMode?: boolean; } export enum CommentThreadCollapsibleState { @@ -903,6 +908,8 @@ declare module 'vscode' { * The command to be executed if the comment is selected in the Comments Panel */ command?: Command; + + isDraft?: boolean; } export interface CommentThreadChangedEvent { @@ -948,6 +955,14 @@ declare module 'vscode' { */ deleteComment?(document: TextDocument, comment: Comment, token: CancellationToken): Promise; + startDraft?(token: CancellationToken): Promise; + deleteDraft?(token: CancellationToken): Promise; + finishDraft?(token: CancellationToken): Promise; + + startDraftLabel?: string; + deleteDraftLabel?: string; + finishDraftLabel?: string; + /** * Notify of updates to comment threads. */ diff --git a/src/vs/workbench/api/electron-browser/mainThreadComments.ts b/src/vs/workbench/api/electron-browser/mainThreadComments.ts index 347b9b6d014..ac3eaa4f631 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadComments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadComments.ts @@ -9,7 +9,7 @@ import * as modes from 'vs/editor/common/modes'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { keys } from 'vs/base/common/map'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../node/extHost.protocol'; +import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentProviderFeatures } from '../node/extHost.protocol'; import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService'; import { COMMENTS_PANEL_ID } from 'vs/workbench/parts/comments/electron-browser/commentsPanel'; @@ -18,13 +18,18 @@ import { URI } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { generateUuid } from 'vs/base/common/uuid'; -export class ExtensionCommentProviderHandler implements modes.DocumentCommentProvider { +export class MainThreadDocumentCommentProvider implements modes.DocumentCommentProvider { private _proxy: ExtHostCommentsShape; private _handle: number; + private _features: CommentProviderFeatures; + get startDraftLabel(): string { return this._features.startDraftLabel; } + get deleteDraftLabel(): string { return this._features.deleteDraftLabel; } + get finishDraftLabel(): string { return this._features.finishDraftLabel; } - constructor(proxy: ExtHostCommentsShape, handle: number) { + constructor(proxy: ExtHostCommentsShape, handle: number, features: CommentProviderFeatures) { this._proxy = proxy; this._handle = handle; + this._features = features; } async provideDocumentComments(uri, token) { @@ -49,6 +54,7 @@ export class ExtensionCommentProviderHandler implements modes.DocumentCommentPro onDidChangeCommentThreads = null; } + @extHostNamedCustomer(MainContext.MainThreadComments) export class MainThreadComments extends Disposable implements MainThreadCommentsShape { private _disposables: IDisposable[]; @@ -71,9 +77,9 @@ export class MainThreadComments extends Disposable implements MainThreadComments this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments); } - $registerDocumentCommentProvider(handle: number): void { + $registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void { this._documentProviders.set(handle, undefined); - const handler = new ExtensionCommentProviderHandler(this._proxy, handle); + const handler = new MainThreadDocumentCommentProvider(this._proxy, handle, features); const providerId = generateUuid(); this._handlers.set(handle, providerId); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 39aff9b5035..21e8605cc59 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -102,8 +102,14 @@ export interface MainThreadCommandsShape extends IDisposable { $getCommands(): Thenable; } +export interface CommentProviderFeatures { + startDraftLabel?: string; + deleteDraftLabel?: string; + finishDraftLabel?: string; +} + export interface MainThreadCommentsShape extends IDisposable { - $registerDocumentCommentProvider(handle: number): void; + $registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void; $unregisterDocumentCommentProvider(handle: number): void; $registerWorkspaceCommentProvider(handle: number, extensionId: string): void; $unregisterWorkspaceCommentProvider(handle: number): void; @@ -1031,6 +1037,7 @@ export interface ExtHostCommentsShape { $replyToCommentThread(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): Thenable; $editComment(handle: number, document: UriComponents, comment: modes.Comment, text: string): Thenable; $deleteComment(handle: number, document: UriComponents, comment: modes.Comment): Thenable; + $getStartDraftLabel(handle: number): Thenable; $provideWorkspaceComments(handle: number): Thenable; } diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index cbd48c1a557..1bc9f7b92e3 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -52,7 +52,11 @@ export class ExtHostComments implements ExtHostCommentsShape { ): vscode.Disposable { const handle = ExtHostComments.handlePool++; this._documentProviders.set(handle, provider); - this._proxy.$registerDocumentCommentProvider(handle); + this._proxy.$registerDocumentCommentProvider(handle, { + startDraftLabel: provider.startDraftLabel, + deleteDraftLabel: provider.deleteDraftLabel, + finishDraftLabel: provider.finishDraftLabel + }); this.registerListeners(handle, provider); return { @@ -117,6 +121,13 @@ export class ExtHostComments implements ExtHostCommentsShape { }); } + $getStartDraftLabel(handle: number): Thenable { + const provider = this._documentProviders.get(handle); + return asThenable(() => { + return provider.startDraftLabel; + }); + } + $provideDocumentComments(handle: number, uri: UriComponents): Thenable { const data = this._documents.getDocumentData(URI.revive(uri)); if (!data || !data.document) { @@ -157,7 +168,8 @@ export class ExtHostComments implements ExtHostCommentsShape { function convertCommentInfo(owner: number, provider: vscode.DocumentCommentProvider, vscodeCommentInfo: vscode.CommentInfo, commandsConverter: CommandsConverter): modes.CommentInfo { return { threads: vscodeCommentInfo.threads.map(x => convertToCommentThread(provider, x, commandsConverter)), - commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : [] + commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : [], + draftMode: provider.startDraft ? (vscodeCommentInfo.inDraftMode ? modes.DraftMode.InDraft : modes.DraftMode.NotInDraft) : modes.DraftMode.NotSupported }; } diff --git a/src/vs/workbench/parts/comments/electron-browser/commentService.ts b/src/vs/workbench/parts/comments/electron-browser/commentService.ts index 8b937d8ae0d..a17ee9eb944 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentService.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentService.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { Range } from 'vs/editor/common/core/range'; import { keys } from 'vs/base/common/map'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ExtensionCommentProviderHandler } from 'vs/workbench/api/electron-browser/mainThreadComments'; +import { MainThreadDocumentCommentProvider } from 'vs/workbench/api/electron-browser/mainThreadComments'; import { assign } from 'vs/base/common/objects'; import { ICommentThreadChangedEvent } from 'vs/workbench/parts/comments/common/commentModel'; @@ -41,7 +41,7 @@ export interface ICommentService { setDocumentComments(resource: URI, commentInfos: ICommentInfo[]): void; setWorkspaceComments(owner: string, commentsByResource: CommentThread[]): void; removeWorkspaceComments(owner: string): void; - registerDataProvider(owner: string, commentProvider: ExtensionCommentProviderHandler): void; + registerDataProvider(owner: string, commentProvider: MainThreadDocumentCommentProvider): void; unregisterDataProvider(owner: string): void; updateComments(ownerId: string, event: CommentThreadChangedEvent): void; createNewCommentThread(owner: string, resource: URI, range: Range, text: string): Promise; @@ -49,6 +49,9 @@ export interface ICommentService { editComment(owner: string, resource: URI, comment: Comment, text: string): Promise; deleteComment(owner: string, resource: URI, comment: Comment): Promise; getComments(resource: URI): Promise; + getStartDraftLabel(owner: string): string; + getDeleteDraftLabel(owner: string): string; + getFinishDraftLabel(owner: string): string; } export class CommentService extends Disposable implements ICommentService { @@ -142,6 +145,36 @@ export class CommentService extends Disposable implements ICommentService { return Promise.resolve(false); } + getStartDraftLabel(owner: string): string | null { + const commentProvider = this._commentProviders.get(owner); + + if (commentProvider) { + return commentProvider.startDraftLabel; + } + + return null; + } + + getDeleteDraftLabel(owner: string): string { + const commentProvider = this._commentProviders.get(owner); + + if (commentProvider) { + return commentProvider.deleteDraftLabel; + } + + return null; + } + + getFinishDraftLabel(owner: string): string { + const commentProvider = this._commentProviders.get(owner); + + if (commentProvider) { + return commentProvider.finishDraftLabel; + } + + return null; + } + getComments(resource: URI): Promise { const result: Promise[] = []; for (const owner of keys(this._commentProviders)) { diff --git a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts index ebc848b4e29..cb444aba6af 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts @@ -65,6 +65,7 @@ export class ReviewZoneWidget extends ZoneWidget { private _commentGlyph: CommentGlyphWidget; private _owner: string; private _pendingComment: string; + private _draftMode: modes.DraftMode; private _localToDispose: IDisposable[]; private _globalToDispose: IDisposable[]; private _markdownRenderer: MarkdownRenderer; @@ -91,6 +92,7 @@ export class ReviewZoneWidget extends ZoneWidget { owner: string, commentThread: modes.CommentThread, pendingComment: string, + draftMode: modes.DraftMode, options: IOptions = {} ) { super(editor, options); @@ -98,6 +100,7 @@ export class ReviewZoneWidget extends ZoneWidget { this._owner = owner; this._commentThread = commentThread; this._pendingComment = pendingComment; + this._draftMode = draftMode; this._isCollapsed = commentThread.collapsibleState !== modes.CommentThreadCollapsibleState.Expanded; this._globalToDispose = []; this._localToDispose = []; @@ -348,6 +351,27 @@ export class ReviewZoneWidget extends ZoneWidget { this.createComment(lineNumber); }); + if (this._draftMode !== modes.DraftMode.NotSupported) { + // render draft button + const draftButton = new Button(formActions); + attachButtonStyler(draftButton, this.themeService); + draftButton.label = this.commentService.getStartDraftLabel(this._owner); + + draftButton.enabled = model.getValueLength() > 0; + this._localToDispose.push(this._commentEditor.onDidChangeModelContent(_ => { + if (this._commentEditor.getValue()) { + draftButton.enabled = true; + } else { + draftButton.enabled = false; + } + })); + + // draftButton.onDidClick(async () => { + // let lineNumber = this._commentGlyph.getPosition().position.lineNumber; + // this.createComment(lineNumber); + // }); + } + this._resizeObserver = new MutationObserver(this._refresh.bind(this)); this._resizeObserver.observe(this._bodyElement, { diff --git a/src/vs/workbench/parts/comments/electron-browser/commentsEditorContribution.ts b/src/vs/workbench/parts/comments/electron-browser/commentsEditorContribution.ts index 6d7ef69d25f..1ed89785369 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentsEditorContribution.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentsEditorContribution.ts @@ -375,10 +375,13 @@ export class ReviewController implements IEditorContribution { return; } - if (!this._commentInfos.some(info => info.owner === e.owner)) { + let commentInfo = this._commentInfos.filter(info => info.owner === e.owner); + if (!commentInfo || !commentInfo.length) { return; } + let draftMode = commentInfo[0].draftMode; + let added = e.added.filter(thread => thread.resource.toString() === editorURI.toString()); let removed = e.removed.filter(thread => thread.resource.toString() === editorURI.toString()); let changed = e.changed.filter(thread => thread.resource.toString() === editorURI.toString()); @@ -400,7 +403,7 @@ export class ReviewController implements IEditorContribution { } }); added.forEach(thread => { - let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.dialogService, this.notificationService, this.editor, e.owner, thread, null, {}); + let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.dialogService, this.notificationService, this.editor, e.owner, thread, null, draftMode, {}); zoneWidget.display(thread.range.startLineNumber, this._commentingRangeDecorator.commentsOptions); this._commentWidgets.push(zoneWidget); this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread); @@ -416,6 +419,13 @@ export class ReviewController implements IEditorContribution { return; } + let commentInfo = this._commentInfos.filter(info => info.owner === ownerId); + if (!commentInfo || !commentInfo.length) { + return; + } + + let draftMode = commentInfo[0].draftMode; + // add new comment this._reviewPanelVisible.set(true); this._newCommentWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.dialogService, this.notificationService, this.editor, ownerId, { @@ -430,7 +440,7 @@ export class ReviewController implements IEditorContribution { }, reply: replyCommand, collapsibleState: CommentThreadCollapsibleState.Expanded, - }, pendingComment, {}); + }, pendingComment, draftMode, {}); this.localToDispose.push(this._newCommentWidget.onDidClose(e => { this._newCommentWidget = null; @@ -559,7 +569,7 @@ export class ReviewController implements IEditorContribution { thread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded; } - let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.dialogService, this.notificationService, this.editor, info.owner, thread, pendingComment, {}); + let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.dialogService, this.notificationService, this.editor, info.owner, thread, pendingComment, info.draftMode, {}); zoneWidget.display(thread.range.startLineNumber, this._commentingRangeDecorator.commentsOptions); this._commentWidgets.push(zoneWidget); }); -- GitLab