diff --git a/src/vs/workbench/api/electron-browser/mainThreadComments.ts b/src/vs/workbench/api/electron-browser/mainThreadComments.ts index 48c07b635e08c..c8d3eca7a9c1a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadComments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadComments.ts @@ -53,7 +53,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments const outerEditorURI = outerEditor.getModel().uri; this.provideDocumentComments(outerEditorURI).then(commentInfos => { - this._commentService.setComments(outerEditorURI, commentInfos.filter(info => info !== null)); + this._commentService.setDocumentComments(outerEditorURI, commentInfos.filter(info => info !== null)); }); })); } @@ -84,7 +84,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments this._panelService.openPanel(COMMENTS_PANEL_ID); this._proxy.$provideWorkspaceComments(handle).then(commentThreads => { if (commentThreads) { - this._commentService.setAllComments(commentThreads); + this._commentService.setWorkspaceComments(handle, commentThreads); } }); } @@ -96,8 +96,10 @@ export class MainThreadComments extends Disposable implements MainThreadComments $unregisterWorkspaceCommentProvider(handle: number): void { this._workspaceProviders.delete(handle); - this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, false); - this._commentService.removeAllComments(); + if (this._workspaceProviders.size === 0) { + this._panelService.setPanelEnablement(COMMENTS_PANEL_ID, false); + } + this._commentService.removeWorkspaceComments(handle); } $onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) { diff --git a/src/vs/workbench/parts/comments/common/commentModel.ts b/src/vs/workbench/parts/comments/common/commentModel.ts index 2cf98fa3dcbda..4fb5b74843cef 100644 --- a/src/vs/workbench/parts/comments/common/commentModel.ts +++ b/src/vs/workbench/parts/comments/common/commentModel.ts @@ -8,8 +8,9 @@ import URI from 'vs/base/common/uri'; import { IRange } from 'vs/editor/common/core/range'; import { Comment, CommentThread, CommentThreadChangedEvent } from 'vs/editor/common/modes'; -import { groupBy, firstIndex } from 'vs/base/common/arrays'; +import { groupBy, firstIndex, flatten } from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; +import { values } from 'vs/base/common/map'; export class CommentNode { threadId: string; @@ -54,21 +55,26 @@ export class ResourceWithCommentThreads { export class CommentsModel { resourceCommentThreads: ResourceWithCommentThreads[]; + commentThreadsMap: Map; constructor() { this.resourceCommentThreads = []; + this.commentThreadsMap = new Map(); } - public setCommentThreads(commentThreads: CommentThread[]): void { - this.resourceCommentThreads = []; - this.addCommentThreads(commentThreads); + public setCommentThreads(owner: number, commentThreads: CommentThread[]): void { + this.commentThreadsMap.set(owner, this.groupByResource(commentThreads)); + this.resourceCommentThreads = flatten(values(this.commentThreadsMap)); } public updateCommentThreads(event: CommentThreadChangedEvent): void { - event.removed.forEach(thread => { + const { owner, removed, changed, added } = event; + let threadsForOwner = this.commentThreadsMap.get(owner); + + removed.forEach(thread => { // Find resource that has the comment thread - const matchingResourceIndex = firstIndex(this.resourceCommentThreads, (resourceData) => resourceData.id === thread.resource); - const matchingResourceData = this.resourceCommentThreads[matchingResourceIndex]; + const matchingResourceIndex = firstIndex(threadsForOwner, (resourceData) => resourceData.id === thread.resource); + const matchingResourceData = threadsForOwner[matchingResourceIndex]; // Find comment node on resource that is that thread and remove it const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId); @@ -76,21 +82,24 @@ export class CommentsModel { // If the comment thread was the last thread for a resource, remove that resource from the list if (matchingResourceData.commentThreads.length === 0) { - this.resourceCommentThreads.splice(matchingResourceIndex, 1); + threadsForOwner.splice(matchingResourceIndex, 1); } }); - event.changed.forEach(thread => { + changed.forEach(thread => { // Find resource that has the comment thread - const matchingResourceIndex = firstIndex(this.resourceCommentThreads, (resourceData) => resourceData.id === thread.resource); - const matchingResourceData = this.resourceCommentThreads[matchingResourceIndex]; + const matchingResourceIndex = firstIndex(threadsForOwner, (resourceData) => resourceData.id === thread.resource); + const matchingResourceData = threadsForOwner[matchingResourceIndex]; // Find comment node on resource that is that thread and replace it const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId); matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread); }); - this.addCommentThreads(event.added); + threadsForOwner = threadsForOwner.concat(this.groupByResource(added)); + + this.commentThreadsMap.set(owner, threadsForOwner); + this.resourceCommentThreads = flatten(values(this.commentThreadsMap)); } public hasCommentThreads(): boolean { @@ -105,15 +114,18 @@ export class CommentsModel { } } - private addCommentThreads(commentThreads: CommentThread[]): void { + private groupByResource(commentThreads: CommentThread[]): ResourceWithCommentThreads[] { + const resourceCommentThreads = []; const commentThreadsByResource = new Map(); for (const group of groupBy(commentThreads, CommentsModel._compareURIs)) { commentThreadsByResource.set(group[0].resource, new ResourceWithCommentThreads(URI.parse(group[0].resource), group)); } commentThreadsByResource.forEach((v, i, m) => { - this.resourceCommentThreads.push(v); + resourceCommentThreads.push(v); }); + + return resourceCommentThreads; } private static _compareURIs(a: CommentThread, b: CommentThread) { diff --git a/src/vs/workbench/parts/comments/electron-browser/commentService.ts b/src/vs/workbench/parts/comments/electron-browser/commentService.ts index 427fbb6f33854..80aa7b9359e7b 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentService.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentService.ts @@ -22,20 +22,25 @@ export interface IResourceCommentThreadEvent { commentInfos: CommentInfo[]; } +export interface IWorkspaceCommentThreadsEvent { + ownerId: number; + commentThreads: CommentThread[]; +} + export interface ICommentService { _serviceBrand: any; readonly onDidSetResourceCommentInfos: Event; - readonly onDidSetAllCommentThreads: Event; + readonly onDidSetAllCommentThreads: Event; readonly onDidUpdateCommentThreads: Event; readonly onDidSetDataProvider: Event; readonly onDidDeleteDataProvider: Event; - setComments(resource: URI, commentInfos: CommentInfo[]): void; - setAllComments(commentsByResource: CommentThread[]): void; - removeAllComments(): void; + setDocumentComments(resource: URI, commentInfos: CommentInfo[]): void; + setWorkspaceComments(owner: number, commentsByResource: CommentThread[]): void; + removeWorkspaceComments(owner: number): void; registerDataProvider(owner: number, commentProvider: DocumentCommentProvider | WorkspaceCommentProvider): void; unregisterDataProvider(owner: number): void; updateComments(event: CommentThreadChangedEvent): void; - createNewCommenThread(owner: number, resource: URI, range: Range, text: string): TPromise; + createNewCommentThread(owner: number, resource: URI, range: Range, text: string): TPromise; replyToCommentThread(owner: number, resource: URI, range: Range, thread: CommentThread, text: string): TPromise; getComments(resource: URI): TPromise; } @@ -52,31 +57,31 @@ export class CommentService extends Disposable implements ICommentService { private readonly _onDidSetResourceCommentInfos: Emitter = this._register(new Emitter()); readonly onDidSetResourceCommentInfos: Event = this._onDidSetResourceCommentInfos.event; - private readonly _onDidSetAllCommentThreads: Emitter = this._register(new Emitter()); - readonly onDidSetAllCommentThreads: Event = this._onDidSetAllCommentThreads.event; + private readonly _onDidSetAllCommentThreads: Emitter = this._register(new Emitter()); + readonly onDidSetAllCommentThreads: Event = this._onDidSetAllCommentThreads.event; private readonly _onDidUpdateCommentThreads: Emitter = this._register(new Emitter()); readonly onDidUpdateCommentThreads: Event = this._onDidUpdateCommentThreads.event; - private _commentProviders = new Map(); + private _commentProviders = new Map(); constructor() { super(); } - setComments(resource: URI, commentInfos: CommentInfo[]): void { + setDocumentComments(resource: URI, commentInfos: CommentInfo[]): void { this._onDidSetResourceCommentInfos.fire({ resource, commentInfos }); } - setAllComments(commentsByResource: CommentThread[]): void { - this._onDidSetAllCommentThreads.fire(commentsByResource); + setWorkspaceComments(owner: number, commentsByResource: CommentThread[]): void { + this._onDidSetAllCommentThreads.fire({ ownerId: owner, commentThreads: commentsByResource }); } - removeAllComments(): void { - this._onDidSetAllCommentThreads.fire([]); + removeWorkspaceComments(owner: number): void { + this._onDidSetAllCommentThreads.fire({ ownerId: owner, commentThreads: [] }); } - registerDataProvider(owner: number, commentProvider: DocumentCommentProvider | WorkspaceCommentProvider) { + registerDataProvider(owner: number, commentProvider: DocumentCommentProvider) { this._commentProviders.set(owner, commentProvider); this._onDidSetDataProvider.fire(); } @@ -90,7 +95,7 @@ export class CommentService extends Disposable implements ICommentService { this._onDidUpdateCommentThreads.fire(event); } - createNewCommenThread(owner: number, resource: URI, range: Range, text: string): TPromise { + createNewCommentThread(owner: number, resource: URI, range: Range, text: string): TPromise { const commentProvider = this._commentProviders.get(owner); if (commentProvider) { diff --git a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts index da24f1bb0df8a..f61fbc9fc15c3 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts @@ -379,7 +379,7 @@ export class ReviewZoneWidget extends ZoneWidget { this._commentEditor.getValue() ); } else { - newCommentThread = await this.commentService.createNewCommenThread( + newCommentThread = await this.commentService.createNewCommentThread( this._owner, this.editor.getModel().uri, new Range(lineNumber, 1, lineNumber, 1), diff --git a/src/vs/workbench/parts/comments/electron-browser/commentsPanel.ts b/src/vs/workbench/parts/comments/electron-browser/commentsPanel.ts index d75c7d5aa5de6..a9786dfabd06d 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentsPanel.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentsPanel.ts @@ -10,7 +10,7 @@ import { debounceEvent } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { CollapseAllAction, DefaultAccessibilityProvider, DefaultController, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults'; import { isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; -import { CommentThread, CommentThreadChangedEvent } from 'vs/editor/common/modes'; +import { CommentThreadChangedEvent } from 'vs/editor/common/modes'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -19,7 +19,7 @@ import { Panel } from 'vs/workbench/browser/panel'; import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/parts/comments/common/commentModel'; import { ReviewController } from 'vs/workbench/parts/comments/electron-browser/commentsEditorContribution'; import { CommentsDataFilter, CommentsDataSource, CommentsModelRenderer } from 'vs/workbench/parts/comments/electron-browser/commentsTreeViewer'; -import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService'; +import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/parts/comments/electron-browser/commentService'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -225,8 +225,8 @@ export class CommentsPanel extends Panel { } } - private onAllCommentsChanged(e: CommentThread[]): void { - this.commentsModel.setCommentThreads(e); + private onAllCommentsChanged(e: IWorkspaceCommentThreadsEvent): void { + this.commentsModel.setCommentThreads(e.ownerId, e.commentThreads); this.refresh(); }