diff --git a/README.md b/README.md index 2090b88..c80450c 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Unix-likes. | Synchronized Output (DEC 2026) | ✅ | | Unicode Core (DEC 2027) | ✅ | | Color Mode Updates (DEC 2031) | ✅ | +| [In-Band Resize Reports](https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83) | ✅ | | Images (kitty) | ✅ | ## Usage diff --git a/src/Loop.zig b/src/Loop.zig index b9bf030..ceea70b 100644 --- a/src/Loop.zig +++ b/src/Loop.zig @@ -89,6 +89,8 @@ pub fn Loop(comptime T: type) type { pub fn winsizeCallback(ptr: *anyopaque) void { const self: *Self = @ptrCast(@alignCast(ptr)); + // We will be receiving winsize updates in-band + if (self.vaxis.state.in_band_resize) return; const winsize = Tty.getWinsize(self.tty.fd) catch return; if (@hasField(Event, "winsize")) { @@ -286,7 +288,12 @@ pub fn handleEventGeneric(self: anytype, vx: *Vaxis, cache: *GraphemeCache, Even .cap_da1 => { std.Thread.Futex.wake(&vx.query_futex, 10); }, - .winsize => unreachable, // handled elsewhere for posix + .winsize => |winsize| { + vx.state.in_band_resize = true; + if (@hasField(Event, "winsize")) { + self.postEvent(.{ .winsize = winsize }); + } + }, } }, } diff --git a/src/Parser.zig b/src/Parser.zig index 90244a2..a08761e 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -6,6 +6,7 @@ const Key = @import("Key.zig"); const Mouse = @import("Mouse.zig"); const code_point = @import("code_point"); const grapheme = @import("grapheme"); +const Winsize = @import("main.zig").Winsize; const log = std.log.scoped(.parser); @@ -470,6 +471,31 @@ inline fn parseCsi(input: []const u8, text_buf: []u8) Result { else => return null_event, } }, + 't' => { + // XTWINOPS + // Split first into fields delimited by ';' + var iter = std.mem.splitScalar(u8, sequence[2 .. sequence.len - 1], ';'); + const ps = iter.first(); + if (std.mem.eql(u8, "48", ps)) { + // in band window resize + const width_char = iter.next() orelse return null_event; + const height_char = iter.next() orelse return null_event; + const width_pix = iter.next() orelse "0"; + const height_pix = iter.next() orelse "0"; + + const winsize: Winsize = .{ + .rows = std.fmt.parseUnsigned(usize, height_char, 10) catch return null_event, + .cols = std.fmt.parseUnsigned(usize, width_char, 10) catch return null_event, + .x_pixel = std.fmt.parseUnsigned(usize, width_pix, 10) catch return null_event, + .y_pixel = std.fmt.parseUnsigned(usize, height_pix, 10) catch return null_event, + }; + return .{ + .event = .{ .winsize = winsize }, + .n = sequence.len, + }; + } + return null_event; + }, 'u' => { // Kitty keyboard // CSI unicode-key-code:alternate-key-codes ; modifiers:event-type ; text-as-codepoints u diff --git a/src/Vaxis.zig b/src/Vaxis.zig index 284285a..18924a3 100644 --- a/src/Vaxis.zig +++ b/src/Vaxis.zig @@ -85,6 +85,7 @@ state: struct { mouse: bool = false, pixel_mouse: bool = false, color_scheme_updates: bool = false, + in_band_resize: bool = false, cursor: struct { row: usize = 0, col: usize = 0, @@ -151,6 +152,10 @@ pub fn resetState(self: *Vaxis, tty: AnyWriter) !void { try tty.writeAll(ctlseqs.color_scheme_reset); self.state.color_scheme_updates = false; } + if (self.state.in_band_resize) { + try tty.writeAll(ctlseqs.in_band_resize_reset); + self.state.in_band_resize = false; + } } /// resize allocates a slice of cells equal to the number of cells @@ -244,6 +249,7 @@ pub fn queryTerminalSend(_: Vaxis, tty: AnyWriter) !void { try tty.writeAll(ctlseqs.decrqm_sgr_pixels ++ ctlseqs.decrqm_unicode ++ ctlseqs.decrqm_color_scheme ++ + ctlseqs.in_band_resize_set ++ ctlseqs.xtversion ++ ctlseqs.csi_u_query ++ ctlseqs.kitty_graphics_query ++ diff --git a/src/ctlseqs.zig b/src/ctlseqs.zig index a911f95..50f5e40 100644 --- a/src/ctlseqs.zig +++ b/src/ctlseqs.zig @@ -20,6 +20,10 @@ pub const mouse_set = "\x1b[?1002;1003;1004;1006h"; pub const mouse_set_pixels = "\x1b[?1002;1003;1004;1016h"; pub const mouse_reset = "\x1b[?1002;1003;1004;1006;1016l"; +// in-band window size reports +pub const in_band_resize_set = "\x1b[?2048h"; +pub const in_band_resize_reset = "\x1b[?2048l"; + // sync pub const sync_set = "\x1b[?2026h"; pub const sync_reset = "\x1b[?2026l";