Skip to content

Commit 3b3e8c2

Browse files
authored
Merge pull request microsoft#210239 from microsoft/tyriar/copilot-4720
Offset terminal when inline chat appears to ensure cursor is visible
2 parents a43d090 + 08d545f commit 3b3e8c2

File tree

4 files changed

+39
-3
lines changed

4 files changed

+39
-3
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr
149149

150150
xtermReady(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
151151
this._chatWidget = new Lazy(() => {
152-
const chatWidget = this._register(this._instantiationService.createInstance(TerminalChatWidget, this._instance.domElement!, this._instance));
152+
const chatWidget = this._register(this._instantiationService.createInstance(TerminalChatWidget, this._instance.domElement!, this._instance, xterm));
153153
this._register(chatWidget.focusTracker.onDidFocus(() => {
154154
TerminalChatController.activeChatWidget = this;
155155
if (!isDetachedTerminalInstance(this._instance)) {

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

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

6+
import type { Terminal as RawXtermTerminal } from '@xterm/xterm';
67
import { Dimension, IFocusTracker, trackFocus } from 'vs/base/browser/dom';
78
import { Event } from 'vs/base/common/event';
89
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
10+
import { MicrotaskDelay } from 'vs/base/common/symbols';
911
import 'vs/css!./media/terminalChatWidget';
1012
import { localize } from 'vs/nls';
1113
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1214
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1315
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
1416
import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService';
1517
import { InlineChatWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget';
16-
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
18+
import { ITerminalInstance, type IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
1719
import { MENU_TERMINAL_CHAT_INPUT, MENU_TERMINAL_CHAT_WIDGET, MENU_TERMINAL_CHAT_WIDGET_FEEDBACK, MENU_TERMINAL_CHAT_WIDGET_STATUS, TerminalChatCommandId, TerminalChatContextKeys } from 'vs/workbench/contrib/terminalContrib/chat/browser/terminalChat';
20+
import { TerminalStickyScrollContribution } from 'vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution';
1821

1922
const enum Constants {
2023
HorizontalMargin = 10
@@ -35,6 +38,7 @@ export class TerminalChatWidget extends Disposable {
3538
constructor(
3639
private readonly _terminalElement: HTMLElement,
3740
private readonly _instance: ITerminalInstance,
41+
private readonly _xterm: IXtermTerminal & { raw: RawXtermTerminal },
3842
@IInstantiationService private readonly _instantiationService: IInstantiationService,
3943
@IContextKeyService private readonly _contextKeyService: IContextKeyService
4044
) {
@@ -73,6 +77,7 @@ export class TerminalChatWidget extends Disposable {
7377
this._register(Event.any(
7478
this._inlineChatWidget.onDidChangeHeight,
7579
this._instance.onDimensionsChanged,
80+
Event.debounce(this._xterm.raw.onCursorMove, () => void 0, MicrotaskDelay),
7681
)(() => this._relayout()));
7782

7883
const observer = new ResizeObserver(() => this._relayout());
@@ -102,6 +107,7 @@ export class TerminalChatWidget extends Disposable {
102107
}
103108
this._dimension = new Dimension(width, height);
104109
this._inlineChatWidget.layout(this._dimension);
110+
105111
this._updateVerticalPosition();
106112
}
107113

@@ -134,7 +140,9 @@ export class TerminalChatWidget extends Disposable {
134140
return;
135141
}
136142
if (top > terminalWrapperHeight - widgetHeight) {
137-
this._container.style.top = '';
143+
this._setTerminalOffset(top - (terminalWrapperHeight - widgetHeight));
144+
} else {
145+
this._setTerminalOffset(undefined);
138146
}
139147
}
140148

@@ -154,6 +162,18 @@ export class TerminalChatWidget extends Disposable {
154162
this._visibleContextKey.set(false);
155163
this._inlineChatWidget.value = '';
156164
this._instance.focus();
165+
this._setTerminalOffset(undefined);
166+
}
167+
private _setTerminalOffset(offset: number | undefined) {
168+
if (offset === undefined || this._container.classList.contains('hide')) {
169+
this._terminalElement.style.position = '';
170+
this._terminalElement.style.bottom = '';
171+
TerminalStickyScrollContribution.get(this._instance)?.hideUnlock();
172+
} else {
173+
this._terminalElement.style.position = 'relative';
174+
this._terminalElement.style.bottom = `${offset}px`;
175+
TerminalStickyScrollContribution.get(this._instance)?.hideLock();
176+
}
157177
}
158178
focus(): void {
159179
this._inlineChatWidget.focus();

src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollContribution.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ export class TerminalStickyScrollContribution extends Disposable implements ITer
6060
this._refreshState();
6161
}
6262

63+
hideLock() {
64+
this._overlay.value?.lockHide();
65+
}
66+
67+
hideUnlock() {
68+
this._overlay.value?.unlockHide();
69+
}
70+
6371
private _refreshState(): void {
6472
if (this._overlay.value) {
6573
this._tryDisable();

src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ export class TerminalStickyScrollOverlay extends Disposable {
129129
});
130130
}
131131

132+
lockHide() {
133+
this._element?.classList.add('lock-hide');
134+
}
135+
136+
unlockHide() {
137+
this._element?.classList.remove('lock-hide');
138+
}
139+
132140
private _setState(state: OverlayState) {
133141
if (this._state === state) {
134142
return;

0 commit comments

Comments
 (0)