aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/parse_table.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/terminal/parse_table.zig
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/parse_table.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/parse_table.zig60
1 files changed, 60 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/terminal/parse_table.zig b/vendor/libghostty-vt/src/terminal/parse_table.zig
index 01bd569c..fa074fa0 100644
--- a/vendor/libghostty-vt/src/terminal/parse_table.zig
+++ b/vendor/libghostty-vt/src/terminal/parse_table.zig
@@ -206,6 +206,13 @@ fn genTable() Table {
single(&result, 0x19, source, source, .ignore);
range(&result, 0, 0x17, source, source, .ignore);
range(&result, 0x1C, 0x1F, source, source, .ignore);
+
+ // High bytes are ignored payload data, overriding the
+ // "anywhere" C1 transitions. See dcs_passthrough below for more.
+ // In dcs_ignore the additional concern is that a UTF-8 payload in
+ // an ignored DCS could otherwise begin a live sequence mid-string
+ // (e.g. 0x9B => csi_entry).
+ range(&result, 0x80, 0xFF, source, source, .ignore);
}
// dcs_param
@@ -241,6 +248,21 @@ fn genTable() Table {
range(&result, 0x1C, 0x1F, source, source, .put);
range(&result, 0x20, 0x7E, source, source, .put);
single(&result, 0x7F, source, source, .ignore);
+
+ // High bytes are payload data, overriding the "anywhere" C1
+ // transitions, matching how osc_string handles them below.
+ // Ghostty is UTF-8 only, and DCS payloads carry UTF-8 text
+ // (e.g. tmux control mode pane content): without this, a
+ // UTF-8 continuation byte in the C1 range terminates or
+ // corrupts the string and 0xA0-0xFF are silently dropped.
+ //
+ // This includes 0x9C (8-bit ST) on purpose: a raw 0x9C is
+ // indistinguishable from a UTF-8 continuation byte ("Ü" is
+ // 0xC3 0x9C), and Ghostty doesn't honor 8-bit C1 controls in
+ // the ground state either (they go through UTF-8 decoding).
+ // DCS strings terminate via 7-bit ST (ESC \) and abort via
+ // CAN/SUB, which are unaffected here.
+ range(&result, 0x80, 0xFF, source, source, .put);
}
// csi_param
@@ -386,3 +408,41 @@ test {
// that it succeeds in creation.
_ = table;
}
+
+test "dcs_passthrough: high bytes are payload data" {
+ // Bytes 0x80-0xFF within a DCS string are payload data, not C1
+ // controls. This includes 0x9C (8-bit ST): a raw 0x9C is
+ // indistinguishable from a UTF-8 continuation byte (e.g. "Ü" is
+ // 0xC3 0x9C) and Ghostty doesn't support 8-bit C1 controls
+ // anywhere else.
+ for (0x80..0x100) |c| {
+ const entry = table[c][@intFromEnum(State.dcs_passthrough)];
+ try std.testing.expectEqual(State.dcs_passthrough, entry.state);
+ try std.testing.expectEqual(Action.put, entry.action);
+ }
+}
+
+test "dcs_ignore: high bytes are ignored payload data" {
+ // Same as dcs_passthrough: a UTF-8 payload inside an ignored DCS
+ // must not trigger "anywhere" C1 transitions (e.g. 0x9B beginning
+ // a CSI mid-string).
+ for (0x80..0x100) |c| {
+ const entry = table[c][@intFromEnum(State.dcs_ignore)];
+ try std.testing.expectEqual(State.dcs_ignore, entry.state);
+ try std.testing.expectEqual(Action.ignore, entry.action);
+ }
+}
+
+test "dcs_passthrough: ESC, CAN, and SUB still exit" {
+ // 7-bit ST (ESC \) is the DCS terminator and CAN/SUB abort, so
+ // these must continue to leave dcs_passthrough. dcs_unhook is
+ // emitted by the parser on any transition out of dcs_passthrough.
+ const esc = table[0x1B][@intFromEnum(State.dcs_passthrough)];
+ try std.testing.expectEqual(State.escape, esc.state);
+
+ const can = table[0x18][@intFromEnum(State.dcs_passthrough)];
+ try std.testing.expectEqual(State.ground, can.state);
+
+ const sub = table[0x1A][@intFromEnum(State.dcs_passthrough)];
+ try std.testing.expectEqual(State.ground, sub.state);
+}