mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-05-21 12:24:26 +00:00
Implement the XTWINOPS (CSI t) control sequences that "make sense".
These sequences were implemented: CSI 14 t - report the text area size in pixels CSI 16 t - report the cell size in pixels CSI 18 t - report the text area size in cells CSI 21 t - report the window title These sequences were not implemented because they manuipulate the window state in ways that we do not want. CSI 1 t CSI 2 t CSI 3 ; x ; y t CSI 4 ; height ; width ; t CSI 5 t CSI 6 t CSI 7 t CSI 8 ; height ; width ; t CSI 9 ; 0 t CSI 9 ; 1 t CSI 9 ; 2 t CSI 9 ; 3 t CSI 10 ; 0 t CSI 10 ; 1 t CSI 10 ; 2 t CSI 24 t These sequences were not implemented because they do not make sense in a Wayland context: CSI 11 t CSI 13 t CSI 14 ; 2 t These sequences were not implemented because they provide information about the screen that is unnecessary. CSI 15 t CSI 19 t These sequences were not implemeted because Ghostty does not maintain an icon title for windows. CSI 20 t CSI 22 ; 0 t CSI 22 ; 1 t CSI 23 ; 0 t CSI 23 ; 1 t These sequences were not implemented because of the additional complexity of maintaining a stack of window titles. CSI 22 ; 2 t CSI 23 ; 2 t
This commit is contained in:
@@ -24,6 +24,13 @@ const log = std.log.scoped(.stream);
|
||||
/// do something else.
|
||||
const debug = false;
|
||||
|
||||
pub const ReportStyle = enum {
|
||||
csi_14_t,
|
||||
csi_16_t,
|
||||
csi_18_t,
|
||||
csi_21_t,
|
||||
};
|
||||
|
||||
/// Returns a type that can process a stream of tty control characters.
|
||||
/// This will call various callback functions on type T. Type T only has to
|
||||
/// implement the callbacks it cares about; any unimplemented callbacks will
|
||||
@@ -1109,6 +1116,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, "sendReport")) {
|
||||
self.handler.sendReport(.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, "sendReport")) {
|
||||
self.handler.sendReport(.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, "sendReport")) {
|
||||
self.handler.sendReport(.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, "sendReport")) {
|
||||
self.handler.sendReport(.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) {
|
||||
0 => if (@hasDecl(T, "restoreCursor"))
|
||||
try self.handler.restoreCursor()
|
||||
@@ -2047,3 +2123,42 @@ test "stream: csi param too long" {
|
||||
var s: Stream(H) = .{ .handler = .{} };
|
||||
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
|
||||
}
|
||||
|
||||
test "stream: send report with CSI t" {
|
||||
const H = struct {
|
||||
style: ?ReportStyle = null,
|
||||
|
||||
pub fn sendReport(self: *@This(), style: ReportStyle) void {
|
||||
self.style = style;
|
||||
}
|
||||
};
|
||||
|
||||
var s: Stream(H) = .{ .handler = .{} };
|
||||
|
||||
try s.nextSlice("\x1b[14t");
|
||||
try testing.expectEqual(ReportStyle.csi_14_t, s.handler.style);
|
||||
|
||||
try s.nextSlice("\x1b[16t");
|
||||
try testing.expectEqual(ReportStyle.csi_16_t, s.handler.style);
|
||||
|
||||
try s.nextSlice("\x1b[18t");
|
||||
try testing.expectEqual(ReportStyle.csi_18_t, s.handler.style);
|
||||
|
||||
try s.nextSlice("\x1b[21t");
|
||||
try testing.expectEqual(ReportStyle.csi_21_t, s.handler.style);
|
||||
}
|
||||
|
||||
test "stream: invalid CSI t" {
|
||||
const H = struct {
|
||||
style: ?ReportStyle = null,
|
||||
|
||||
pub fn sendReport(self: *@This(), style: ReportStyle) void {
|
||||
self.style = style;
|
||||
}
|
||||
};
|
||||
|
||||
var s: Stream(H) = .{ .handler = .{} };
|
||||
|
||||
try s.nextSlice("\x1b[19t");
|
||||
try testing.expectEqual(null, s.handler.style);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user