Skip to content

Commit 76ef361

Browse files
authored
Merge pull request microsoft#257769 from mjbvz/legislative-mouse
Don't let chat output renderers block mouse wheel
2 parents 266ace5 + 674fabe commit 76ef361

File tree

7 files changed

+38
-9
lines changed

7 files changed

+38
-9
lines changed

src/vs/base/browser/ui/list/listWidget.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { isNumber } from '../../../common/types.js';
2929
import './list.css';
3030
import { IIdentityProvider, IKeyboardNavigationDelegate, IKeyboardNavigationLabelProvider, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IListEvent, IListGestureEvent, IListMouseEvent, IListElementRenderDetails, IListRenderer, IListTouchEvent, IListVirtualDelegate, ListError } from './list.js';
3131
import { IListView, IListViewAccessibilityProvider, IListViewDragAndDrop, IListViewOptions, IListViewOptionsUpdate, ListViewTargetSector, ListView } from './listView.js';
32-
import { StandardMouseEvent } from '../../mouseEvent.js';
32+
import { IMouseWheelEvent, StandardMouseEvent } from '../../mouseEvent.js';
3333
import { autorun, constObservable, IObservable } from '../../../common/observable.js';
3434

3535
interface ITraitChangeEvent {
@@ -1971,6 +1971,10 @@ export class List<T> implements ISpliceable<T>, IDisposable {
19711971
this.styleController.style(styles);
19721972
}
19731973

1974+
delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
1975+
this.view.delegateScrollFromMouseWheelEvent(browserEvent);
1976+
}
1977+
19741978
private toListEvent({ indexes, browserEvent }: ITraitChangeEvent) {
19751979
return { indexes, elements: indexes.map(i => this.view.element(i)), browserEvent };
19761980
}

src/vs/base/browser/ui/tree/abstractTree.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { IHoverDelegate } from '../hover/hoverDelegate.js';
3737
import { createInstantHoverDelegate } from '../hover/hoverDelegateFactory.js';
3838
import { autorun, constObservable } from '../../../common/observable.js';
3939
import { alert } from '../aria/aria.js';
40+
import { IMouseWheelEvent } from '../../mouseEvent.js';
4041

4142
class TreeElementsDragAndDropData<T, TFilterData, TContext> extends ElementsDragAndDropData<T, TContext> {
4243

@@ -3224,6 +3225,10 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
32243225
return new TreeNavigator(this.view, this.model, start);
32253226
}
32263227

