aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/Terminal.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
commitdcfe11a7588fcd42471159453810abc9b7720a57 (patch)
treec32a77266028e73ca2382b96c96f8438a5fcd621 /vendor/libghostty-vt/src/terminal/Terminal.zig
parent2dfed860103c4e4505ac7f25def9fe37da1e1e6a (diff)
build: update libghostty-vt vendor
vendor ghostty 063ac3e and remove the musl libc++ link workaround. expose the new selection formatter and hyperlink uri apis for follow-up rendering work. add manual artifact validation for static linux builds.
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/Terminal.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/Terminal.zig91
1 files changed, 83 insertions, 8 deletions
diff --git a/vendor/libghostty-vt/src/terminal/Terminal.zig b/vendor/libghostty-vt/src/terminal/Terminal.zig
index 99536e7a..6740a93e 100644
--- a/vendor/libghostty-vt/src/terminal/Terminal.zig
+++ b/vendor/libghostty-vt/src/terminal/Terminal.zig
@@ -191,6 +191,26 @@ pub const Options = struct {
/// The default mode state. When the terminal gets a reset, it
/// will revert back to this state.
default_modes: modespkg.ModePacked = .{},
+
+ /// The total storage limit for Kitty images in bytes. Has no effect
+ /// if kitty images are disabled at build-time.
+ kitty_image_storage_limit: usize = switch (build_options.artifact) {
+ .ghostty => 320 * 1000 * 1000, // 320MB
+
+ // libghostty we start with a much lower limit since this is an
+ // embedded library and we want to be more conservative with memory
+ // usage by default.
+ .lib => 10 * 1000 * 1000, // 10MB
+ },
+
+ /// The limits for what medium types are allowed for Kitty image loading.
+ /// Has no effect if kitty images are disabled otherwise. For example,
+ // if no `sys.decode_png` hook is specified, png formats are disabled
+ // no matter what.
+ kitty_image_loading_limits: if (build_options.kitty_graphics)
+ kitty.graphics.LoadingImage.Limits
+ else
+ void = if (build_options.kitty_graphics) .direct else {},
};
/// Initialize a new terminal.
@@ -205,6 +225,8 @@ pub fn init(
.cols = cols,
.rows = rows,
.max_scrollback = opts.max_scrollback,
+ .kitty_image_storage_limit = opts.kitty_image_storage_limit,
+ .kitty_image_loading_limits = opts.kitty_image_loading_limits,
});
errdefer screen_set.deinit(alloc);
@@ -551,20 +573,25 @@ pub fn print(self: *Terminal, c: u21) !void {
// it.
if (self.modes.get(.grapheme_cluster)) return;
- // If we're at cell zero, then this is malformed data and we don't
- // print anything or even store this. Zero-width characters are ALWAYS
- // attached to some other non-zero-width character at the time of
- // writing.
- if (self.screens.active.cursor.x == 0) {
+ // If we have wraparound enabled and a pending wrap, the character
+ // we're attaching to is still under the cursor. Otherwise, it's the
+ // cell to the left.
+ const left: size.CellCountInt = if (self.modes.get(.wraparound) and self.screens.active.cursor.pending_wrap) 0 else 1;
+
+ // If we're at cell zero and not pending a wrap, then this is malformed
+ // data and we don't print anything or even store this. Zero-width
+ // characters are ALWAYS attached to some other non-zero-width
+ // character at the time of writing.
+ if (self.screens.active.cursor.x == 0 and left == 1) {
log.warn("zero-width character with no prior character, ignoring", .{});
return;
}
// Find our previous cell
const prev = prev: {
- const immediate = self.screens.active.cursorCellLeft(1);
+ const immediate = self.screens.active.cursorCellLeft(left);
if (immediate.wide != .spacer_tail) break :prev immediate;
- break :prev self.screens.active.cursorCellLeft(2);
+ break :prev self.screens.active.cursorCellLeft(left + 1);
};
// If our previous cell has no text, just ignore the zero-width character
@@ -2693,6 +2720,34 @@ pub fn kittyGraphics(
return kitty.graphics.execute(alloc, self, cmd);
}
+/// Set the storage size limit for Kitty graphics across all screens.
+pub fn setKittyGraphicsSizeLimit(
+ self: *Terminal,
+ alloc: Allocator,
+ limit: usize,
+) !void {
+ if (comptime !build_options.kitty_graphics) return;
+ var it = self.screens.all.iterator();
+ while (it.next()) |entry| {
+ const screen: *Screen = entry.value.*;
+ try screen.kitty_images.setLimit(alloc, screen, limit);
+ }
+}
+
+/// Set the allowed medium types for Kitty graphics image loading
+/// across all screens.
+pub fn setKittyGraphicsLoadingLimits(
+ self: *Terminal,
+ limits: kitty.graphics.LoadingImage.Limits,
+) void {
+ if (comptime !build_options.kitty_graphics) return;
+ var it = self.screens.all.iterator();
+ while (it.next()) |entry| {
+ const screen: *Screen = entry.value.*;
+ screen.kitty_images.image_limits = limits;
+ }
+}
+
/// Set a style attribute.
pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
try self.screens.active.setAttribute(attr);
@@ -2941,12 +2996,15 @@ pub fn switchScreen(self: *Terminal, key: ScreenSet.Key) !?*Screen {
.alternate => 0,
},
- // Inherit our Kitty image storage limit from the primary
+ // Inherit our Kitty image settings from the primary
// screen if we have to initialize.
.kitty_image_storage_limit = if (comptime build_options.kitty_graphics)
primary.kitty_images.total_limit
else
0,
+ .kitty_image_loading_limits = if (comptime build_options.kitty_graphics)
+ primary.kitty_images.image_limits
+ else {},
},
);
};
@@ -3260,6 +3318,23 @@ test "Terminal: zero-width character at start" {
try testing.expect(!t.isDirty(.{ .screen = .{ .x = 0, .y = 0 } }));
}
+// https://github.com/ghostty-org/ghostty/issues/12581
+test "Terminal: zero-width character attaches to pending wrap cell" {
+ var t = try init(testing.allocator, .{ .cols = 2, .rows = 2 });
+ defer t.deinit(testing.allocator);
+
+ // Disable grapheme clustering to exercise the fallback path.
+ t.modes.set(.grapheme_cluster, false);
+
+ try t.print('x');
+ try t.print('å');
+ try t.print(0x0332); // Combining low line.
+
+ const str = try t.plainString(testing.allocator);
+ defer testing.allocator.free(str);
+ try testing.expectEqualStrings("xå̲", str);
+}
+
// https://github.com/mitchellh/ghostty/issues/1400
test "Terminal: print single very long line" {
var t = try init(testing.allocator, .{ .rows = 5, .cols = 5 });