aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/c/render.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/c/render.zig
parent550e9f8cc085f428429f5cf2da0bb2dba897e8b8 (diff)
chore: update vendored libghostty-vt
refs #276
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/c/render.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/c/render.zig173
1 files changed, 153 insertions, 20 deletions
diff --git a/vendor/libghostty-vt/src/terminal/c/render.zig b/vendor/libghostty-vt/src/terminal/c/render.zig
index 0f3b2e78..6cf78ec5 100644
--- a/vendor/libghostty-vt/src/terminal/c/render.zig
+++ b/vendor/libghostty-vt/src/terminal/c/render.zig
@@ -188,6 +188,25 @@ pub fn update(
return .success;
}
+pub fn begin_update(
+ state_: RenderState,
+ terminal_: terminal_c.Terminal,
+) callconv(lib.calling_conv) Result {
+ const state = state_ orelse return .invalid_value;
+ const t: *ZigTerminal = (terminal_ orelse return .invalid_value).terminal;
+
+ state.state.beginUpdate(state.alloc, t) catch return .out_of_memory;
+ return .success;
+}
+
+pub fn end_update(
+ state_: RenderState,
+) callconv(lib.calling_conv) Result {
+ const state = state_ orelse return .invalid_value;
+ state.state.endUpdate();
+ return .success;
+}
+
pub fn get(
state_: RenderState,
data: Data,
@@ -591,7 +610,7 @@ fn rowCellsGetGraphemesUtf8(
if (!cell.hasText()) return .success;
- var needed = std.unicode.utf8CodepointSequenceLength(cell.codepoint()) catch
+ var needed: usize = std.unicode.utf8CodepointSequenceLength(cell.codepoint()) catch
return .invalid_value;
for (extra) |cp| {
needed += std.unicode.utf8CodepointSequenceLength(cp) catch
@@ -787,6 +806,61 @@ test "render: update invalid value" {
try testing.expectEqual(Result.invalid_value, update(state, null));
}
+test "render: begin/end update invalid value" {
+ var state: RenderState = null;
+ try testing.expectEqual(Result.success, new(
+ &lib.alloc.test_allocator,
+ &state,
+ ));
+ defer free(state);
+
+ try testing.expectEqual(Result.invalid_value, begin_update(null, null));
+ try testing.expectEqual(Result.invalid_value, begin_update(state, null));
+ try testing.expectEqual(Result.invalid_value, end_update(null));
+
+ // End without a begin is safe.
+ try testing.expectEqual(Result.success, end_update(state));
+}
+
+test "render: begin/end update" {
+ var terminal: terminal_c.Terminal = null;
+ try testing.expectEqual(Result.success, terminal_c.new(
+ &lib.alloc.test_allocator,
+ &terminal,
+ .{
+ .cols = 10,
+ .rows = 3,
+ .max_scrollback = 10_000,
+ },
+ ));
+ defer terminal_c.free(terminal);
+
+ // Write some styled text so that the update has deferred work.
+ const t = terminal.?.terminal;
+ var s = t.vtStream();
+ defer s.deinit();
+ s.nextSlice("\x1b[1mAB"); // Bold
+
+ var state: RenderState = null;
+ try testing.expectEqual(Result.success, new(
+ &lib.alloc.test_allocator,
+ &state,
+ ));
+ defer free(state);
+
+ // Begin should record pending work, end should complete it.
+ try testing.expectEqual(Result.success, begin_update(state, terminal));
+ try testing.expect(state.?.state.pending_styles.items.len > 0);
+ try testing.expectEqual(Result.success, end_update(state));
+ try testing.expectEqual(0, state.?.state.pending_styles.items.len);
+
+ // The cell styles should be complete.
+ const row_data = state.?.state.row_data.slice();
+ const cells = row_data.items(.cells);
+ try testing.expect(cells[0].get(0).style.flags.bold);
+ try testing.expect(cells[0].get(1).style.flags.bold);
+}
+
test "render: get invalid value" {
var cols: size.CellCountInt = 0;
try testing.expectEqual(Result.invalid_value, get(null, .cols, @ptrCast(&cols)));
@@ -1293,6 +1367,82 @@ test "render: row cells get has_styling" {
}
test "render: row cells get graphemes utf8" {
+ const cases = [_]struct {
+ terminal_input: []const u8,
+ expected: []const u8,
+ }{
+ .{
+ .terminal_input = "e\u{301}",
+ .expected = "e\u{301}",
+ },
+ .{
+ .terminal_input = "\x1b[?2027h\u{1F1FA}\u{1F1F8}",
+ .expected = "\u{1F1FA}\u{1F1F8}",
+ },
+ .{
+ .terminal_input = "\x1b[?2027h\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}",
+ .expected = "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}",
+ },
+ };
+
+ for (cases) |case| {
+ var terminal: terminal_c.Terminal = null;
+ try testing.expectEqual(Result.success, terminal_c.new(
+ &lib.alloc.test_allocator,
+ &terminal,
+ .{ .cols = 10, .rows = 3, .max_scrollback = 10_000 },
+ ));
+ defer terminal_c.free(terminal);
+
+ terminal_c.vt_write(terminal, case.terminal_input.ptr, case.terminal_input.len);
+
+ var state: RenderState = null;
+ try testing.expectEqual(Result.success, new(
+ &lib.alloc.test_allocator,
+ &state,
+ ));
+ defer free(state);
+
+ try testing.expectEqual(Result.success, update(state, terminal));
+
+ var it: RowIterator = null;
+ try testing.expectEqual(Result.success, row_iterator_new(
+ &lib.alloc.test_allocator,
+ &it,
+ ));
+ defer row_iterator_free(it);
+
+ var cells: RowCells = null;
+ try testing.expectEqual(Result.success, row_cells_new(
+ &lib.alloc.test_allocator,
+ &cells,
+ ));
+ defer row_cells_free(cells);
+
+ try testing.expectEqual(Result.success, get(state, .row_iterator, @ptrCast(&it)));
+ try testing.expect(row_iterator_next(it));
+ try testing.expectEqual(Result.success, row_get(it, .cells, @ptrCast(&cells)));
+
+ try testing.expectEqual(Result.success, row_cells_select(cells, 0));
+
+ var text: lib.Buffer = .{};
+ try testing.expectEqual(Result.out_of_space, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
+ try testing.expectEqual(case.expected.len, text.len);
+
+ var small = [_]u8{'x'} ** 32;
+ const small_cap = case.expected.len - 1;
+ text = .{ .ptr = small[0..small_cap].ptr, .cap = small_cap };
+ try testing.expectEqual(Result.out_of_space, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
+ try testing.expectEqual(case.expected.len, text.len);
+ try testing.expectEqualSlices(u8, &([_]u8{'x'} ** 32), &small);
+
+ var buf: [32]u8 = undefined;
+ text = .{ .ptr = &buf, .cap = case.expected.len };
+ try testing.expectEqual(Result.success, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
+ try testing.expectEqual(case.expected.len, text.len);
+ try testing.expectEqualStrings(case.expected, buf[0..text.len]);
+ }
+
var terminal: terminal_c.Terminal = null;
try testing.expectEqual(Result.success, terminal_c.new(
&lib.alloc.test_allocator,
@@ -1331,26 +1481,9 @@ test "render: row cells get graphemes utf8" {
try testing.expect(row_iterator_next(it));
try testing.expectEqual(Result.success, row_get(it, .cells, @ptrCast(&cells)));
- try testing.expectEqual(Result.success, row_cells_select(cells, 0));
-
- var text: lib.Buffer = .{};
- try testing.expectEqual(Result.out_of_space, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
- try testing.expectEqual(@as(usize, input.len), text.len);
-
- var small = [_]u8{ 'x', 'x' };
- text = .{ .ptr = &small, .cap = small.len };
- try testing.expectEqual(Result.out_of_space, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
- try testing.expectEqual(@as(usize, input.len), text.len);
- try testing.expectEqualSlices(u8, &.{ 'x', 'x' }, &small);
-
- var buf: [8]u8 = undefined;
- text = .{ .ptr = &buf, .cap = buf.len };
- try testing.expectEqual(Result.success, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
- try testing.expectEqual(input.len, text.len);
- try testing.expectEqualStrings(input, buf[0..text.len]);
-
try testing.expectEqual(Result.success, row_cells_select(cells, 1));
- text = .{ .ptr = &buf, .cap = buf.len };
+ var buf: [8]u8 = undefined;
+ var text: lib.Buffer = .{ .ptr = &buf, .cap = buf.len };
try testing.expectEqual(Result.success, row_cells_get(cells, .graphemes_utf8, @ptrCast(&text)));
try testing.expectEqual(@as(usize, 0), text.len);
}