Merge pull request #1955 from ghostty-org/ibsr

terminal: implement in-band size reports (Mode 2048)
This commit is contained in:
Mitchell Hashimoto
2024-07-17 19:54:24 -07:00
committed by GitHub
5 changed files with 47 additions and 1 deletions

View File

@ -216,6 +216,7 @@ const entries: []const ModeEntry = &.{
.{ .name = "synchronized_output", .value = 2026 }, .{ .name = "synchronized_output", .value = 2026 },
.{ .name = "grapheme_cluster", .value = 2027 }, .{ .name = "grapheme_cluster", .value = 2027 },
.{ .name = "report_color_scheme", .value = 2031 }, .{ .name = "report_color_scheme", .value = 2031 },
.{ .name = "in_band_size_reports", .value = 2048 },
}; };
test { test {

View File

@ -344,6 +344,7 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi
/// Resize the terminal. /// Resize the terminal.
pub fn resize( pub fn resize(
self: *Termio, self: *Termio,
td: *ThreadData,
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
screen_size: renderer.ScreenSize, screen_size: renderer.ScreenSize,
padding: renderer.Padding, padding: renderer.Padding,
@ -377,9 +378,39 @@ pub fn resize(
// Wake up our renderer so any changes will be shown asap // Wake up our renderer so any changes will be shown asap
self.renderer_wakeup.notify() catch {}; 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 /// Reset the synchronized output mode. This is usually called by timer
/// expiration from the termio thread. /// expiration from the termio thread.
pub fn resetSynchronizedOutput(self: *Termio) void { pub fn resetSynchronizedOutput(self: *Termio) void {

View File

@ -267,6 +267,7 @@ fn drainMailbox(
}, },
.inspector => |v| self.flags.has_inspector = v, .inspector => |v| self.flags.has_inspector = v,
.resize => |v| self.handleResize(cb, v), .resize => |v| self.handleResize(cb, v),
.size_report => try io.sizeReport(data),
.clear_screen => |v| try io.clearScreen(data, v.history), .clear_screen => |v| try io.clearScreen(data, v.history),
.scroll_viewport => |v| try io.scrollViewport(v), .scroll_viewport => |v| try io.scrollViewport(v),
.jump_to_prompt => |v| try io.jumpToPrompt(v), .jump_to_prompt => |v| try io.jumpToPrompt(v),
@ -369,7 +370,12 @@ fn coalesceCallback(
if (cb.self.coalesce_data.resize) |v| { if (cb.self.coalesce_data.resize) |v| {
cb.self.coalesce_data.resize = null; 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}); log.warn("error during resize err={}", .{err});
}; };
} }

View File

@ -42,6 +42,10 @@ pub const Message = union(enum) {
/// Resize the window. /// Resize the window.
resize: Resize, 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 the screen.
clear_screen: struct { clear_screen: struct {
/// Include clearing the history /// Include clearing the history

View File

@ -597,6 +597,10 @@ pub const StreamHandler = struct {
self.messageWriter(.{ .linefeed_mode = enabled }); self.messageWriter(.{ .linefeed_mode = enabled });
}, },
.in_band_size_reports => if (enabled) self.messageWriter(.{
.size_report = {},
}),
.mouse_event_x10 => { .mouse_event_x10 => {
if (enabled) { if (enabled) {
self.terminal.flags.mouse_event = .x10; self.terminal.flags.mouse_event = .x10;