diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 4b3503072..467c67fd6 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -1469,6 +1469,19 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void { const row = self.screen.getRow(.{ .active = self.screen.cursor.y - 1 }); if (!row.isWrapped()) break; } + + // UNDEFINED TERMINAL BEHAVIOR. This situation is not handled in xterm + // and currently results in a crash in xterm. Given no other known + // terminal [to me] implements XTREVWRAP2, I decided to just mimick + // the behavior of xterm up and not including the crash by wrapping + // up to the (0, 0) and stopping there. My reasoning is that for an + // appropriately sized value of "count" this is the behavior that xterm + // would have. This is unit tested. + if (self.screen.cursor.y == 0) { + assert(self.screen.cursor.x == 0); + break; + } + self.screen.cursor.y -= 1; self.screen.cursor.x = right_margin; count -= 1; @@ -6125,6 +6138,22 @@ test "Terminal: cursorLeft extended reverse wrap is priority if both set" { } } +test "Terminal: cursorLeft extended reverse wrap above top scroll region" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + t.modes.set(.wraparound, true); + t.modes.set(.reverse_wrap_extended, true); + + t.setTopAndBottomMargin(3, 0); + t.setCursorPos(2, 1); + t.cursorLeft(1000); + + try testing.expectEqual(@as(usize, 0), t.screen.cursor.x); + try testing.expectEqual(@as(usize, 0), t.screen.cursor.y); +} + test "Terminal: cursorDown basic" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 0f3c073d0..e48125fce 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -60,6 +60,8 @@ pub fn Stream(comptime Handler: type) type { for (actions) |action_opt| { const action = action_opt orelse continue; + // log.info("action: {}", .{action}); + // If this handler handles everything manually then we do nothing // if it can be processed. if (@hasDecl(T, "handleManually")) { @@ -75,11 +77,6 @@ pub fn Stream(comptime Handler: type) type { if (processed) continue; } - // if (action_opt) |action| { - // if (action != .print) - // log.info("action: {}", .{action}); - // } - switch (action) { .print => |p| if (@hasDecl(T, "print")) try self.handler.print(p), .execute => |code| try self.execute(code),