Change:
<!-- Do Not Delete This! bugreporttemplate --<!-- Please read our Rules of Conduct: --<!-- Read our guide about submitting issues: --<!-- Search existing issues to avoid creating duplicates. --<!-- Test using the latest Insiders build to see if your issue has already been fixed: --<!-- Instead of creating your report here, use 'Report Issue' from the 'Help' menu in VS Code to pre-fill useful information. --<!-- Launch with to check. --Does this issue occur when all extensions are disabled?: Yes <!-- If you answered No above, use 'Help: Start Extension Bisect' from Command Palette to try to identify the cause. --<!-- Issues caused by an extension need to be reported directly to the extension publisher. The 'Help Report Issue' dialog can assist with this. --- VS Code Version: 1.78.0 (Universal) OS Version: macOS Ventura 13.3.1 (a) Steps to Reproduce: a comment thread with multiple replies. on "Reply". typing a response. write , e.g. to add new replies fetched in the background by the extension. Focus is removed from the Reply input when the comment list renders. When the Reply input is open but empty, this will also close the input again, which is jarring. ! Expected behavior would be that updates to earlier replies (at least as long as they preserve ) do not affect focus. When the Reply input is empty, it should remain open if new comments come in. cc
Thanks for creating this issue! It looks like you may be using an old version of VS Code, the latest stable release is 1.78.1. Please try upgrading to the latest version and checking whether this issue remains. Happy Coding!
To clarify our use case a bit more: we don't expect background updates to happening frequently (i.e. not live collaboration similar to Google Docs) but we might occasionally still receive a single new round of comments from a reviewer while the change author is currently typing a reply. As far as I know there is no way for our extension to learn if the Reply input is open with pending content, meaning we cannot delay automatic background updates to wait until we won't interrupt the user.
Focus goes back to so it appears to be lost, not stolen.
It's a surprising and inconvenient behavior that updating fields in vscode.CommentThread steals focus. It'd be great if the APIs are updated not to steal the focus. Our extension (for Gerrit code review integration) has a method to decorate a vscode.CommentThread, which currently always updates all the CommenThread's fields even if there's a field having no change. This construct makes the implementation simple, removing the need of checking the equality for every field. All was good - until we realized the bug of the focus being stolen at an unexpected timing while the user is editing the code. We will workaround the issue by introducing equality check everywhere, but I hope we could remove the workaround in future.

Discussion:
return; } <del> updateCommentThread(commentThread: languages.CommentThread<T>) { </del> <ins> updateCommentThread(commentThread: languages.CommentThread<T>, preserveFocus: boolean) { </ins> const oldCommentsLen = this._commentElements.length; const newCommentsLen = commentThread.comments ? commentThread.comments.length : 0;

} this._updateAriaLabel(); <del> this._setFocusedComment(this._focusedComment); </del> <ins> if (!preserveFocus) { this._setFocusedComment(this._focusedComment); } </ins> } private _updateAriaLabel() {

this._commentThreadDisposables = []; this._bindCommentThreadListeners(); <del> this._body.updateCommentThread(commentThread); </del> <ins> this._body.updateCommentThread(commentThread, this._commentReply?.isCommentEditorFocused() ?? false); </ins> this._threadIsEmpty.set(!this._body.length); this._header.updateCommentThread(commentThread); this._commentReply?.updateCommentThread(commentThread);

} } <del> if (shouldMoveWidget && this._isExpanded) { </del> <ins> if ((shouldMoveWidget && this._isExpanded) || (this._commentThread.collapsibleState === languages.CommentThreadCollapsibleState.Expanded && !this._isExpanded)) { </ins> this.show(this.arrowPosition(this._commentThread.range), 2); <del> } if (this._commentThread.collapsibleState === languages.CommentThreadCollapsibleState.Expanded) { this.show(this.arrowPosition(this._commentThread.range), 2); } else { </del> <ins> } else if (this._commentThread.collapsibleState !== languages.CommentThreadCollapsibleState.Expanded) { </ins> this.hide(); } }