mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
terminal/kitty: add loading limits to kitty graphics protocol
Add a Limits type to LoadingImage that controls which transmission mediums (file, temporary_file, shared_memory) are allowed when loading images. This defaults to "direct" (most restrictive) on ImageStorage and is set to "all" by Termio, allowing apprt embedders like libghostty to restrict medium types for resource or security reasons. The limits are stored on ImageStorage, plumbed through Screen.Options for screen initialization and inheritance, and enforced in graphics_exec during both query and transmit. Two new Terminal methods (setKittyGraphicsSizeLimit, setKittyGraphicsLoadingLimits) centralize updating all screens, replacing the manual iteration previously done in Termio.
This commit is contained in:
@@ -257,6 +257,12 @@ pub const Options = struct {
|
||||
/// screen. Kitty image storage is per-screen.
|
||||
kitty_image_storage_limit: usize = 320 * 1000 * 1000, // 320MB
|
||||
|
||||
/// The limits for what medium types are allowed for Kitty image loading.
|
||||
kitty_image_loading_limits: if (build_options.kitty_graphics)
|
||||
kitty.graphics.LoadingImage.Limits
|
||||
else
|
||||
void = if (build_options.kitty_graphics) .direct else {},
|
||||
|
||||
/// A simple, default terminal. If you rely on specific dimensions or
|
||||
/// scrollback (or lack of) then do not use this directly. This is just
|
||||
/// for callers that need some defaults.
|
||||
@@ -313,6 +319,7 @@ pub fn init(
|
||||
&result,
|
||||
opts.kitty_image_storage_limit,
|
||||
) catch unreachable;
|
||||
result.kitty_images.image_limits = opts.kitty_image_loading_limits;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -2693,6 +2693,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 +2969,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 {},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ pub const unicode = @import("graphics_unicode.zig");
|
||||
pub const Command = command.Command;
|
||||
pub const CommandParser = command.Parser;
|
||||
pub const Image = image.Image;
|
||||
pub const LoadingImage = image.LoadingImage;
|
||||
pub const ImageStorage = storage.ImageStorage;
|
||||
pub const RenderPlacement = render.Placement;
|
||||
pub const Response = command.Response;
|
||||
|
||||
@@ -44,7 +44,7 @@ pub fn execute(
|
||||
var quiet = cmd.quiet;
|
||||
|
||||
const resp_: ?Response = switch (cmd.control) {
|
||||
.query => query(alloc, cmd),
|
||||
.query => query(alloc, terminal, cmd),
|
||||
.display => display(alloc, terminal, cmd),
|
||||
.delete => delete(alloc, terminal, cmd),
|
||||
|
||||
@@ -94,7 +94,11 @@ pub fn execute(
|
||||
/// This command is used to attempt to load an image and respond with
|
||||
/// success/error but does not persist any of the command to the terminal
|
||||
/// state.
|
||||
fn query(alloc: Allocator, cmd: *const Command) Response {
|
||||
fn query(
|
||||
alloc: Allocator,
|
||||
terminal: *const Terminal,
|
||||
cmd: *const Command,
|
||||
) Response {
|
||||
const t = cmd.control.query;
|
||||
|
||||
// Query requires image ID. We can't actually send a response without
|
||||
@@ -112,7 +116,8 @@ fn query(alloc: Allocator, cmd: *const Command) Response {
|
||||
};
|
||||
|
||||
// Attempt to load the image. If we cannot, then set an appropriate error.
|
||||
var loading = LoadingImage.init(alloc, cmd, .all) catch |err| {
|
||||
const storage = &terminal.screens.active.kitty_images;
|
||||
var loading = LoadingImage.init(alloc, cmd, storage.image_limits) catch |err| {
|
||||
encodeError(&result, err);
|
||||
return result;
|
||||
};
|
||||
@@ -322,7 +327,7 @@ fn loadAndAddImage(
|
||||
}
|
||||
|
||||
break :loading loading.*;
|
||||
} else try .init(alloc, cmd, .all);
|
||||
} else try .init(alloc, cmd, storage.image_limits);
|
||||
|
||||
// We only want to deinit on error. If we're chunking, then we don't
|
||||
// want to deinit at all. If we're not chunking, then we'll deinit
|
||||
|
||||
@@ -51,6 +51,9 @@ pub const ImageStorage = struct {
|
||||
/// Non-null if there is an in-progress loading image.
|
||||
loading: ?*LoadingImage = null,
|
||||
|
||||
/// The limits of what medium types are allowed for image loading.
|
||||
image_limits: LoadingImage.Limits = .direct,
|
||||
|
||||
/// The total bytes of image data that have been loaded and the limit.
|
||||
/// If the limit is reached, the oldest images will be evicted to make
|
||||
/// space. Unused images take priority.
|
||||
@@ -89,8 +92,9 @@ pub const ImageStorage = struct {
|
||||
) !void {
|
||||
// Special case disabling by quickly deleting all
|
||||
if (limit == 0) {
|
||||
const image_limits = self.image_limits;
|
||||
self.deinit(alloc, s);
|
||||
self.* = .{};
|
||||
self.* = .{ .image_limits = image_limits };
|
||||
}
|
||||
|
||||
// If we re lowering our limit, check if we need to evict.
|
||||
|
||||
@@ -259,16 +259,9 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
|
||||
});
|
||||
errdefer term.deinit(alloc);
|
||||
|
||||
// Set the image size limits
|
||||
var it = term.screens.all.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const screen: *terminalpkg.Screen = entry.value.*;
|
||||
try screen.kitty_images.setLimit(
|
||||
alloc,
|
||||
screen,
|
||||
opts.config.image_storage_limit,
|
||||
);
|
||||
}
|
||||
// Set the Kitty image settings
|
||||
try term.setKittyGraphicsSizeLimit(alloc, opts.config.image_storage_limit);
|
||||
term.setKittyGraphicsLoadingLimits(.all);
|
||||
|
||||
// Set our default cursor style
|
||||
term.screens.active.cursor.cursor_style = opts.config.cursor_style;
|
||||
@@ -463,16 +456,9 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi
|
||||
break :cursor color.toTerminalRGB() orelse break :cursor null;
|
||||
};
|
||||
|
||||
// Set the image size limits
|
||||
var it = self.terminal.screens.all.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const screen: *terminalpkg.Screen = entry.value.*;
|
||||
try screen.kitty_images.setLimit(
|
||||
self.alloc,
|
||||
screen,
|
||||
config.image_storage_limit,
|
||||
);
|
||||
}
|
||||
// Set the image limits
|
||||
try self.terminal.setKittyGraphicsSizeLimit(self.alloc, config.image_storage_limit);
|
||||
self.terminal.setKittyGraphicsLoadingLimits(.all);
|
||||
}
|
||||
|
||||
/// Resize the terminal.
|
||||
|
||||
Reference in New Issue
Block a user