Skip to content

Commit e8980d8

Browse files
authored
Merge pull request #145252 from microsoft/tyriar/145241
Improve command navigation behavior
2 parents 53743df + afb8967 commit e8980d8

File tree

1 file changed

+28
-11
lines changed

1 file changed

+28
-11
lines changed

src/vs/workbench/contrib/terminal/browser/xterm/commandTrackerAddon.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
6565
this._selectionStart = null;
6666
}
6767

68-
scrollToPreviousCommand(scrollPosition: ScrollPosition = ScrollPosition.Top, retainSelection: boolean = false): void {
68+
scrollToPreviousCommand(scrollPosition: ScrollPosition = ScrollPosition.Middle, retainSelection: boolean = false): void {
6969
if (!this._terminal) {
7070
return;
7171
}
@@ -74,9 +74,11 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
7474
}
7575

7676
let markerIndex;
77-
const currentLineY = Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.active.baseY);
77+
const currentLineY = typeof this._currentMarker === 'object'
78+
? this._getTargetScrollLine(this._terminal, this._currentMarker, scrollPosition)
79+
: Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.active.baseY);
7880
const viewportY = this._terminal.buffer.active.viewportY;
79-
if (!retainSelection && currentLineY !== viewportY) {
81+
if (typeof this._currentMarker === 'object' ? !this._isMarkerInViewport(this._terminal, this._currentMarker) : currentLineY !== viewportY) {
8082
// The user has scrolled, find the line based on the current scroll position. This only
8183
// works when not retaining selection
8284
const markersBelowViewport = this._getCommandMarkers().filter(e => e.line >= viewportY).length;
@@ -104,7 +106,7 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
104106
this._scrollToMarker(this._currentMarker, scrollPosition);
105107
}
106108

107-
scrollToNextCommand(scrollPosition: ScrollPosition = ScrollPosition.Top, retainSelection: boolean = false): void {
109+
scrollToNextCommand(scrollPosition: ScrollPosition = ScrollPosition.Middle, retainSelection: boolean = false): void {
108110
if (!this._terminal) {
109111
return;
110112
}
@@ -113,9 +115,11 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
113115
}
114116

115117
let markerIndex;
116-
const currentLineY = Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.active.baseY);
118+
const currentLineY = typeof this._currentMarker === 'object'
119+
? this._getTargetScrollLine(this._terminal, this._currentMarker, scrollPosition)
120+
: Math.min(this._getLine(this._terminal, this._currentMarker), this._terminal.buffer.active.baseY);
117121
const viewportY = this._terminal.buffer.active.viewportY;
118-
if (!retainSelection && currentLineY !== viewportY) {
122+
if (typeof this._currentMarker === 'object' ? !this._isMarkerInViewport(this._terminal, this._currentMarker) : currentLineY !== viewportY) {
119123
// The user has scrolled, find the line based on the current scroll position. This only
120124
// works when not retaining selection
121125
const markersAboveViewport = this._getCommandMarkers().filter(e => e.line <= viewportY).length;
@@ -147,11 +151,24 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
147151
if (!this._terminal) {
148152
return;
149153
}
150-
let line = marker.line;
154+
if (!this._isMarkerInViewport(this._terminal, marker)) {
155+
const line = this._getTargetScrollLine(this._terminal, marker, position);
156+
this._terminal.scrollToLine(line);
157+
}
158+
}
159+
160+
private _getTargetScrollLine(terminal: Terminal, marker: IMarker, position: ScrollPosition) {
161+
// Middle is treated at 1/4 of the viewport's size because context below is almost always
162+
// more important than context above in the terminal.
151163
if (position === ScrollPosition.Middle) {
152-
line = Math.max(line - Math.floor(this._terminal.rows / 2), 0);
164+
return Math.max(marker.line - Math.floor(terminal.rows / 4), 0);
153165
}
154-
this._terminal.scrollToLine(line);
166+
return marker.line;
167+
}
168+
169+
private _isMarkerInViewport(terminal: Terminal, marker: IMarker) {
170+
const viewportY = terminal.buffer.active.viewportY;
171+
return marker.line >= viewportY && marker.line < viewportY + terminal.rows;
155172
}
156173

157174
selectToPreviousCommand(): void {
@@ -232,7 +249,7 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
232249
return marker.line;
233250
}
234251

235-
scrollToPreviousLine(xterm: Terminal, scrollPosition: ScrollPosition = ScrollPosition.Top, retainSelection: boolean = false): void {
252+
scrollToPreviousLine(xterm: Terminal, scrollPosition: ScrollPosition = ScrollPosition.Middle, retainSelection: boolean = false): void {
236253
if (!retainSelection) {
237254
this._selectionStart = null;
238255
}
@@ -255,7 +272,7 @@ export class CommandTrackerAddon extends Disposable implements ICommandTracker,
255272
this._scrollToMarker(this._currentMarker, scrollPosition);
256273
}
257274

258-
scrollToNextLine(xterm: Terminal, scrollPosition: ScrollPosition = ScrollPosition.Top, retainSelection: boolean = false): void {
275+
scrollToNextLine(xterm: Terminal, scrollPosition: ScrollPosition = ScrollPosition.Middle, retainSelection: boolean = false): void {
259276
if (!retainSelection) {
260277
this._selectionStart = null;
261278
}

0 commit comments

Comments
 (0)