From c089c37b90a8205cb6222782957811a9f4fa13fd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 7 Oct 2023 08:42:08 -0700 Subject: [PATCH] terminal: CUF handles right margin --- src/terminal/Terminal.zig | 83 ++++++++++++++++++++++++++++++++++--- website/app/vt/cuf/page.mdx | 83 +++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 website/app/vt/cuf/page.mdx diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 3b7f1713c..2fc0ee95c 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -1439,16 +1439,21 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void { /// maximum move distance then it is internally adjusted to the maximum. /// This sequence will not scroll the screen or scroll region. If amount is /// 0, adjust it to 1. -/// TODO: test -pub fn cursorRight(self: *Terminal, count: usize) void { +pub fn cursorRight(self: *Terminal, count_req: usize) void { const tracy = trace(@src()); defer tracy.end(); - self.screen.cursor.x += if (count == 0) 1 else count; + // Always resets pending wrap self.screen.cursor.pending_wrap = false; - if (self.screen.cursor.x >= self.cols) { - self.screen.cursor.x = self.cols - 1; - } + + // The max the cursor can move to depends where the cursor currently is + const max = if (self.screen.cursor.x <= self.scrolling_region.right) + self.scrolling_region.right + else + self.cols - 1; + + const count = @max(count_req, 1); + self.screen.cursor.x = @min(max, self.screen.cursor.x +| count); } /// Move the cursor down amount lines. If amount is greater than the maximum @@ -4044,3 +4049,69 @@ test "Terminal: cursorUp resets wrap" { try testing.expectEqualStrings("ABCDX", str); } } + +test "Terminal: cursorRight resets wrap" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + for ("ABCDE") |c| try t.print(c); + try testing.expect(t.screen.cursor.pending_wrap); + t.cursorRight(1); + try testing.expect(!t.screen.cursor.pending_wrap); + try t.print('X'); + + { + var str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("ABCDX", str); + } +} + +test "Terminal: cursorRight to the edge of screen" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + t.cursorRight(100); + try t.print('X'); + + { + var str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings(" X", str); + } +} + +test "Terminal: cursorRight left of right margin" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + t.scrolling_region.right = 2; + t.cursorRight(100); + try t.print('X'); + + { + var str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings(" X", str); + } +} + +test "Terminal: cursorRight right of right margin" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + t.scrolling_region.right = 2; + t.screen.cursor.x = 3; + t.cursorRight(100); + try t.print('X'); + + { + var str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings(" X", str); + } +} diff --git a/website/app/vt/cuf/page.mdx b/website/app/vt/cuf/page.mdx new file mode 100644 index 000000000..6e660c4f9 --- /dev/null +++ b/website/app/vt/cuf/page.mdx @@ -0,0 +1,83 @@ +import VTSequence from "@/components/VTSequence"; + +# Cursor Forward (CUF) + + + +Move the cursor `n` cells right. + +The parameter `n` must be an integer greater than or equal to 1. If `n` is less than +or equal to 0, adjust `n` to be 1. If `n` is omitted, `n` defaults to 1. + +This sequence always unsets the pending wrap state. + +The rightmost boundary the cursor can move to is determined by the current +cursor column and the [right margin](#TODO). If the cursor begins to the right +of the right margin, modify the right margin to be the rightmost column +of the screen for the duration of the sequence. The rightmost column the cursor +can be on is the right margin. + +Move the cursor `n` cells to the right up to and including the rightmost boundary. +This sequence never wraps or modifies cell content. This sequence is not affected +by any terminal modes. + +## Validation + +### CUF V-1: Pending Wrap is Unset + +```bash +cols=$(tput cols) +printf "\033[${cols}G" # move to last column +printf "A" # set pending wrap state +printf "\033[C" # move forward one +printf "XYZ" +``` + +``` +|_________X| +|YZ________| +``` + +### CUF V-2: Rightmost Boundary with Reverse Wrap Disabled + +```bash +printf "A" +printf "\033[500C" # forward larger than screen width +printf "B" +``` + +``` +|A________Bc +``` + +### CUF V-3: Left of the Right Margin + +```bash +printf "\033[1;1H" # move to top-left +printf "\033[0J" # clear screen +printf "\033[?69h" # enable left/right margins +printf "\033[3;5s" # scroll region left/right +printf "\033[1G" # move to left +printf "\033[500C" # forward larger than screen width +printf "X" +``` + +``` +|____X_____| +``` + +### CUF V-4: Right of the Right Margin + +```bash +printf "\033[1;1H" # move to top-left +printf "\033[0J" # clear screen +printf "\033[?69h" # enable left/right margins +printf "\033[3;5s" # scroll region left/right +printf "\033[6G" # move to right of margin +printf "\033[500C" # forward larger than screen width +printf "X" +``` + +``` +|_________X| +```