diff --git a/src/terminal/modes.zig b/src/terminal/modes.zig index c9ed84cbd..c4dbb1cd6 100644 --- a/src/terminal/modes.zig +++ b/src/terminal/modes.zig @@ -216,6 +216,7 @@ const entries: []const ModeEntry = &.{ .{ .name = "synchronized_output", .value = 2026 }, .{ .name = "grapheme_cluster", .value = 2027 }, .{ .name = "report_color_scheme", .value = 2031 }, + .{ .name = "in_band_size_reports", .value = 2048 }, }; test { diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index 9459f9152..9f83e671f 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -344,6 +344,7 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi /// Resize the terminal. pub fn resize( self: *Termio, + td: *ThreadData, grid_size: renderer.GridSize, screen_size: renderer.ScreenSize, padding: renderer.Padding, @@ -377,9 +378,39 @@ pub fn resize( // Wake up our renderer so any changes will be shown asap self.renderer_wakeup.notify() catch {}; + + // If we have size reporting enabled we need to send a report. + if (self.terminal.modes.get(.in_band_size_reports)) { + try self.sizeReportLocked(td); + } } } +/// Make a mode 2048 in-band size report. +pub fn sizeReport(self: *Termio, td: *ThreadData) !void { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + try self.sizeReportLocked(td); +} + +fn sizeReportLocked(self: *Termio, td: *ThreadData) !void { + // 1024 bytes should be enough for size report since report + // in columns and pixels. + var buf: [1024]u8 = undefined; + const message = try std.fmt.bufPrint( + &buf, + "\x1B[48;{};{};{};{}t", + .{ + self.grid_size.rows, + self.grid_size.columns, + self.terminal.height_px, + self.terminal.width_px, + }, + ); + + try self.queueWrite(td, message, false); +} + /// Reset the synchronized output mode. This is usually called by timer /// expiration from the termio thread. pub fn resetSynchronizedOutput(self: *Termio) void { diff --git a/src/termio/Thread.zig b/src/termio/Thread.zig index 73e384f51..1dc240827 100644 --- a/src/termio/Thread.zig +++ b/src/termio/Thread.zig @@ -267,6 +267,7 @@ fn drainMailbox( }, .inspector => |v| self.flags.has_inspector = v, .resize => |v| self.handleResize(cb, v), + .size_report => try io.sizeReport(data), .clear_screen => |v| try io.clearScreen(data, v.history), .scroll_viewport => |v| try io.scrollViewport(v), .jump_to_prompt => |v| try io.jumpToPrompt(v), @@ -369,7 +370,12 @@ fn coalesceCallback( if (cb.self.coalesce_data.resize) |v| { cb.self.coalesce_data.resize = null; - cb.io.resize(v.grid_size, v.screen_size, v.padding) catch |err| { + cb.io.resize( + &cb.data, + v.grid_size, + v.screen_size, + v.padding, + ) catch |err| { log.warn("error during resize err={}", .{err}); }; } diff --git a/src/termio/message.zig b/src/termio/message.zig index 31b203f05..5d17ad8d8 100644 --- a/src/termio/message.zig +++ b/src/termio/message.zig @@ -42,6 +42,10 @@ pub const Message = union(enum) { /// Resize the window. resize: Resize, + /// Request a size report is sent to the pty (in-band size report, + /// mode 2048: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83) + size_report: void, + /// Clear the screen. clear_screen: struct { /// Include clearing the history diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index bb45cd480..ea5562e5a 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -597,6 +597,10 @@ pub const StreamHandler = struct { self.messageWriter(.{ .linefeed_mode = enabled }); }, + .in_band_size_reports => if (enabled) self.messageWriter(.{ + .size_report = {}, + }), + .mouse_event_x10 => { if (enabled) { self.terminal.flags.mouse_event = .x10;