From d657bce2d12045cfdb0f396687b5353e0a727980 Mon Sep 17 00:00:00 2001 From: Caleb Foust Date: Mon, 23 Oct 2023 19:15:36 -0400 Subject: [PATCH] fix: bug with empty lines --- pkg/mux/screen/replay/replay_test.go | 28 +++++++++++++++++++--------- pkg/mux/screen/replay/screen.go | 16 +++++++++++++++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/pkg/mux/screen/replay/replay_test.go b/pkg/mux/screen/replay/replay_test.go index c99e8c84..0341bc37 100644 --- a/pkg/mux/screen/replay/replay_test.go +++ b/pkg/mux/screen/replay/replay_test.go @@ -65,15 +65,15 @@ func TestSearch(t *testing.T) { func TestIndex(t *testing.T) { var r = newReplay(createTestSession(), bind.NewEngine[bind.Action]()) - r.setIndex(2, 0) + r.gotoIndex(2, 0) require.Equal(t, "t ", r.getLine(0).String()[:2]) - r.setIndex(2, 1) + r.gotoIndex(2, 1) require.Equal(t, "te ", r.getLine(0).String()[:3]) - r.setIndex(2, 0) + r.gotoIndex(2, 0) require.Equal(t, "t ", r.getLine(0).String()[:2]) - r.setIndex(2, -1) + r.gotoIndex(2, -1) require.Equal(t, "test", r.getLine(0).String()[:4]) - r.setIndex(4, -1) + r.gotoIndex(4, -1) require.Equal(t, "take", r.getLine(0).String()[:4]) } @@ -86,8 +86,8 @@ func TestViewport(t *testing.T) { var r = newReplay(s.Events(), bind.NewEngine[bind.Action]()) input(r, geom.Size{R: 10, C: 10}) require.Equal(t, geom.Vec2{R: 0, C: 0}, r.minOffset) - require.Equal(t, geom.Vec2{R: 10, C: 10}, r.maxOffset) - require.Equal(t, geom.Vec2{R: 10, C: 10}, r.offset) + require.Equal(t, geom.Vec2{R: 11, C: 10}, r.maxOffset) + require.Equal(t, geom.Vec2{R: 11, C: 10}, r.offset) } func TestScroll(t *testing.T) { @@ -105,7 +105,7 @@ func TestScroll(t *testing.T) { ) var r = newReplay(s.Events(), bind.NewEngine[bind.Action]()) - input(r, geom.Size{R: 2, C: 10}) + input(r, geom.Size{R: 3, C: 10}) require.Equal(t, 1, r.cursor.R) require.Equal(t, 5, r.cursor.C) require.Equal(t, 5, r.desiredCol) @@ -155,7 +155,7 @@ func TestCursor(t *testing.T) { ) var r = newReplay(s.Events(), bind.NewEngine[bind.Action]()) - input(r, geom.Size{R: 2, C: 10}) + input(r, geom.Size{R: 3, C: 10}) require.Equal(t, 2, r.offset.R) require.Equal(t, 1, r.cursor.R) require.Equal(t, 4, r.cursor.C) @@ -187,3 +187,13 @@ func TestCursor(t *testing.T) { C: 0, }, r.viewportToTerm(r.cursor)) } + +func TestEmpty(t *testing.T) { + s := sessions.NewSimulator() + s.Add( + geom.Size{R: 5, C: 10}, + ) + + var r = newReplay(s.Events(), bind.NewEngine[bind.Action]()) + input(r, geom.Size{R: 3, C: 10}, ActionCursorDown) +} diff --git a/pkg/mux/screen/replay/screen.go b/pkg/mux/screen/replay/screen.go index 57afa82e..497dbcd3 100644 --- a/pkg/mux/screen/replay/screen.go +++ b/pkg/mux/screen/replay/screen.go @@ -166,9 +166,16 @@ func (r *Replay) recalculateViewport() { // Get the glyphs for a row in term space. func (r *Replay) getLine(row int) emu.Line { - var line emu.Line screen := r.terminal.Screen() history := r.terminal.History() + + // Handle out-of-bounds lines + clamped := geom.Clamp(row, -len(history), r.getTerminalSize().R-1) + if clamped != row { + return nil + } + + var line emu.Line if row < 0 { line = history[len(history)+row] } else { @@ -238,6 +245,10 @@ func getNonWhitespace(line emu.Line) (first, last int) { // and down in a text editor. func (r *Replay) resolveDesiredColumn(point geom.Vec2) int { line := r.getLine(point.R) + if line == nil { + return 0 + } + occupancy := getOccupancy(line) // desiredCol occupied -> return that col @@ -369,6 +380,9 @@ func (r *Replay) moveCursorDelta(dy, dx int) { // Motion to the right is bounded to the last non-whitespace character if newPos.C > oldPos.C { line := r.getLine(newPos.R) + if line == nil { + return + } _, lastCell := getNonWhitespace(line) newPos.C = geom.Min(lastCell, newPos.C) }