3228+
delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent): void {
3229+
this.view.delegateScrollFromMouseWheelEvent(browserEvent);
3230+
}
3231+
32273232
dispose(): void {
32283233
dispose(this.disposables);
32293234
this.stickyScrollController?.dispose();

src/vs/workbench/contrib/chat/browser/chat.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { IMouseWheelEvent } from '../../../../base/browser/mouseEvent.js';
67
import { Event } from '../../../../base/common/event.js';
78
import { IDisposable } from '../../../../base/common/lifecycle.js';
89
import { URI } from '../../../../base/common/uri.js';
@@ -224,6 +225,8 @@ export interface IChatWidget {
224225
getViewState(): IChatViewState;
225226
togglePaused(): void;
226227
lockToCodingAgent(name: string): void;
228+
229+
delegateScrollFromMouseWheelEvent(event: IMouseWheelEvent): void;
227230
}
228231

229232

src/vs/workbench/contrib/chat/browser/chatContentParts/chatContentParts.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export interface IChatContentPart extends IDisposable {
3131
}
3232

3333
export interface IChatContentPartRenderContext {
34-
element: ChatTreeItem;
35-
elementIndex: number;
36-
container: HTMLElement;
37-
content: ReadonlyArray<IChatRendererContent>;
38-
contentIndex: number;
39-
preceedingContentParts: ReadonlyArray<IChatContentPart>;
34+
readonly element: ChatTreeItem;
35+
readonly elementIndex: number;
36+
readonly container: HTMLElement;
37+
readonly content: ReadonlyArray<IChatRendererContent>;
38+
readonly contentIndex: number;
39+
readonly preceedingContentParts: ReadonlyArray<IChatContentPart>;
4040
}

src/vs/workbench/contrib/chat/browser/chatContentParts/toolInvocationParts/chatToolOutputPart.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { localize } from '../../../../../../nls.js';
1212
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
1313
import { IChatToolInvocation, IChatToolInvocationSerialized, IToolResultOutputDetailsSerialized } from '../../../common/chatService.js';
1414
import { IToolResultOutputDetails } from '../../../common/languageModelToolsService.js';
15-
import { IChatCodeBlockInfo } from '../../chat.js';
15+
import { IChatCodeBlockInfo, IChatWidgetService } from '../../chat.js';
1616
import { IChatOutputRendererService } from '../../chatOutputItemRenderer.js';
1717
import { IChatContentPartRenderContext } from '../chatContentParts.js';
1818
import { ChatCustomProgressPart } from '../chatProgressContentPart.js';
@@ -28,8 +28,9 @@ export class ChatToolOutputSubPart extends BaseChatToolInvocationSubPart {
2828

2929
constructor(
3030
toolInvocation: IChatToolInvocation | IChatToolInvocationSerialized,
31-
_context: IChatContentPartRenderContext,
31+
private readonly context: IChatContentPartRenderContext,
3232
@IChatOutputRendererService private readonly chatOutputItemRendererService: IChatOutputRendererService,
33+
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
3334
@IInstantiationService private readonly instantiationService: IInstantiationService,
3435
) {
3536
super(toolInvocation);
@@ -55,6 +56,7 @@ export class ChatToolOutputSubPart extends BaseChatToolInvocationSubPart {
5556
private createOutputPart(details: IToolResultOutputDetails): HTMLElement {
5657
const parent = dom.$('div.webview-output');
5758
parent.style.maxHeight = '80vh';
59+
// TODO: we should cache the height when restoring to avoid extra layout shifts
5860

5961
const progressMessage = dom.$('span');
6062
progressMessage.textContent = localize('loading', 'Rendering tool output...');
@@ -75,6 +77,14 @@ export class ChatToolOutputSubPart extends BaseChatToolInvocationSubPart {
7577
this._register(renderedItem.onDidChangeHeight(() => {
7678
this._onDidChangeHeight.fire();
7779
}));
80+
81+
this._register(renderedItem.webview.onDidWheel(e => {
82+
this.chatWidgetService.getWidgetBySessionId(this.context.element.sessionId)?.delegateScrollFromMouseWheelEvent({
83+
...e,
84+
preventDefault: () => { },
85+
stopPropagation: () => { }
86+
});
87+
}));
7888
}, (error) => {
7989
// TODO: show error in UI too
8090
console.error('Error rendering tool output:', error);

src/vs/workbench/contrib/chat/browser/chatOutputItemRenderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface RegisterOptions {
3232

3333
export interface RenderedOutputPart extends IDisposable {
3434
readonly onDidChangeHeight: Event<number>;
35+
readonly webview: IWebview;
3536
}
3637

3738
export interface IChatOutputRendererService {
@@ -102,6 +103,7 @@ export class ChatOutputRendererService extends Disposable implements IChatOutput
102103
await rendererData.renderer.renderOutputPart(mime, data, webview, token);
103104

104105
return {
106+
webview,
105107
onDidChangeHeight: onDidChangeHeight.event,
106108
dispose: () => {
107109
store.dispose();

src/vs/workbench/contrib/chat/browser/chatWidget.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import { CancellationToken } from '../../../../base/common/cancellation.js';
7474
import { ComputeAutomaticInstructions } from '../common/promptSyntax/computeAutomaticInstructions.js';
7575
import { startupExpContext, StartupExperimentGroup } from '../../../services/coreExperimentation/common/coreExperimentationService.js';
7676
import { IWorkspaceContextService, WorkbenchState } from '../../../../platform/workspace/common/workspace.js';
77+
import { IMouseWheelEvent } from '../../../../base/browser/mouseEvent.js';
7778

7879
const $ = dom.$;
7980

@@ -2181,6 +2182,10 @@ export class ChatWidget extends Disposable implements IChatWidget {
21812182
// Remove any existing agent prefix (e.g., @agent) from the beginning
21822183
return text.replace(/^@\w+\s*/, '');
21832184
}
2185+
2186+
delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent): void {
2187+
this.tree.delegateScrollFromMouseWheelEvent(browserEvent);
2188+
}
21842189
}
21852190

21862191
export class ChatWidgetService extends Disposable implements IChatWidgetService {

0 commit comments

Comments
 (0)