From c989f0472793e511640c27f3bffd858b055aec90 Mon Sep 17 00:00:00 2001 From: codestory Date: Thu, 13 Feb 2025 15:44:03 +0000 Subject: [PATCH 1/4] refactor: improve chat widget's auto-scrolling logic with clearer variable names --- .../contrib/aideAgent/browser/aideAgentWidget.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts index 2ac92c6c07f..2268ccd0a13 100644 --- a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts +++ b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts @@ -665,12 +665,12 @@ export class ChatWidget extends Disposable implements IChatWidget { private onDidChangeTreeContentHeight(): void { if (this.tree.scrollHeight !== this.previousTreeScrollHeight) { - // Due to rounding, the scrollTop + renderHeight will not exactly match the scrollHeight. - // Consider the tree to be scrolled all the way down if it is within 2px of the bottom. - const lastElementWasVisible = this.tree.scrollTop + this.tree.renderHeight >= this.previousTreeScrollHeight - 2; - if (lastElementWasVisible) { + // Check if we're near the bottom of the list (within 2px) + const isNearBottom = this.tree.scrollTop + this.tree.renderHeight >= this.previousTreeScrollHeight - 2; + + if (isNearBottom) { dom.scheduleAtNextAnimationFrame(dom.getWindow(this.listContainer), () => { - // Can't set scrollTop during this event listener, the list might overwrite the change + // Scroll to the new bottom this.scrollToEnd(); }, 0); } @@ -1225,4 +1225,4 @@ export class ChatWidgetService implements IAideAgentWidgetService { toDisposable(() => this._widgets.splice(this._widgets.indexOf(newWidget), 1)) ); } -} +} \ No newline at end of file From 51ae0834338a62d6a6ea5161dbf4aa5ea50b9cdf Mon Sep 17 00:00:00 2001 From: codestory Date: Thu, 13 Feb 2025 15:47:30 +0000 Subject: [PATCH 2/4] refactor: improve chat widget scrolling behavior --- .../contrib/aideAgent/browser/aideAgentWidget.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts index 2268ccd0a13..a25531a2431 100644 --- a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts +++ b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts @@ -664,10 +664,15 @@ export class ChatWidget extends Disposable implements IChatWidget { } private onDidChangeTreeContentHeight(): void { + // Store current scroll info before any changes + const scrollTop = this.tree.scrollTop; + const renderHeight = this.tree.renderHeight; + const currentScrollBottom = scrollTop + renderHeight; + + // Check if we're near the bottom of the list (within 2px) + const isNearBottom = currentScrollBottom >= this.previousTreeScrollHeight - 2; + if (this.tree.scrollHeight !== this.previousTreeScrollHeight) { - // Check if we're near the bottom of the list (within 2px) - const isNearBottom = this.tree.scrollTop + this.tree.renderHeight >= this.previousTreeScrollHeight - 2; - if (isNearBottom) { dom.scheduleAtNextAnimationFrame(dom.getWindow(this.listContainer), () => { // Scroll to the new bottom From 3e79c8f681c5e90b973e2749cf428effeed0f082 Mon Sep 17 00:00:00 2001 From: codestory Date: Thu, 13 Feb 2025 15:53:25 +0000 Subject: [PATCH 3/4] fix: reset userScrolledAway flag when revealing last chat item --- src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts index a25531a2431..e774aaed8c6 100644 --- a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts +++ b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts @@ -406,6 +406,7 @@ export class ChatWidget extends Disposable implements IChatWidget { if (this.lastItem) { const offset = Math.max(this.lastItem.currentRenderedHeight ?? 0, 1e6); this.tree.reveal(this.lastItem, offset); + this._userScrolledAway = false; } } From a08f6e003b432daec9dc46a9d3396588e0b4d7a5 Mon Sep 17 00:00:00 2001 From: codestory Date: Thu, 13 Feb 2025 17:32:57 +0000 Subject: [PATCH 4/4] fix: improve chat widget scrolling behavior to respect user interactions --- .../aideAgent/browser/aideAgentWidget.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts index e774aaed8c6..ff05dde6d87 100644 --- a/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts +++ b/src/vs/workbench/contrib/aideAgent/browser/aideAgentWidget.ts @@ -161,6 +161,7 @@ export class ChatWidget extends Disposable implements IChatWidget { } private previousTreeScrollHeight: number = 0; + private _userScrolledAway: boolean = false; private readonly viewModelDisposables = this._register(new DisposableStore()); private _viewModel: ChatViewModel | undefined; @@ -635,6 +636,14 @@ export class ChatWidget extends Disposable implements IChatWidget { })); this._register(this.tree.onDidScroll(() => { this._onDidScroll.fire(); + + // Check if user has scrolled away from the bottom + const scrollTop = this.tree.scrollTop; + const renderHeight = this.tree.renderHeight; + const scrollHeight = this.tree.scrollHeight; + + // Consider the user scrolled away if they're not within 2px of the bottom + this._userScrolledAway = scrollTop + renderHeight < scrollHeight - 2; })); } @@ -665,16 +674,11 @@ export class ChatWidget extends Disposable implements IChatWidget { } private onDidChangeTreeContentHeight(): void { - // Store current scroll info before any changes - const scrollTop = this.tree.scrollTop; - const renderHeight = this.tree.renderHeight; - const currentScrollBottom = scrollTop + renderHeight; - - // Check if we're near the bottom of the list (within 2px) - const isNearBottom = currentScrollBottom >= this.previousTreeScrollHeight - 2; - if (this.tree.scrollHeight !== this.previousTreeScrollHeight) { - if (isNearBottom) { + // Check if we're near the bottom of the list (within 2px) + const isNearBottom = this.tree.scrollTop + this.tree.renderHeight >= this.previousTreeScrollHeight - 2; + + if (isNearBottom && !this._userScrolledAway) { dom.scheduleAtNextAnimationFrame(dom.getWindow(this.listContainer), () => { // Scroll to the new bottom this.scrollToEnd();