mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
Merge pull request #2057 from jcollie/xtwinops
[DRAFT] Implement the XTWINOPS (CSI t) control sequences that "make sense".
This commit is contained in:
@ -713,6 +713,31 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
|
|||||||
try self.rt_surface.setTitle(slice);
|
try self.rt_surface.setTitle(slice);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.report_title => |style| {
|
||||||
|
const title: ?[:0]const u8 = title: {
|
||||||
|
if (!@hasDecl(apprt.runtime.Surface, "getTitle")) break :title null;
|
||||||
|
break :title self.rt_surface.getTitle();
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = switch (style) {
|
||||||
|
.csi_21_t => try std.fmt.allocPrint(
|
||||||
|
self.alloc,
|
||||||
|
"\x1b]l{s}\x1b\\",
|
||||||
|
.{title orelse ""},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// We always use an allocating message because we don't know
|
||||||
|
// the length of the title and this isn't a performance critical
|
||||||
|
// path.
|
||||||
|
self.io.queueMessage(.{
|
||||||
|
.write_alloc = .{
|
||||||
|
.alloc = self.alloc,
|
||||||
|
.data = data,
|
||||||
|
},
|
||||||
|
}, .unlocked);
|
||||||
|
},
|
||||||
|
|
||||||
.set_mouse_shape => |shape| {
|
.set_mouse_shape => |shape| {
|
||||||
log.debug("changing mouse shape: {}", .{shape});
|
log.debug("changing mouse shape: {}", .{shape});
|
||||||
try self.rt_surface.setMouseShape(shape);
|
try self.rt_surface.setMouseShape(shape);
|
||||||
|
@ -306,6 +306,10 @@ pub const Surface = struct {
|
|||||||
keymap_state: input.Keymap.State,
|
keymap_state: input.Keymap.State,
|
||||||
inspector: ?*Inspector = null,
|
inspector: ?*Inspector = null,
|
||||||
|
|
||||||
|
/// The current title of the surface. The embedded apprt saves this so
|
||||||
|
/// that getTitle works without the implementer needing to save it.
|
||||||
|
title: ?[:0]const u8 = null,
|
||||||
|
|
||||||
/// Surface initialization options.
|
/// Surface initialization options.
|
||||||
pub const Options = extern struct {
|
pub const Options = extern struct {
|
||||||
/// The platform that this surface is being initialized for and
|
/// The platform that this surface is being initialized for and
|
||||||
@ -429,6 +433,9 @@ pub const Surface = struct {
|
|||||||
// Shut down our inspector
|
// Shut down our inspector
|
||||||
self.freeInspector();
|
self.freeInspector();
|
||||||
|
|
||||||
|
// Free our title
|
||||||
|
if (self.title) |v| self.app.core_app.alloc.free(v);
|
||||||
|
|
||||||
// Remove ourselves from the list of known surfaces in the app.
|
// Remove ourselves from the list of known surfaces in the app.
|
||||||
self.app.core_app.deleteSurface(self);
|
self.app.core_app.deleteSurface(self);
|
||||||
|
|
||||||
@ -537,12 +544,22 @@ pub const Surface = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||||
|
// Dupe the title so that we can store it. If we get an allocation
|
||||||
|
// error we just ignore it, since this only breaks a few minor things.
|
||||||
|
const alloc = self.app.core_app.alloc;
|
||||||
|
if (self.title) |v| alloc.free(v);
|
||||||
|
self.title = alloc.dupeZ(u8, slice) catch null;
|
||||||
|
|
||||||
self.app.opts.set_title(
|
self.app.opts.set_title(
|
||||||
self.userdata,
|
self.userdata,
|
||||||
slice.ptr,
|
slice.ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTitle(self: *Surface) ?[:0]const u8 {
|
||||||
|
return self.title;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setMouseShape(self: *Surface, shape: terminal.MouseShape) !void {
|
pub fn setMouseShape(self: *Surface, shape: terminal.MouseShape) !void {
|
||||||
self.app.opts.set_mouse_shape(
|
self.app.opts.set_mouse_shape(
|
||||||
self.userdata,
|
self.userdata,
|
||||||
|
@ -360,6 +360,11 @@ pub const Surface = struct {
|
|||||||
/// The monitor dimensions so we can toggle fullscreen on and off.
|
/// The monitor dimensions so we can toggle fullscreen on and off.
|
||||||
monitor_dims: MonitorDimensions,
|
monitor_dims: MonitorDimensions,
|
||||||
|
|
||||||
|
/// Save the title text so that we can return it later when requested.
|
||||||
|
/// This is allocated from the heap so it must be freed when we deinit the
|
||||||
|
/// surface.
|
||||||
|
title_text: ?[:0]const u8 = null,
|
||||||
|
|
||||||
pub const Options = struct {};
|
pub const Options = struct {};
|
||||||
|
|
||||||
/// Initialize the surface into the given self pointer. This gives a
|
/// Initialize the surface into the given self pointer. This gives a
|
||||||
@ -463,6 +468,8 @@ pub const Surface = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Surface) void {
|
pub fn deinit(self: *Surface) void {
|
||||||
|
if (self.title_text) |t| self.core_surface.alloc.free(t);
|
||||||
|
|
||||||
// Remove ourselves from the list of known surfaces in the app.
|
// Remove ourselves from the list of known surfaces in the app.
|
||||||
self.app.app.deleteSurface(self);
|
self.app.app.deleteSurface(self);
|
||||||
|
|
||||||
@ -609,7 +616,14 @@ pub const Surface = struct {
|
|||||||
|
|
||||||
/// Set the title of the window.
|
/// Set the title of the window.
|
||||||
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||||
self.window.setTitle(slice.ptr);
|
if (self.title_text) |t| self.core_surface.alloc.free(t);
|
||||||
|
self.title_text = try self.core_surface.alloc.dupeZ(u8, slice);
|
||||||
|
self.window.setTitle(self.title_text.?.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the title of the window.
|
||||||
|
pub fn getTitle(self: *Surface) ?[:0]const u8 {
|
||||||
|
return self.title_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the shape of the cursor.
|
/// Set the shape of the cursor.
|
||||||
|
@ -935,6 +935,10 @@ pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
|||||||
self.updateTitleLabels();
|
self.updateTitleLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTitle(self: *Surface) ?[:0]const u8 {
|
||||||
|
return self.title_text;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setMouseShape(
|
pub fn setMouseShape(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
shape: terminal.MouseShape,
|
shape: terminal.MouseShape,
|
||||||
|
@ -18,6 +18,9 @@ pub const Message = union(enum) {
|
|||||||
/// of any length
|
/// of any length
|
||||||
set_title: [256]u8,
|
set_title: [256]u8,
|
||||||
|
|
||||||
|
/// Report the window title back to the terminal
|
||||||
|
report_title: ReportTitleStyle,
|
||||||
|
|
||||||
/// Set the mouse shape.
|
/// Set the mouse shape.
|
||||||
set_mouse_shape: terminal.MouseShape,
|
set_mouse_shape: terminal.MouseShape,
|
||||||
|
|
||||||
@ -57,6 +60,12 @@ pub const Message = union(enum) {
|
|||||||
|
|
||||||
/// Report the color scheme
|
/// Report the color scheme
|
||||||
report_color_scheme: void,
|
report_color_scheme: void,
|
||||||
|
|
||||||
|
pub const ReportTitleStyle = enum {
|
||||||
|
csi_21_t,
|
||||||
|
|
||||||
|
// This enum is a placeholder for future title styles.
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A surface mailbox.
|
/// A surface mailbox.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Modes for the ED CSI command.
|
/// Modes for the ED CSI command.
|
||||||
pub const EraseDisplay = enum(u8) {
|
pub const EraseDisplay = enum(u8) {
|
||||||
below = 0,
|
below = 0,
|
||||||
above = 1,
|
above = 1,
|
||||||
@ -10,7 +10,7 @@ pub const EraseDisplay = enum(u8) {
|
|||||||
scroll_complete = 22,
|
scroll_complete = 22,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Modes for the EL CSI command.
|
/// Modes for the EL CSI command.
|
||||||
pub const EraseLine = enum(u8) {
|
pub const EraseLine = enum(u8) {
|
||||||
right = 0,
|
right = 0,
|
||||||
left = 1,
|
left = 1,
|
||||||
@ -22,7 +22,7 @@ pub const EraseLine = enum(u8) {
|
|||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Modes for the TBC (tab clear) command.
|
/// Modes for the TBC (tab clear) command.
|
||||||
pub const TabClear = enum(u8) {
|
pub const TabClear = enum(u8) {
|
||||||
current = 0,
|
current = 0,
|
||||||
all = 3,
|
all = 3,
|
||||||
@ -31,3 +31,12 @@ pub const TabClear = enum(u8) {
|
|||||||
// user-generated.
|
// user-generated.
|
||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Style formats for terminal size reports.
|
||||||
|
pub const SizeReportStyle = enum {
|
||||||
|
// XTWINOPS
|
||||||
|
csi_14_t,
|
||||||
|
csi_16_t,
|
||||||
|
csi_18_t,
|
||||||
|
csi_21_t,
|
||||||
|
};
|
||||||
|
@ -38,6 +38,7 @@ pub const Pin = PageList.Pin;
|
|||||||
pub const Screen = @import("Screen.zig");
|
pub const Screen = @import("Screen.zig");
|
||||||
pub const ScreenType = Terminal.ScreenType;
|
pub const ScreenType = Terminal.ScreenType;
|
||||||
pub const Selection = @import("Selection.zig");
|
pub const Selection = @import("Selection.zig");
|
||||||
|
pub const SizeReportStyle = csi.SizeReportStyle;
|
||||||
pub const StringMap = @import("StringMap.zig");
|
pub const StringMap = @import("StringMap.zig");
|
||||||
pub const Style = style.Style;
|
pub const Style = style.Style;
|
||||||
pub const Terminal = @import("Terminal.zig");
|
pub const Terminal = @import("Terminal.zig");
|
||||||
|
@ -1109,6 +1109,75 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// XTWINOPS
|
||||||
|
't' => switch (input.intermediates.len) {
|
||||||
|
0 => {
|
||||||
|
if (input.params.len > 0) {
|
||||||
|
switch (input.params[0]) {
|
||||||
|
14 => if (input.params.len == 1) {
|
||||||
|
// report the text area size in pixels
|
||||||
|
if (@hasDecl(T, "sendSizeReport")) {
|
||||||
|
self.handler.sendSizeReport(.csi_14_t);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring unimplemented CSI 14 t",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring CSI 14 t with extra parameters: {}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
16 => if (input.params.len == 1) {
|
||||||
|
// report cell size in pixels
|
||||||
|
if (@hasDecl(T, "sendSizeReport")) {
|
||||||
|
self.handler.sendSizeReport(.csi_16_t);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring unimplemented CSI 16 t",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring CSI 16 t with extra parameters: {s}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
18 => if (input.params.len == 1) {
|
||||||
|
// report screen size in characters
|
||||||
|
if (@hasDecl(T, "sendSizeReport")) {
|
||||||
|
self.handler.sendSizeReport(.csi_18_t);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring unimplemented CSI 18 t",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring CSI 18 t with extra parameters: {s}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
21 => if (input.params.len == 1) {
|
||||||
|
// report window title
|
||||||
|
if (@hasDecl(T, "sendSizeReport")) {
|
||||||
|
self.handler.sendSizeReport(.csi_21_t);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring unimplemented CSI 21 t",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
} else log.warn(
|
||||||
|
"ignoring CSI 21 t with extra parameters: {s}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
else => log.warn(
|
||||||
|
"ignoring CSI t with unimplemented parameter: {s}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else log.err(
|
||||||
|
"ignoring CSI t with no parameters: {s}",
|
||||||
|
.{input},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
else => log.warn(
|
||||||
|
"ignoring unimplemented CSI t with intermediates: {s}",
|
||||||
|
.{input},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
'u' => switch (input.intermediates.len) {
|
'u' => switch (input.intermediates.len) {
|
||||||
0 => if (@hasDecl(T, "restoreCursor"))
|
0 => if (@hasDecl(T, "restoreCursor"))
|
||||||
try self.handler.restoreCursor()
|
try self.handler.restoreCursor()
|
||||||
@ -2047,3 +2116,42 @@ test "stream: csi param too long" {
|
|||||||
var s: Stream(H) = .{ .handler = .{} };
|
var s: Stream(H) = .{ .handler = .{} };
|
||||||
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
|
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "stream: send report with CSI t" {
|
||||||
|
const H = struct {
|
||||||
|
style: ?csi.SizeReportStyle = null,
|
||||||
|
|
||||||
|
pub fn sendSizeReport(self: *@This(), style: csi.SizeReportStyle) void {
|
||||||
|
self.style = style;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s: Stream(H) = .{ .handler = .{} };
|
||||||
|
|
||||||
|
try s.nextSlice("\x1b[14t");
|
||||||
|
try testing.expectEqual(csi.SizeReportStyle.csi_14_t, s.handler.style);
|
||||||
|
|
||||||
|
try s.nextSlice("\x1b[16t");
|
||||||
|
try testing.expectEqual(csi.SizeReportStyle.csi_16_t, s.handler.style);
|
||||||
|
|
||||||
|
try s.nextSlice("\x1b[18t");
|
||||||
|
try testing.expectEqual(csi.SizeReportStyle.csi_18_t, s.handler.style);
|
||||||
|
|
||||||
|
try s.nextSlice("\x1b[21t");
|
||||||
|
try testing.expectEqual(csi.SizeReportStyle.csi_21_t, s.handler.style);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "stream: invalid CSI t" {
|
||||||
|
const H = struct {
|
||||||
|
style: ?csi.SizeReportStyle = null,
|
||||||
|
|
||||||
|
pub fn sendSizeReport(self: *@This(), style: csi.SizeReportStyle) void {
|
||||||
|
self.style = style;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s: Stream(H) = .{ .handler = .{} };
|
||||||
|
|
||||||
|
try s.nextSlice("\x1b[19t");
|
||||||
|
try testing.expectEqual(null, s.handler.style);
|
||||||
|
}
|
||||||
|
@ -383,23 +383,24 @@ pub fn resize(
|
|||||||
|
|
||||||
// If we have size reporting enabled we need to send a report.
|
// If we have size reporting enabled we need to send a report.
|
||||||
if (self.terminal.modes.get(.in_band_size_reports)) {
|
if (self.terminal.modes.get(.in_band_size_reports)) {
|
||||||
try self.sizeReportLocked(td);
|
try self.sizeReportLocked(td, .mode_2048);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a mode 2048 in-band size report.
|
/// Make a size report.
|
||||||
pub fn sizeReport(self: *Termio, td: *ThreadData) !void {
|
pub fn sizeReport(self: *Termio, td: *ThreadData, style: termio.Message.SizeReport) !void {
|
||||||
self.renderer_state.mutex.lock();
|
self.renderer_state.mutex.lock();
|
||||||
defer self.renderer_state.mutex.unlock();
|
defer self.renderer_state.mutex.unlock();
|
||||||
try self.sizeReportLocked(td);
|
try self.sizeReportLocked(td, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sizeReportLocked(self: *Termio, td: *ThreadData) !void {
|
fn sizeReportLocked(self: *Termio, td: *ThreadData, style: termio.Message.SizeReport) !void {
|
||||||
// 1024 bytes should be enough for size report since report
|
// 1024 bytes should be enough for size report since report
|
||||||
// in columns and pixels.
|
// in columns and pixels.
|
||||||
var buf: [1024]u8 = undefined;
|
var buf: [1024]u8 = undefined;
|
||||||
const message = try std.fmt.bufPrint(
|
const message = switch (style) {
|
||||||
|
.mode_2048 => try std.fmt.bufPrint(
|
||||||
&buf,
|
&buf,
|
||||||
"\x1B[48;{};{};{};{}t",
|
"\x1B[48;{};{};{};{}t",
|
||||||
.{
|
.{
|
||||||
@ -408,7 +409,32 @@ fn sizeReportLocked(self: *Termio, td: *ThreadData) !void {
|
|||||||
self.terminal.height_px,
|
self.terminal.height_px,
|
||||||
self.terminal.width_px,
|
self.terminal.width_px,
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
|
.csi_14_t => try std.fmt.bufPrint(
|
||||||
|
&buf,
|
||||||
|
"\x1b[4;{};{}t",
|
||||||
|
.{
|
||||||
|
self.terminal.height_px,
|
||||||
|
self.terminal.width_px,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
.csi_16_t => try std.fmt.bufPrint(
|
||||||
|
&buf,
|
||||||
|
"\x1b[6;{};{}t",
|
||||||
|
.{
|
||||||
|
self.terminal.height_px / self.grid_size.rows,
|
||||||
|
self.terminal.width_px / self.grid_size.columns,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
.csi_18_t => try std.fmt.bufPrint(
|
||||||
|
&buf,
|
||||||
|
"\x1b[8;{};{}t",
|
||||||
|
.{
|
||||||
|
self.grid_size.rows,
|
||||||
|
self.grid_size.columns,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
try self.queueWrite(td, message, false);
|
try self.queueWrite(td, message, false);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +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),
|
.size_report => |v| try io.sizeReport(data, v),
|
||||||
.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),
|
||||||
|
@ -42,9 +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,
|
/// Request a size report is sent to the pty ([in-band
|
||||||
/// mode 2048: https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83)
|
/// size report, mode 2048](https://gist.github.com/rockorager/e695fb2924d36b2bcf1fff4a3704bd83) and
|
||||||
size_report: void,
|
/// [XTWINOPS](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps;Ps;Ps-t.1EB0)).
|
||||||
|
size_report: SizeReport,
|
||||||
|
|
||||||
/// Clear the screen.
|
/// Clear the screen.
|
||||||
clear_screen: struct {
|
clear_screen: struct {
|
||||||
@ -94,6 +95,14 @@ pub const Message = union(enum) {
|
|||||||
.alloc => |v| Message{ .write_alloc = v },
|
.alloc => |v| Message{ .write_alloc = v },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The types of size reports that we support
|
||||||
|
pub const SizeReport = enum {
|
||||||
|
mode_2048,
|
||||||
|
csi_14_t,
|
||||||
|
csi_16_t,
|
||||||
|
csi_18_t,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a union that can be used to accommodate data that fit within an array,
|
/// Creates a union that can be used to accommodate data that fit within an array,
|
||||||
|
@ -598,7 +598,7 @@ pub const StreamHandler = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.in_band_size_reports => if (enabled) self.messageWriter(.{
|
.in_band_size_reports => if (enabled) self.messageWriter(.{
|
||||||
.size_report = {},
|
.size_report = .mode_2048,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.mouse_event_x10 => {
|
.mouse_event_x10 => {
|
||||||
@ -1259,4 +1259,14 @@ pub const StreamHandler = struct {
|
|||||||
|
|
||||||
self.surfaceMessageWriter(message);
|
self.surfaceMessageWriter(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a report to the pty.
|
||||||
|
pub fn sendSizeReport(self: *StreamHandler, style: terminal.SizeReportStyle) void {
|
||||||
|
switch (style) {
|
||||||
|
.csi_14_t => self.messageWriter(.{ .size_report = .csi_14_t }),
|
||||||
|
.csi_16_t => self.messageWriter(.{ .size_report = .csi_16_t }),
|
||||||
|
.csi_18_t => self.messageWriter(.{ .size_report = .csi_18_t }),
|
||||||
|
.csi_21_t => self.surfaceMessageWriter(.{ .report_title = .csi_21_t }),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user