Skip to content

Commit be67c88

Browse files
committed
Fix viewport jumping to top after exiting vim/less; bump to 1.2.6
The auto-scroll-restore logic in dataReceived didn't account for the alternate screen buffer. While in vim/less the alt buffer's yDisp is 0, so wasInScrollback (preYDisp < latestYBase) evaluated true the whole time. On exit, the buffer switch back to normal happens inside super.dataReceived, then the stale wasInScrollback==true ran scrollTo(row: 0) on the now-active normal buffer, snapping it to the top. Guard all scroll bookkeeping behind staying on the normal buffer for the whole chunk, and re-read terminal.buffer fresh after super instead of using a captured (potentially stale alt-buffer) reference.
1 parent c8dcb84 commit be67c88

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

Notchy.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@
290290
"@executable_path/../Frameworks",
291291
);
292292
MACOSX_DEPLOYMENT_TARGET = 15.6;
293-
MARKETING_VERSION = 1.2.5;
293+
MARKETING_VERSION = 1.2.6;
294294
PRODUCT_BUNDLE_IDENTIFIER = li.luy.notchy;
295295
PRODUCT_NAME = "$(TARGET_NAME)";
296296
REGISTER_APP_GROUPS = YES;
@@ -330,7 +330,7 @@
330330
"@executable_path/../Frameworks",
331331
);
332332
MACOSX_DEPLOYMENT_TARGET = 15.6;
333-
MARKETING_VERSION = 1.2.5;
333+
MARKETING_VERSION = 1.2.6;
334334
PRODUCT_BUNDLE_IDENTIFIER = li.luy.notchy;
335335
PRODUCT_NAME = "$(TARGET_NAME)";
336336
REGISTER_APP_GROUPS = YES;

Notchy/TerminalManager.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,17 +261,29 @@ class ClickThroughTerminalView: LocalProcessTerminalView {
261261
}
262262

263263
override func dataReceived(slice: ArraySlice<UInt8>) {
264-
let buffer = getTerminal().buffer
265-
let preYDisp = buffer.yDisp
266-
let wasInScrollback = preYDisp < latestYBase
264+
let terminal = getTerminal()
265+
let wasAlternate = terminal.isCurrentBufferAlternate
266+
let preYDisp = terminal.buffer.yDisp
267+
// Only treat the viewport as "in scrollback" on the normal buffer.
268+
// The alternate buffer (vim/less) has no scrollback and its yDisp is
269+
// unrelated to latestYBase, so comparing them would spuriously fire.
270+
let wasInScrollback = !wasAlternate && preYDisp < latestYBase
267271

268272
super.dataReceived(slice: slice)
269273
hasNewData = true
270274

275+
// Re-read the buffer: super may have switched buffers (entering or
276+
// leaving vim via \e[?1049h/l). yDisp isn't comparable across that
277+
// switch, so skip all scroll bookkeeping unless we stayed on the
278+
// normal buffer for the whole chunk. Without this guard, leaving the
279+
// alternate screen runs scrollTo on the freshly-restored normal
280+
// buffer and snaps it to the top.
281+
guard !wasAlternate, !terminal.isCurrentBufferAlternate else { return }
282+
271283
// Snapshot the new yBase so extractAllLines can read the live bottom
272284
// even when the viewport is parked in scrollback.
273-
if buffer.yDisp != preYDisp {
274-
latestYBase = buffer.yDisp
285+
if terminal.buffer.yDisp != preYDisp {
286+
latestYBase = terminal.buffer.yDisp
275287
}
276288

277289
// Only restore the viewport if the user was already browsing

0 commit comments

Comments
 (0)