diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 6034476466..1cbcf82aa8 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -136,6 +136,12 @@ const ScrollingRegion = struct { // Precondition: top < bottom top: usize, bottom: usize, + + // Left/right scroll regions. + // Precondition: right > left + // Precondition: right <= cols - 1 + left: usize, + right: usize, }; /// Initialize a new terminal. @@ -152,6 +158,8 @@ pub fn init(alloc: Allocator, cols: usize, rows: usize) !Terminal { .scrolling_region = .{ .top = 0, .bottom = rows - 1, + .left = 0, + .right = cols - 1, }, .pwd = std.ArrayList(u8).init(alloc), }; @@ -326,6 +334,8 @@ pub fn resize(self: *Terminal, alloc: Allocator, cols_req: usize, rows: usize) ! self.scrolling_region = .{ .top = 0, .bottom = rows - 1, + .left = 0, + .right = cols - 1, }; } @@ -1524,11 +1534,16 @@ pub fn carriageReturn(self: *Terminal) void { const tracy = trace(@src()); defer tracy.end(); - // TODO: left/right margin mode - // TODO: origin mode - - self.screen.cursor.x = 0; + // Always reset pending wrap state self.screen.cursor.pending_wrap = false; + + // In origin mode we always move to the left margin + self.screen.cursor.x = if (self.modes.get(.origin)) + self.scrolling_region.left + else if (self.screen.cursor.x >= self.scrolling_region.left) + self.scrolling_region.left + else + 0; } /// Linefeed moves the cursor to the next line. @@ -1759,11 +1774,8 @@ pub fn setScrollingRegion(self: *Terminal, top: usize, bottom: usize) void { b = self.rows; } - self.scrolling_region = .{ - .top = t - 1, - .bottom = b - 1, - }; - + self.scrolling_region.top = t - 1; + self.scrolling_region.bottom = b - 1; self.setCursorPos(1, 1); } @@ -1871,7 +1883,12 @@ pub fn fullReset(self: *Terminal, alloc: Allocator) void { self.screen.saved_cursor = .{}; self.screen.selection = null; self.screen.kitty_keyboard = .{}; - self.scrolling_region = .{ .top = 0, .bottom = self.rows - 1 }; + self.scrolling_region = .{ + .top = 0, + .bottom = self.rows - 1, + .left = 0, + .right = self.cols - 1, + }; self.previous_char = null; self.eraseDisplay(alloc, .scrollback, false); self.eraseDisplay(alloc, .complete, false); @@ -2195,6 +2212,37 @@ test "Terminal: carriage return unsets pending wrap" { try testing.expect(t.screen.cursor.pending_wrap == false); } +test "Terminal: carriage return origin mode moves to left margin" { + var t = try init(testing.allocator, 5, 80); + defer t.deinit(testing.allocator); + + t.modes.set(.origin, true); + t.screen.cursor.x = 0; + t.scrolling_region.left = 2; + t.carriageReturn(); + try testing.expectEqual(@as(usize, 2), t.screen.cursor.x); +} + +test "Terminal: carriage return left of left margin moves to zero" { + var t = try init(testing.allocator, 5, 80); + defer t.deinit(testing.allocator); + + t.screen.cursor.x = 1; + t.scrolling_region.left = 2; + t.carriageReturn(); + try testing.expectEqual(@as(usize, 0), t.screen.cursor.x); +} + +test "Terminal: carriage return right of left margin moves to left margin" { + var t = try init(testing.allocator, 5, 80); + defer t.deinit(testing.allocator); + + t.screen.cursor.x = 3; + t.scrolling_region.left = 2; + t.carriageReturn(); + try testing.expectEqual(@as(usize, 2), t.screen.cursor.x); +} + test "Terminal: backspace" { var t = try init(testing.allocator, 80, 80); defer t.deinit(testing.allocator);