Skip to content

Commit

Permalink
Support multiple workspaceCommentsProvider contributions in comments …
Browse files Browse the repository at this point in the history
…panel, fixes #51622
  • Loading branch information
Rachel Macfarlane committed Jun 11, 2018
1 parent e09017d commit 915bbb2
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 38 deletions.
10 changes: 6 additions & 4 deletions src/vs/workbench/api/electron-browser/mainThreadComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
}));
}
Expand Down Expand Up @@ -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);
}
});
}
Expand All @@ -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) {
Expand Down
40 changes: 26 additions & 14 deletions src/vs/workbench/parts/comments/common/commentModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -54,43 +55,51 @@ export class ResourceWithCommentThreads {

export class CommentsModel {
resourceCommentThreads: ResourceWithCommentThreads[];
commentThreadsMap: Map<number, ResourceWithCommentThreads[]>;

constructor() {
this.resourceCommentThreads = [];
this.commentThreadsMap = new Map<number, ResourceWithCommentThreads[]>();
}

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);
matchingResourceData.commentThreads.splice(index, 1);

// 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 {
Expand All @@ -105,15 +114,18 @@ export class CommentsModel {
}
}

private addCommentThreads(commentThreads: CommentThread[]): void {
private groupByResource(commentThreads: CommentThread[]): ResourceWithCommentThreads[] {
const resourceCommentThreads = [];
const commentThreadsByResource = new Map<string, ResourceWithCommentThreads>();
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) {
Expand Down
35 changes: 20 additions & 15 deletions src/vs/workbench/parts/comments/electron-browser/commentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,25 @@ export interface IResourceCommentThreadEvent {
commentInfos: CommentInfo[];
}

export interface IWorkspaceCommentThreadsEvent {
ownerId: number;
commentThreads: CommentThread[];
}

export interface ICommentService {
_serviceBrand: any;
readonly onDidSetResourceCommentInfos: Event<IResourceCommentThreadEvent>;
readonly onDidSetAllCommentThreads: Event<CommentThread[]>;
readonly onDidSetAllCommentThreads: Event<IWorkspaceCommentThreadsEvent>;
readonly onDidUpdateCommentThreads: Event<CommentThreadChangedEvent>;
readonly onDidSetDataProvider: Event<void>;
readonly onDidDeleteDataProvider: Event<number>;
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<CommentThread>;
createNewCommentThread(owner: number, resource: URI, range: Range, text: string): TPromise<CommentThread>;
replyToCommentThread(owner: number, resource: URI, range: Range, thread: CommentThread, text: string): TPromise<CommentThread>;
getComments(resource: URI): TPromise<CommentInfo[]>;
}
Expand All @@ -52,31 +57,31 @@ export class CommentService extends Disposable implements ICommentService {
private readonly _onDidSetResourceCommentInfos: Emitter<IResourceCommentThreadEvent> = this._register(new Emitter<IResourceCommentThreadEvent>());
readonly onDidSetResourceCommentInfos: Event<IResourceCommentThreadEvent> = this._onDidSetResourceCommentInfos.event;

private readonly _onDidSetAllCommentThreads: Emitter<CommentThread[]> = this._register(new Emitter<CommentThread[]>());
readonly onDidSetAllCommentThreads: Event<CommentThread[]> = this._onDidSetAllCommentThreads.event;
private readonly _onDidSetAllCommentThreads: Emitter<IWorkspaceCommentThreadsEvent> = this._register(new Emitter<IWorkspaceCommentThreadsEvent>());
readonly onDidSetAllCommentThreads: Event<IWorkspaceCommentThreadsEvent> = this._onDidSetAllCommentThreads.event;

private readonly _onDidUpdateCommentThreads: Emitter<CommentThreadChangedEvent> = this._register(new Emitter<CommentThreadChangedEvent>());
readonly onDidUpdateCommentThreads: Event<CommentThreadChangedEvent> = this._onDidUpdateCommentThreads.event;

private _commentProviders = new Map<number, (DocumentCommentProvider | WorkspaceCommentProvider)>();
private _commentProviders = new Map<number, DocumentCommentProvider>();

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();
}
Expand All @@ -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<CommentThread> {
createNewCommentThread(owner: number, resource: URI, range: Range, text: string): TPromise<CommentThread> {
const commentProvider = this._commentProviders.get(owner);

if (commentProvider) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';

Expand Down Expand Up @@ -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();
}

Expand Down

0 comments on commit 915bbb2

Please sign in to comment.