diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index ce57654ba8d..2f9db2824ba 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -1593,7 +1593,7 @@ export interface CommentThread { extensionId?: string; threadId: string; resource: string | null; - range: T; + range: T | undefined; label: string | undefined; contextValue: string | undefined; comments: Comment[] | undefined; @@ -1605,7 +1605,7 @@ export interface CommentThread { canReply: boolean; input?: CommentInput; onDidChangeInput: Event; - onDidChangeRange: Event; + onDidChangeRange: Event; onDidChangeLabel: Event; onDidChangeCollapsibleState: Event; onDidChangeState: Event; diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 0c27746ee67..e754d811964 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -13,7 +13,7 @@ import * as languages from 'vs/editor/common/languages'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; -import { ICommentInfo, ICommentService, INotebookCommentInfo } from 'vs/workbench/contrib/comments/browser/commentService'; +import { ICommentController, ICommentInfo, ICommentService, INotebookCommentInfo } from 'vs/workbench/contrib/comments/browser/commentService'; import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsView'; import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from '../common/extHost.protocol'; import { COMMENTS_VIEW_ID, COMMENTS_VIEW_STORAGE_ID, COMMENTS_VIEW_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer'; @@ -80,12 +80,12 @@ export class MainThreadCommentThread implements languages.CommentThread { private readonly _onDidChangeComments = new Emitter(); get onDidChangeComments(): Event { return this._onDidChangeComments.event; } - set range(range: T) { + set range(range: T | undefined) { this._range = range; this._onDidChangeRange.fire(this._range); } - get range(): T { + get range(): T | undefined { return this._range; } @@ -100,7 +100,7 @@ export class MainThreadCommentThread implements languages.CommentThread { return this._canReply; } - private readonly _onDidChangeRange = new Emitter(); + private readonly _onDidChangeRange = new Emitter(); public onDidChangeRange = this._onDidChangeRange.event; private _collapsibleState: languages.CommentThreadCollapsibleState | undefined; @@ -138,7 +138,7 @@ export class MainThreadCommentThread implements languages.CommentThread { } isDocumentCommentThread(): this is languages.CommentThread { - return Range.isIRange(this._range); + return this._range === undefined || Range.isIRange(this._range); } private _state: languages.CommentThreadState | undefined; @@ -164,7 +164,7 @@ export class MainThreadCommentThread implements languages.CommentThread { public extensionId: string, public threadId: string, public resource: string, - private _range: T, + private _range: T | undefined, private _canReply: boolean, private _isTemplate: boolean ) { @@ -207,7 +207,7 @@ export class MainThreadCommentThread implements languages.CommentThread { } } -export class MainThreadCommentController { +export class MainThreadCommentController implements ICommentController { get handle(): number { return this._handle; } @@ -267,7 +267,7 @@ export class MainThreadCommentController { commentThreadHandle: number, threadId: string, resource: UriComponents, - range: IRange | ICellRange, + range: IRange | ICellRange | undefined, isTemplate: boolean ): languages.CommentThread { const thread = new MainThreadCommentThread( @@ -547,7 +547,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments commentThreadHandle: number, threadId: string, resource: UriComponents, - range: IRange | ICellRange, + range: IRange | ICellRange | undefined, extensionId: ExtensionIdentifier, isTemplate: boolean ): languages.CommentThread | undefined { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 84170d79528..e972a4ee503 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -124,7 +124,7 @@ export interface CommentChanges { } export type CommentThreadChanges = Partial<{ - range: T; + range: T | undefined; label: string; contextValue: string | null; comments: CommentChanges[]; @@ -138,7 +138,7 @@ export interface MainThreadCommentsShape extends IDisposable { $registerCommentController(handle: number, id: string, label: string): void; $unregisterCommentController(handle: number): void; $updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void; - $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange | ICellRange, extensionId: ExtensionIdentifier, isTemplate: boolean): languages.CommentThread | undefined; + $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange | ICellRange | undefined, extensionId: ExtensionIdentifier, isTemplate: boolean): languages.CommentThread | undefined; $updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, changes: CommentThreadChanges): void; $deleteCommentThread(handle: number, commentThreadHandle: number): void; $updateCommentingRanges(handle: number): void; diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index b88799e695d..b9cd2eb20bf 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -19,6 +19,7 @@ import * as types from 'vs/workbench/api/common/extHostTypes'; 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'; type ProviderHandle = number; @@ -233,7 +234,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo isTemplate: boolean; }>; - class ExtHostCommentThread implements vscode.CommentThread { + class ExtHostCommentThread implements vscode.CommentThread2 { private static _handlePool: number = 0; readonly handle = ExtHostCommentThread._handlePool++; public commentHandle: number = 0; @@ -263,15 +264,15 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo private readonly _onDidUpdateCommentThread = new Emitter(); readonly onDidUpdateCommentThread = this._onDidUpdateCommentThread.event; - set range(range: vscode.Range) { - if (!range.isEqual(this._range)) { + set range(range: vscode.Range | undefined) { + if (((range === undefined) !== (this._range === undefined)) || (!range || !this._range || !range.isEqual(this._range))) { this._range = range; this.modifications.range = range; this._onDidUpdateCommentThread.fire(); } } - get range(): vscode.Range { + get range(): vscode.Range | undefined { return this._range; } @@ -358,14 +359,14 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo private _acceptInputDisposables = new MutableDisposable(); - readonly value: vscode.CommentThread; + readonly value: vscode.CommentThread2; constructor( commentControllerId: string, private _commentControllerHandle: number, private _id: string | undefined, private _uri: vscode.Uri, - private _range: vscode.Range, + private _range: vscode.Range | undefined, private _comments: vscode.Comment[], public readonly extensionDescription: IExtensionDescription, private _isTemplate: boolean @@ -409,7 +410,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo this.value = { get uri() { return that.uri; }, get range() { return that.range; }, - set range(value: vscode.Range) { that.range = value; }, + set range(value: vscode.Range | undefined) { that.range = value; }, get comments() { return that.comments; }, set comments(value: vscode.Comment[]) { that.comments = value; }, get collapsibleState() { return that.collapsibleState; }, @@ -582,11 +583,11 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo set commentingRangeProvider(commentingRangeProvider: vscode.CommentingRangeProvider | undefined) { that.commentingRangeProvider = commentingRangeProvider; }, get reactionHandler(): ReactionHandler | undefined { return that.reactionHandler; }, set reactionHandler(handler: ReactionHandler | undefined) { that.reactionHandler = handler; }, - createCommentThread(uri: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): vscode.CommentThread { + createCommentThread(uri: vscode.Uri, range: vscode.Range | undefined, comments: vscode.Comment[]): vscode.CommentThread | vscode.CommentThread2 { return that.createCommentThread(uri, range, comments).value; }, dispose: () => { that.dispose(); }, - }); + }) as any; // TODO @alexr00 remove this cast when the proposed API is stable this._localDisposables = []; this._localDisposables.push({ @@ -596,17 +597,13 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo }); } - createCommentThread(resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): ExtHostCommentThread; - createCommentThread(arg0: vscode.Uri | string, arg1: vscode.Uri | vscode.Range, arg2: vscode.Range | vscode.Comment[], arg3?: vscode.Comment[]): vscode.CommentThread { - if (typeof arg0 === 'string') { - const commentThread = new ExtHostCommentThread(this.id, this.handle, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[], this._extension, false); - this._threads.set(commentThread.handle, commentThread); - return commentThread; - } else { - const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[], this._extension, false); - this._threads.set(commentThread.handle, commentThread); - return commentThread; + createCommentThread(resource: vscode.Uri, range: vscode.Range | undefined, comments: vscode.Comment[]): ExtHostCommentThread { + if (range === undefined) { + checkProposedApiEnabled(this._extension, 'fileComments'); } + const commentThread = new ExtHostCommentThread(this.id, this.handle, undefined, resource, range, comments, this._extension, false); + this._threads.set(commentThread.handle, commentThread); + return commentThread; } $createCommentThreadTemplate(uriComponents: UriComponents, range: IRange): ExtHostCommentThread { diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadBody.ts b/src/vs/workbench/contrib/comments/browser/commentThreadBody.ts index 047d6c8cb1f..a06b7a7716d 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadBody.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadBody.ts @@ -225,9 +225,14 @@ export class CommentThreadBody extends D private _updateAriaLabel() { if (this._commentThread.isDocumentCommentThread()) { - this._commentsElement.ariaLabel = nls.localize('commentThreadAria.withRange', "Comment thread with {0} comments on lines {1} through {2}. {3}.", - this._commentThread.comments?.length, this._commentThread.range.startLineNumber, this._commentThread.range.endLineNumber, - this._commentThread.label); + if (this._commentThread.range) { + this._commentsElement.ariaLabel = nls.localize('commentThreadAria.withRange', "Comment thread with {0} comments on lines {1} through {2}. {3}.", + this._commentThread.comments?.length, this._commentThread.range.startLineNumber, this._commentThread.range.endLineNumber, + this._commentThread.label); + } else { + this._commentsElement.ariaLabel = nls.localize('commentThreadAria.document', "Comment thread with {0} comments on the entire document. {1}.", + this._commentThread.comments?.length, this._commentThread.label); + } } else { this._commentsElement.ariaLabel = nls.localize('commentThreadAria', "Comment thread with {0} comments. {1}.", this._commentThread.comments?.length, this._commentThread.label); diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadRangeDecorator.ts b/src/vs/workbench/contrib/comments/browser/commentThreadRangeDecorator.ts index b685642dc22..0c9828613d2 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadRangeDecorator.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadRangeDecorator.ts @@ -73,7 +73,7 @@ export class CommentThreadRangeDecorator extends Disposable { const newDecoration: CommentThreadRangeDecoration[] = []; if (thread) { const range = thread.range; - if (!((range.startLineNumber === range.endLineNumber) && (range.startColumn === range.endColumn))) { + if (range && !((range.startLineNumber === range.endLineNumber) && (range.startColumn === range.endColumn))) { if (thread.collapsibleState === CommentThreadCollapsibleState.Expanded) { this.currentThreadCollapseStateListener = thread.onDidChangeCollapsibleState(state => { if (state === CommentThreadCollapsibleState.Collapsed) { @@ -108,7 +108,7 @@ export class CommentThreadRangeDecorator extends Disposable { const range = thread.range; // We only want to show a range decoration when there's the range spans either multiple lines // or, when is spans multiple characters on the sample line - if ((range.startLineNumber === range.endLineNumber) && (range.startColumn === range.endColumn)) { + if (!range || (range.startLineNumber === range.endLineNumber) && (range.startColumn === range.endColumn)) { return; } diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts index 77b25e79990..26c40b04385 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts @@ -187,15 +187,18 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const height = this.editor.getLayoutInfo().height; const coords = this._commentThreadWidget.getCommentCoords(commentUniqueId); if (coords) { - const commentThreadCoords = coords.thread; - const commentCoords = coords.comment; - - this.editor.setScrollTop(this.editor.getTopForLineNumber(this._commentThread.range.startLineNumber) - height / 2 + commentCoords.top - commentThreadCoords.top); + let scrollTop: number = 1; + if (this._commentThread.range) { + const commentThreadCoords = coords.thread; + const commentCoords = coords.comment; + scrollTop = this.editor.getTopForLineNumber(this._commentThread.range.startLineNumber) - height / 2 + commentCoords.top - commentThreadCoords.top; + } + this.editor.setScrollTop(scrollTop); return; } } - this.editor.revealRangeInCenter(this._commentThread.range); + this.editor.revealRangeInCenter(this._commentThread.range ?? new Range(1, 1, 1, 1)); if (focus) { this._commentThreadWidget.focus(); } @@ -228,12 +231,16 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const newPosition = this.getPosition(); if (newPosition) { - let range: Range; const originalRange = this._commentThread.range; + if (!originalRange) { + return; + } + let range: Range; + if (newPosition.lineNumber !== originalRange.endLineNumber) { // The widget could have moved as a result of editor changes. // We need to try to calculate the new, more correct, range for the comment. - const distance = newPosition.lineNumber - this._commentThread.range.endLineNumber; + const distance = newPosition.lineNumber - originalRange.endLineNumber; range = new Range(originalRange.startLineNumber + distance, originalRange.startColumn, originalRange.endLineNumber + distance, originalRange.endColumn); } else { range = new Range(originalRange.startLineNumber, originalRange.startColumn, originalRange.endLineNumber, originalRange.endColumn); @@ -251,7 +258,10 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._disposables.add(this._commentThreadWidget); } - private arrowPosition(range: IRange): IPosition { + private arrowPosition(range: IRange | undefined): IPosition | undefined { + if (!range) { + return undefined; + } // Arrow on top edge of zone widget will be at the start of the line if range is multi-line, else at midpoint of range (rounding rightwards) return { lineNumber: range.endLineNumber, column: range.endLineNumber === range.startLineNumber ? (range.startColumn + range.endColumn + 1) / 2 : 1 }; } @@ -295,7 +305,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentThreadWidget.updateCommentThread(commentThread); // Move comment glyph widget and show position if the line has changed. - const lineNumber = this._commentThread.range.endLineNumber; + const lineNumber = this._commentThread.range?.endLineNumber ?? 1; let shouldMoveWidget = false; if (this._commentGlyph) { this._commentGlyph.setThreadState(commentThread.state); @@ -324,15 +334,17 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentThreadWidget.layout(widthInPixel); } - display(range: IRange) { - this._commentGlyph = new CommentGlyphWidget(this.editor, range.endLineNumber); - this._commentGlyph.setThreadState(this._commentThread.state); + display(range: IRange | undefined) { + if (range) { + this._commentGlyph = new CommentGlyphWidget(this.editor, range?.endLineNumber ?? -1); + this._commentGlyph.setThreadState(this._commentThread.state); + } this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight)); this._disposables.add(this._commentThreadWidget.onDidResize(dimension => { this._refresh(dimension); })); - if (this._commentThread.collapsibleState === languages.CommentThreadCollapsibleState.Expanded) { + if ((this._commentThread.collapsibleState === languages.CommentThreadCollapsibleState.Expanded) || (range === undefined)) { this.show(this.arrowPosition(range), 2); } @@ -351,7 +363,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentThreadDisposables.push(this._commentThread.onDidChangeRange(range => { // Move comment glyph widget and show position if the line has changed. - const lineNumber = this._commentThread.range.startLineNumber; + const lineNumber = this._commentThread.range?.startLineNumber ?? 1; let shouldMoveWidget = false; if (this._commentGlyph) { if (this._commentGlyph.getPosition().position!.lineNumber !== lineNumber) { @@ -379,8 +391,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if (this._initialCollapsibleState === undefined) { const onDidChangeInitialCollapsibleState = this._commentThread.onDidChangeInitialCollapsibleState(state => { - this._initialCollapsibleState = state; - this._commentThread.collapsibleState = state; + // File comments always start expanded + this._initialCollapsibleState = this._commentThread.range ? state : languages.CommentThreadCollapsibleState.Expanded; + this._commentThread.collapsibleState = this._initialCollapsibleState; onDidChangeInitialCollapsibleState.dispose(); }); this._commentThreadDisposables.push(onDidChangeInitialCollapsibleState); @@ -420,7 +433,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const currentPosition = this.getPosition(); - if (this._viewZone && currentPosition && currentPosition.lineNumber !== this._viewZone.afterLineNumber) { + if (this._viewZone && currentPosition && currentPosition.lineNumber !== this._viewZone.afterLineNumber && this._viewZone.afterLineNumber !== 0) { this._viewZone.afterLineNumber = currentPosition.lineNumber; } @@ -444,9 +457,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentThreadWidget.applyTheme(theme, fontInfo); } - override show(rangeOrPos: IRange | IPosition, heightInLines: number): void { + override show(rangeOrPos: IRange | IPosition | undefined, heightInLines: number): void { this._isExpanded = true; - super.show(rangeOrPos, heightInLines); + super.show(rangeOrPos ?? new Range(0, 0, 0, 0), heightInLines); this._commentThread.collapsibleState = languages.CommentThreadCollapsibleState.Expanded; this._refresh(this._commentThreadWidget.getDimensions()); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsController.ts b/src/vs/workbench/contrib/comments/browser/commentsController.ts index fa9d517bd9d..d7e975b3042 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsController.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsController.ts @@ -536,6 +536,12 @@ export class CommentController implements IEditorContribution { a = b; b = temp; } + if (a.commentThread.range === undefined) { + return -1; + } + if (b.commentThread.range === undefined) { + return 1; + } if (a.commentThread.range.startLineNumber < b.commentThread.range.startLineNumber) { return -1; } @@ -556,10 +562,10 @@ export class CommentController implements IEditorContribution { }); const idx = findFirstInSorted(sortedWidgets, widget => { - const lineValueOne = reverse ? after.lineNumber : widget.commentThread.range.startLineNumber; - const lineValueTwo = reverse ? widget.commentThread.range.startLineNumber : after.lineNumber; - const columnValueOne = reverse ? after.column : widget.commentThread.range.startColumn; - const columnValueTwo = reverse ? widget.commentThread.range.startColumn : after.column; + const lineValueOne = reverse ? after.lineNumber : (widget.commentThread.range?.startLineNumber ?? 0); + const lineValueTwo = reverse ? (widget.commentThread.range?.startLineNumber ?? 0) : after.lineNumber; + const columnValueOne = reverse ? after.column : (widget.commentThread.range?.startColumn ?? 0); + const columnValueTwo = reverse ? (widget.commentThread.range?.startColumn ?? 0) : after.column; if (lineValueOne > lineValueTwo) { return true; } @@ -580,7 +586,7 @@ export class CommentController implements IEditorContribution { } else { nextWidget = sortedWidgets[idx]; } - this.editor.setSelection(nextWidget.commentThread.range); + this.editor.setSelection(nextWidget.commentThread.range ?? new Range(1, 1, 1, 1)); nextWidget.reveal(undefined, true); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 329552f84ac..5da02b74bb5 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -3,10 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $ } from 'vs/base/browser/dom'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import 'vs/css!./media/review'; -import { IActiveCodeEditor, ICodeEditor, isCodeEditor, isDiffEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; +import { IActiveCodeEditor, ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import * as nls from 'vs/nls'; @@ -20,24 +19,6 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ActiveCursorHasCommentingRange, CommentController, ID } from 'vs/workbench/contrib/comments/browser/commentsController'; -export class ReviewViewZone implements IViewZone { - public readonly afterLineNumber: number; - public readonly domNode: HTMLElement; - private callback: (top: number) => void; - - constructor(afterLineNumber: number, onDomNodeTop: (top: number) => void) { - this.afterLineNumber = afterLineNumber; - this.callback = onDomNodeTop; - - this.domNode = $('.review-viewzone'); - } - - onDomNodeTop(top: number): void { - this.callback(top); - } -} - - export class NextCommentThreadAction extends EditorAction { constructor() { super({ diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index 368d2bae934..e53ef0f180a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -207,10 +207,12 @@ export class CommentNodeRenderer implements IListRenderer templateData.threadMetadata.commentPreview.title = renderedComment.element.textContent ?? ''; } - if (node.element.range.startLineNumber === node.element.range.endLineNumber) { - templateData.threadMetadata.range.textContent = nls.localize('commentLine', "[Ln {0}]", node.element.range.startLineNumber); - } else { - templateData.threadMetadata.range.textContent = nls.localize('commentRange', "[Ln {0}-{1}]", node.element.range.startLineNumber, node.element.range.endLineNumber); + if (node.element.range) { + if (node.element.range.startLineNumber === node.element.range.endLineNumber) { + templateData.threadMetadata.range.textContent = nls.localize('commentLine', "[Ln {0}]", node.element.range.startLineNumber); + } else { + templateData.threadMetadata.range.textContent = nls.localize('commentRange', "[Ln {0}-{1}]", node.element.range.startLineNumber, node.element.range.endLineNumber); + } } if (!node.element.hasReply()) { diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index c869e7f0857..5a787f30cc0 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -41,6 +41,7 @@ import { IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; 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'; const CONTEXT_KEY_HAS_COMMENTS = new RawContextKey('commentsView.hasComments', false); const CONTEXT_KEY_SOME_COMMENTS_EXPANDED = new RawContextKey('commentsView.someCommentsExpanded', false); @@ -312,14 +313,23 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView { return nls.localize('resourceWithCommentThreadsLabel', "Comments in {0}, full path {1}", basename(element.resource), element.resource.fsPath); } if (element instanceof CommentNode) { - return nls.localize('resourceWithCommentLabel', - "Comment from ${0} at line {1} column {2} in {3}, source: {4}", - element.comment.userName, - element.range.startLineNumber, - element.range.startColumn, - basename(element.resource), - (typeof element.comment.body === 'string') ? element.comment.body : element.comment.body.value - ); + if (element.range) { + return nls.localize('resourceWithCommentLabel', + "Comment from ${0} at line {1} column {2} in {3}, source: {4}", + element.comment.userName, + element.range.startLineNumber, + element.range.startColumn, + basename(element.resource), + (typeof element.comment.body === 'string') ? element.comment.body : element.comment.body.value + ); + } else { + return nls.localize('resourceWithCommentLabelFile', + "Comment from ${0} in {1}, source: {2}", + element.comment.userName, + basename(element.resource), + (typeof element.comment.body === 'string') ? element.comment.body : element.comment.body.value + ); + } } return ''; }, @@ -385,7 +395,7 @@ export class CommentsPanel extends FilterViewPane implements ICommentsView { options: { pinned: pinned, preserveFocus: preserveFocus, - selection: range + selection: range ?? new Range(1, 1, 1, 1) } }, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => { if (editor) { diff --git a/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts index c66072f9640..d20c6bc6187 100644 --- a/src/vs/workbench/contrib/comments/common/commentModel.ts +++ b/src/vs/workbench/contrib/comments/common/commentModel.ts @@ -16,14 +16,14 @@ export interface ICommentThreadChangedEvent extends CommentThreadChangedEvent