diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 6940be082..ecc599a98 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -432,6 +432,18 @@ pub fn Stream(comptime Handler: type) type { }, ) else log.warn("unimplemented CSI callback: {}", .{action}), + // HPR - Cursor Horizontal Position Relative + 'a' => if (@hasDecl(T, "setCursorColRelative")) try self.handler.setCursorColRelative( + switch (action.params.len) { + 0 => 1, + 1 => action.params[0], + else => { + log.warn("invalid HPR command: {}", .{action}); + return; + }, + }, + ) else log.warn("unimplemented CSI callback: {}", .{action}), + // Repeat Previous Char (REP) 'b' => if (@hasDecl(T, "printRepeat")) try self.handler.printRepeat( switch (action.params.len) { @@ -474,6 +486,18 @@ pub fn Stream(comptime Handler: type) type { }, ) else log.warn("unimplemented CSI callback: {}", .{action}), + // VPR - Cursor Vertical Position Relative + 'e' => if (@hasDecl(T, "setCursorRowRelative")) try self.handler.setCursorRowRelative( + switch (action.params.len) { + 0 => 1, + 1 => action.params[0], + else => { + log.warn("invalid VPR command: {}", .{action}); + return; + }, + }, + ) else log.warn("unimplemented CSI callback: {}", .{action}), + // TBC - Tab Clear // TODO: test 'g' => if (@hasDecl(T, "tabClear")) try self.handler.tabClear( diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 87d6600ac..cf6b1ab7c 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1316,10 +1316,24 @@ const StreamHandler = struct { self.terminal.setCursorPos(self.terminal.screen.cursor.y + 1, col); } + pub fn setCursorColRelative(self: *StreamHandler, offset: u16) !void { + self.terminal.setCursorPos( + self.terminal.screen.cursor.y + 1, + self.terminal.screen.cursor.x + 1 + offset, + ); + } + pub fn setCursorRow(self: *StreamHandler, row: u16) !void { self.terminal.setCursorPos(row, self.terminal.screen.cursor.x + 1); } + pub fn setCursorRowRelative(self: *StreamHandler, offset: u16) !void { + self.terminal.setCursorPos( + self.terminal.screen.cursor.y + 1 + offset, + self.terminal.screen.cursor.x + 1, + ); + } + pub fn setCursorPos(self: *StreamHandler, row: u16, col: u16) !void { self.terminal.setCursorPos(row, col); } diff --git a/website/app/vt/hpa/page.mdx b/website/app/vt/hpa/page.mdx index 67ab76d51..f0cd13278 100644 --- a/website/app/vt/hpa/page.mdx +++ b/website/app/vt/hpa/page.mdx @@ -7,3 +7,8 @@ import VTSequence from "@/components/VTSequence"; This sequence performs [cursor position (CUP)](/vt/cup) with `x` set to the parameterized value and `y` set to the current cursor position. There is no additional or different behavior for using `HPA`. + +Because this invokes `CUP`, the cursor row (`x`) can change if it is +outside the bounds of the `CUP` operation. For example, if +[origin mode](#TODO) is set and the current cursor position is outside +of the scroll region, the row will be adjusted. diff --git a/website/app/vt/hpr/page.mdx b/website/app/vt/hpr/page.mdx new file mode 100644 index 000000000..fbc865b52 --- /dev/null +++ b/website/app/vt/hpr/page.mdx @@ -0,0 +1,17 @@ +import VTSequence from "@/components/VTSequence"; + +# Horizontal Position Relative (HPR) + + + +This sequence performs [cursor position (CUP)](/vt/cup) with `x` set +to the current cursor column plus `x` and `y` set to the current cursor row. +There is no additional or different behavior for using `HPR`. + +The parameter `x` must be an integer greater than or equal to 1. If `x` is less than +or equal to 0, adjust `x` to be 1. If `x` is omitted, `x` defaults to 1. + +Because this invokes `CUP`, the cursor row (`y`) can change if it is +outside the bounds of the `CUP` operation. For example, if +[origin mode](#TODO) is set and the current cursor position is outside +of the scroll region, the row will be adjusted. diff --git a/website/app/vt/vpa/page.mdx b/website/app/vt/vpa/page.mdx index e663b1bbd..f25c745e1 100644 --- a/website/app/vt/vpa/page.mdx +++ b/website/app/vt/vpa/page.mdx @@ -7,3 +7,8 @@ import VTSequence from "@/components/VTSequence"; This sequence performs [cursor position (CUP)](/vt/cup) with `y` set to the parameterized value and `x` set to the current cursor position. There is no additional or different behavior for using `VPA`. + +Because this invokes `CUP`, the cursor column (`y`) can change if it is +outside the bounds of the `CUP` operation. For example, if +[origin mode](#TODO) is set and the current cursor position is outside +of the scroll region, the column will be adjusted. diff --git a/website/app/vt/vpr/page.mdx b/website/app/vt/vpr/page.mdx new file mode 100644 index 000000000..990b3185a --- /dev/null +++ b/website/app/vt/vpr/page.mdx @@ -0,0 +1,17 @@ +import VTSequence from "@/components/VTSequence"; + +# Vertical Position Relative (VPR) + + + +This sequence performs [cursor position (CUP)](/vt/cup) with `y` set +to the current cursor row plus `y` and `x` set to the current cursor column. +There is no additional or different behavior for using `VPR`. + +The parameter `y` must be an integer greater than or equal to 1. If `y` is less than +or equal to 0, adjust `y` to be 1. If `y` is omitted, `y` defaults to 1. + +Because this invokes `CUP`, the cursor column (`x`) can change if it is +outside the bounds of the `CUP` operation. For example, if +[origin mode](#TODO) is set and the current cursor position is outside +of the scroll region, the column will be adjusted.