diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 8896e0b6e1c..a5bfd4f0d49 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -26,6 +26,7 @@ import { MarshalledId } from 'vs/base/common/marshallingIds'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { Schemas } from 'vs/base/common/network'; import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; +import { MarshalledCommentThread } from 'vs/workbench/common/comments'; export class MainThreadCommentThread implements languages.CommentThread { private _input?: languages.CommentInput; @@ -197,7 +198,7 @@ export class MainThreadCommentThread implements languages.CommentThread { this._onDidChangeState.dispose(); } - toJSON(): any { + toJSON(): MarshalledCommentThread { return { $mid: MarshalledId.CommentThread, commentControlHandle: this.controllerHandle, diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index 3e20208c247..eb85e826f5f 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -20,6 +20,7 @@ import type * as vscode from 'vscode'; import { ExtHostCommentsShape, IMainContext, MainContext, CommentThreadChanges, CommentChanges } from './extHost.protocol'; import { ExtHostCommands } from './extHostCommands'; import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { MarshalledCommentThread } from 'vs/workbench/common/comments'; type ProviderHandle = number; @@ -53,16 +54,17 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo return commentController.value; } else if (arg && arg.$mid === MarshalledId.CommentThread) { - const commentController = this._commentControllers.get(arg.commentControlHandle); + const marshalledCommentThread: MarshalledCommentThread = arg; + const commentController = this._commentControllers.get(marshalledCommentThread.commentControlHandle); if (!commentController) { - return arg; + return marshalledCommentThread; } - const commentThread = commentController.getCommentThread(arg.commentThreadHandle); + const commentThread = commentController.getCommentThread(marshalledCommentThread.commentThreadHandle); if (!commentThread) { - return arg; + return marshalledCommentThread; } return commentThread.value; diff --git a/src/vs/workbench/common/comments.ts b/src/vs/workbench/common/comments.ts new file mode 100644 index 00000000000..038819d8f99 --- /dev/null +++ b/src/vs/workbench/common/comments.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { MarshalledId } from 'vs/base/common/marshallingIds'; +import { CommentThread } from 'vs/editor/common/languages'; + +export interface MarshalledCommentThread { + $mid: MarshalledId.CommentThread; + commentControlHandle: number; + commentThreadHandle: number; +} + +export interface MarshalledCommentThreadInternal extends MarshalledCommentThread { + thread: CommentThread; +} diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 95ef19e971e..df2afb078e5 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -50,6 +50,7 @@ import { COMMENTS_SECTION, ICommentsConfiguration } from 'vs/workbench/contrib/c import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { MarshalledCommentThread } from 'vs/workbench/common/comments'; class CommentsActionRunner extends ActionRunner { protected override async runAction(action: IAction, context: any[]): Promise { @@ -293,7 +294,7 @@ export class CommentNode extends Disposable { return result; } - private get commentNodeContext() { + private get commentNodeContext(): [any, MarshalledCommentThread] { return [{ thread: this.commentThread, commentUniqueId: this.comment.uniqueIdInThread, diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadHeader.ts b/src/vs/workbench/contrib/comments/browser/commentThreadHeader.ts index b206d26b011..9784625cd2f 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadHeader.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadHeader.ts @@ -22,6 +22,7 @@ import { CommentMenus } from 'vs/workbench/contrib/comments/browser/commentMenus import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { MarshalledId } from 'vs/base/common/marshallingIds'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { MarshalledCommentThread } from 'vs/workbench/common/comments'; const collapseIcon = registerIcon('review-comment-collapse', Codicon.chevronUp, nls.localize('collapseIcon', 'Icon to collapse a review comment.')); const COLLAPSE_ACTION_CLASS = 'expand-review-action ' + ThemeIcon.asClassName(collapseIcon); @@ -122,7 +123,7 @@ export class CommentThreadHeader extends Disposable { getAnchor: () => event, getActions: () => actions, actionRunner: new ActionRunner(), - getActionsContext: () => { + getActionsContext: (): MarshalledCommentThread => { return { commentControlHandle: this._commentThread.controllerHandle, commentThreadHandle: this._commentThread.commentThreadHandle, diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index bcd9366e524..e09cd4f5167 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -351,7 +351,7 @@ export class CommentThreadWidget extends } focusCommentEditor() { - this._commentReply?.focusCommentEditor(); + this._commentReply?.expandReplyAreaAndFocusCommentEditor(); } focus() { diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts index baa3438345d..a3c6f70f09a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts @@ -31,6 +31,12 @@ function getCommentThreadWidgetStateColor(thread: languages.CommentThreadState | return getCommentThreadStateBorderColor(thread, theme) ?? theme.getColor(peekViewBorder); } +export enum CommentWidgetFocus { + None = 0, + Widget = 1, + Editor = 2 +} + export function parseMouseDownInfoFromEvent(e: IEditorMouseEvent) { const range = e.target.range; @@ -181,7 +187,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget // we don't do anything here as we always do the reveal ourselves. } - public reveal(commentUniqueId?: number, focus: boolean = false) { + public reveal(commentUniqueId?: number, focus: CommentWidgetFocus = CommentWidgetFocus.None) { if (!this._isExpanded) { this.show(this.arrowPosition(this._commentThread.range), 2); } @@ -197,16 +203,20 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget scrollTop = this.editor.getTopForLineNumber(this._commentThread.range.startLineNumber) - height / 2 + commentCoords.top - commentThreadCoords.top; } this.editor.setScrollTop(scrollTop); - if (focus) { + if (focus === CommentWidgetFocus.Widget) { this._commentThreadWidget.focus(); + } else if (focus === CommentWidgetFocus.Editor) { + this._commentThreadWidget.focusCommentEditor(); } return; } } this.editor.revealRangeInCenter(this._commentThread.range ?? new Range(1, 1, 1, 1)); - if (focus) { + if (focus === CommentWidgetFocus.Widget) { this._commentThreadWidget.focus(); + } else if (focus === CommentWidgetFocus.Editor) { + this._commentThreadWidget.focusCommentEditor(); } } diff --git a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts index b47cdb2b883..e57e7c315e2 100644 --- a/src/vs/workbench/contrib/comments/browser/comments.contribution.ts +++ b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts @@ -17,10 +17,14 @@ import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/co import { COMMENTS_VIEW_ID } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; import { CommentThreadState } from 'vs/editor/common/languages'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { CONTEXT_KEY_HAS_COMMENTS, CONTEXT_KEY_SOME_COMMENTS_EXPANDED, CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsView'; import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { Codicon } from 'vs/base/common/codicons'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { revealCommentThread } from 'vs/workbench/contrib/comments/browser/commentsController'; +import { MarshalledCommentThreadInternal } from 'vs/workbench/common/comments'; registerAction2(class Collapse extends ViewAction { constructor() { @@ -64,6 +68,28 @@ registerAction2(class Expand extends ViewAction { } }); +registerAction2(class Reply extends Action2 { + constructor() { + super({ + id: 'comments.reply', + title: nls.localize('reply', "Reply"), + icon: Codicon.reply, + menu: { + id: MenuId.CommentsViewThreadActions, + order: 100, + when: ContextKeyExpr.equals('canReply', true) + }, + }); + } + + override run(accessor: ServicesAccessor, marshalledCommentThread: MarshalledCommentThreadInternal): void { + const commentService = accessor.get(ICommentService); + const editorService = accessor.get(IEditorService); + const uriIdentityService = accessor.get(IUriIdentityService); + revealCommentThread(commentService, editorService, uriIdentityService, marshalledCommentThread.thread, marshalledCommentThread.thread.comments![marshalledCommentThread.thread.comments!.length - 1], true); + } +}); + Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ id: 'comments', order: 20, diff --git a/src/vs/workbench/contrib/comments/browser/commentsController.ts b/src/vs/workbench/contrib/comments/browser/commentsController.ts index e83cb560c6c..7abfde48305 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsController.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsController.ts @@ -10,12 +10,12 @@ import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/com import { onUnexpectedError } from 'vs/base/common/errors'; import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./media/review'; -import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IEditorMouseEvent, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IRange, Range } from 'vs/editor/common/core/range'; -import { EditorType, IDiffEditor, IEditorContribution, IModelChangedEvent } from 'vs/editor/common/editorCommon'; +import { EditorType, IDiffEditor, IEditor, IEditorContribution, IModelChangedEvent } from 'vs/editor/common/editorCommon'; import { IModelDecorationOptions, IModelDeltaDecoration } from 'vs/editor/common/model'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { ModelDecorationOptions, TextModel } from 'vs/editor/common/model/textModel'; import * as languages from 'vs/editor/common/languages'; import * as nls from 'vs/nls'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -23,8 +23,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; import { CommentGlyphWidget } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget'; import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService'; -import { isMouseUpEventDragFromMouseDown, parseMouseDownInfoFromEvent, ReviewZoneWidget } from 'vs/workbench/contrib/comments/browser/commentThreadZoneWidget'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { CommentWidgetFocus, isMouseUpEventDragFromMouseDown, parseMouseDownInfoFromEvent, ReviewZoneWidget } from 'vs/workbench/contrib/comments/browser/commentThreadZoneWidget'; +import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/embeddedCodeEditorWidget'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; @@ -45,6 +45,8 @@ import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/commo import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { URI } from 'vs/base/common/uri'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; export const ID = 'editor.contrib.review'; @@ -366,6 +368,57 @@ class CommentingRangeDecorator { } } +export function revealCommentThread(commentService: ICommentService, editorService: IEditorService, uriIdentityService: IUriIdentityService, + commentThread: languages.CommentThread, comment: languages.Comment, focusReply?: boolean, pinned?: boolean, preserveFocus?: boolean, sideBySide?: boolean): void { + if (!commentThread.resource) { + return; + } + if (!commentService.isCommentingEnabled) { + commentService.enableCommenting(true); + } + + const range = commentThread.range; + const focus = focusReply ? CommentWidgetFocus.Editor : (preserveFocus ? CommentWidgetFocus.None : CommentWidgetFocus.Widget); + + const activeEditor = editorService.activeTextEditorControl; + // If the active editor is a diff editor where one of the sides has the comment, + // then we try to reveal the comment in the diff editor. + const currentActiveResources: IEditor[] = isDiffEditor(activeEditor) ? [activeEditor.getOriginalEditor(), activeEditor.getModifiedEditor()] + : (activeEditor ? [activeEditor] : []); + const threadToReveal = commentThread.threadId; + const commentToReveal = comment.uniqueIdInThread; + const resource = URI.parse(commentThread.resource); + + for (const editor of currentActiveResources) { + const model = editor.getModel(); + if ((model instanceof TextModel) && uriIdentityService.extUri.isEqual(resource, model.uri)) { + + if (threadToReveal && isCodeEditor(editor)) { + const controller = CommentController.get(editor); + controller?.revealCommentThread(threadToReveal, commentToReveal, true, focus); + } + return; + } + } + + editorService.openEditor({ + resource, + options: { + pinned: pinned, + preserveFocus: preserveFocus, + selection: range ?? new Range(1, 1, 1, 1) + } + } as ITextResourceEditorInput, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => { + if (editor) { + const control = editor.getControl(); + if (threadToReveal && isCodeEditor(control)) { + const controller = CommentController.get(control); + controller?.revealCommentThread(threadToReveal, commentToReveal, true, focus); + } + } + }); +} + export class CommentController implements IEditorContribution { private readonly globalToDispose = new DisposableStore(); private readonly localToDispose = new DisposableStore(); @@ -630,7 +683,7 @@ export class CommentController implements IEditorContribution { return editor.getContribution(ID); } - public revealCommentThread(threadId: string, commentUniqueId: number, fetchOnceIfNotExist: boolean, focus: boolean): void { + public revealCommentThread(threadId: string, commentUniqueId: number, fetchOnceIfNotExist: boolean, focus: CommentWidgetFocus): void { const commentThreadWidget = this._commentWidgets.filter(widget => widget.commentThread.threadId === threadId); if (commentThreadWidget.length === 1) { commentThreadWidget[0].reveal(commentUniqueId, focus); @@ -734,7 +787,7 @@ export class CommentController implements IEditorContribution { nextWidget = sortedWidgets[idx]; } this.editor.setSelection(nextWidget.commentThread.range ?? new Range(1, 1, 1, 1)); - nextWidget.reveal(undefined, true); + nextWidget.reveal(undefined, CommentWidgetFocus.Widget); } public previousCommentThread(): void { diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index df131acad4b..147d7ed6fab 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -42,6 +42,7 @@ import { MarshalledId } from 'vs/base/common/marshallingIds'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { MarshalledCommentThread, MarshalledCommentThreadInternal } from 'vs/workbench/common/comments'; export const COMMENTS_VIEW_ID = 'workbench.panel.comments'; export const COMMENTS_VIEW_STORAGE_ID = 'Comments'; @@ -161,7 +162,8 @@ class CommentsMenus implements IDisposable { const overlay: [string, any][] = [ ['commentController', element.owner], ['resourceScheme', element.resource.scheme], - ['commentThread', element.contextValue] + ['commentThread', element.contextValue], + ['canReply', element.thread.canReply] ]; const contextKeyService = this.contextKeyService.createOverlay(overlay); @@ -304,7 +306,7 @@ export class CommentNodeRenderer implements IListRenderer commentControlHandle: node.element.controllerHandle, commentThreadHandle: node.element.threadHandle, $mid: MarshalledId.CommentThread - }; + } as MarshalledCommentThread; if (!node.element.hasReply()) { templateData.repliesMetadata.container.style.display = 'none'; @@ -511,10 +513,11 @@ export class CommentsList extends WorkbenchObjectTree ({ + getActionsContext: (): MarshalledCommentThreadInternal => ({ commentControlHandle: node.controllerHandle, commentThreadHandle: node.threadHandle, - $mid: MarshalledId.CommentThread + $mid: MarshalledId.CommentThread, + thread: node.thread }) }); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index 2530cf96e7c..b45f12a0cb7 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -7,12 +7,11 @@ import 'vs/css!./media/panel'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { basename } from 'vs/base/common/resources'; -import { isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { CommentNode, ResourceWithCommentThreads, ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel'; import { IWorkspaceCommentThreadsEvent, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService'; -import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { CommentsList, COMMENTS_VIEW_TITLE, Filter } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; import { IViewPaneOptions, FilterViewPane } from 'vs/workbench/browser/parts/views/viewPane'; @@ -24,8 +23,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { IEditor } from 'vs/editor/common/editorCommon'; -import { TextModel } from 'vs/editor/common/model/textModel'; import { CommentsViewFilterFocusContextKey, ICommentsView } from 'vs/workbench/contrib/comments/browser/comments'; import { CommentsFilters, CommentsFiltersChangeEvent } from 'vs/workbench/contrib/comments/browser/commentsViewActions'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; @@ -34,8 +31,7 @@ import { FilterOptions } from 'vs/workbench/contrib/comments/browser/commentsFil import { CommentThreadState } from 'vs/editor/common/languages'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; import { Iterable } from 'vs/base/common/iterator'; -import { CommentController } from 'vs/workbench/contrib/comments/browser/commentsController'; -import { Range } from 'vs/editor/common/core/range'; +import { revealCommentThread } from 'vs/workbench/contrib/comments/browser/commentsController'; import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands'; import { CommentsModel, ICommentsModel } from 'vs/workbench/contrib/comments/browser/commentsModel'; @@ -323,62 +319,17 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView { })); } - private openFile(element: any, pinned?: boolean, preserveFocus?: boolean, sideBySide?: boolean): boolean { + private openFile(element: any, pinned?: boolean, preserveFocus?: boolean, sideBySide?: boolean): void { if (!element) { - return false; + return; } if (!(element instanceof ResourceWithCommentThreads || element instanceof CommentNode)) { - return false; + return; } - - if (!this.commentService.isCommentingEnabled) { - this.commentService.enableCommenting(true); - } - - const range = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].range : element.range; - - const activeEditor = this.editorService.activeTextEditorControl; - // If the active editor is a diff editor where one of the sides has the comment, - // then we try to reveal the comment in the diff editor. - const currentActiveResources: IEditor[] = isDiffEditor(activeEditor) ? [activeEditor.getOriginalEditor(), activeEditor.getModifiedEditor()] - : (activeEditor ? [activeEditor] : []); - - for (const editor of currentActiveResources) { - const model = editor.getModel(); - if ((model instanceof TextModel) && this.uriIdentityService.extUri.isEqual(element.resource, model.uri)) { - const threadToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].threadId : element.threadId; - const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment.uniqueIdInThread : element.comment.uniqueIdInThread; - if (threadToReveal && isCodeEditor(editor)) { - const controller = CommentController.get(editor); - controller?.revealCommentThread(threadToReveal, commentToReveal, true, !preserveFocus); - } - - return true; - } - } - - const threadToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].threadId : element.threadId; + const threadToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].thread : element.thread; const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment : element.comment; - - this.editorService.openEditor({ - resource: element.resource, - options: { - pinned: pinned, - preserveFocus: preserveFocus, - selection: range ?? new Range(1, 1, 1, 1) - } - }, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => { - if (editor) { - const control = editor.getControl(); - if (threadToReveal && isCodeEditor(control)) { - const controller = CommentController.get(control); - controller?.revealCommentThread(threadToReveal, commentToReveal.uniqueIdInThread, true, !preserveFocus); - } - } - }); - - return true; + return revealCommentThread(this.commentService, this.editorService, this.uriIdentityService, threadToReveal, commentToReveal, false, pinned, preserveFocus, sideBySide); } private async refresh(): Promise { diff --git a/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts index e4418a28dfc..7bf9efe417a 100644 --- a/src/vs/workbench/contrib/comments/common/commentModel.ts +++ b/src/vs/workbench/contrib/comments/common/commentModel.ts @@ -16,18 +16,26 @@ export interface ICommentThreadChangedEvent extends CommentThreadChangedEvent new CommentNode(uniqueOwner, threadId, resource, comment, range, commentThread.state, commentThread.contextValue, owner, commentThread.controllerHandle, commentThread.commentThreadHandle)); + const { comments } = commentThread; + const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(uniqueOwner, owner, resource, comment, commentThread)); if (commentNodes.length > 1) { commentNodes[0].replies = commentNodes.slice(1, commentNodes.length); }