aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-16 23:28:05 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-16 23:29:28 +0300
commit4a3302d19a2baa3a33e910e0088c24e780905b90 (patch)
treedcaf76fae1c82102d933c9225b17ca7ac5d3a847 /vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
parent550e9f8cc085f428429f5cf2da0bb2dba897e8b8 (diff)
chore: update vendored libghostty-vt
refs #276
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig71
1 files changed, 71 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig b/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
index aa35fbeb..bc0ffb5b 100644
--- a/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
+++ b/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
@@ -149,6 +149,26 @@ pub const Parser = struct {
}
}
+ /// Feed a slice of bytes to the parser. This is equivalent to
+ /// calling feed for each byte in order, but once we're in the data
+ /// state the remainder of the slice is appended in bulk, avoiding
+ /// per-byte overhead for large payloads.
+ pub fn feedSlice(self: *Parser, bytes: []const u8) !void {
+ var rem = bytes;
+ while (rem.len > 0) {
+ if (self.state == .data) {
+ if (self.data.items.len + rem.len > self.max_bytes) {
+ return error.OutOfMemory;
+ }
+ try self.data.appendSlice(self.arena.child_allocator, rem);
+ return;
+ }
+
+ try self.feed(rem[0]);
+ rem = rem[1..];
+ }
+ }
+
/// Complete the parsing. This must be called after all the
/// bytes have been fed to the parser.
///
@@ -987,6 +1007,57 @@ test "transmission command" {
try testing.expectEqual(@as(u32, 20), v.height);
}
+test "feedSlice matches per-byte feed" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+
+ const input = "f=24,s=10,v=20;aGVsbG8gd29ybGQ=";
+
+ var p1 = Parser.init(alloc, 1024 * 1024);
+ defer p1.deinit();
+ for (input) |c| try p1.feed(c);
+ const c1 = try p1.complete(alloc);
+ defer c1.deinit(alloc);
+
+ var p2 = Parser.init(alloc, 1024 * 1024);
+ defer p2.deinit();
+ try p2.feedSlice(input);
+ const c2 = try p2.complete(alloc);
+ defer c2.deinit(alloc);
+
+ try testing.expect(c1.control == .transmit);
+ try testing.expect(c2.control == .transmit);
+ try testing.expectEqualStrings(c1.data, c2.data);
+}
+
+test "feedSlice across slice boundaries" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+ var p = Parser.init(alloc, 1024 * 1024);
+ defer p.deinit();
+
+ try p.feedSlice("f=24,s=10");
+ try p.feedSlice(",v=20;aGVsbG8g");
+ try p.feedSlice("d29ybGQ=");
+ const command = try p.complete(alloc);
+ defer command.deinit(alloc);
+
+ try testing.expect(command.control == .transmit);
+
+ // The payload is base64-decoded on completion.
+ try testing.expectEqualStrings("hello world", command.data);
+}
+
+test "feedSlice respects max_bytes" {
+ const testing = std.testing;
+ const alloc = testing.allocator;
+ var p = Parser.init(alloc, 4);
+ defer p.deinit();
+
+ try p.feedSlice("f=24;ab");
+ try testing.expectError(error.OutOfMemory, p.feedSlice("cde"));
+}
+
test "transmission ignores 'm' if medium is not direct" {
const testing = std.testing;
const alloc = testing.allocator;