terminal/kitty-gfx: placement now works properly

This commit is contained in:
Mitchell Hashimoto
2023-08-20 16:56:44 -07:00
parent 7bec2820a7
commit b3a3ca1182
2 changed files with 65 additions and 3 deletions

View File

@ -2,6 +2,7 @@ const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const point = @import("../point.zig");
const Terminal = @import("../Terminal.zig");
const command = @import("graphics_command.zig");
const image = @import("graphics_image.zig");
@ -9,6 +10,11 @@ const Command = command.Command;
const Response = command.Response;
const Image = image.Image;
// TODO:
// - image ids need to be assigned, can't just be zero
// - delete
// (not exhaustive, almost every op is ignoring additional config)
/// Execute a Kitty graphics command against the given terminal. This
/// will never fail, but the response may indicate an error and the
/// terminal state may not be updated to reflect the command. This will
@ -112,16 +118,47 @@ fn display(
cmd: *Command,
) Response {
const d = cmd.display().?;
// Display requires image ID or number.
if (d.image_id == 0 and d.image_number == 0) {
return .{ .message = "EINVAL: image ID or number required" };
}
// Build up our response
var result: Response = .{
.id = d.image_id,
.image_number = d.image_number,
.placement_id = d.placement_id,
};
// TODO
// Verify the requested image exists if we have an ID
const storage = &terminal.screen.kitty_images;
const img_: ?Image = if (d.image_id != 0)
storage.imageById(d.image_id)
else
storage.imageByNumber(d.image_number);
const img = img_ orelse {
result.message = "EINVAL: image not found";
return result;
};
// Make sure our response has the image id in case we looked up by number
result.id = img.id;
// Determine the screen point for the placement.
const placement_point = (point.Viewport{
.x = terminal.screen.cursor.x,
.y = terminal.screen.cursor.y,
}).toScreen(&terminal.screen);
// Add the placement
storage.addPlacement(alloc, img.id, d.placement_id, .{
.point = placement_point,
}) catch |err| {
encodeError(&result, err);
return result;
};
_ = alloc;
_ = terminal;
return result;
}

View File

@ -33,7 +33,22 @@ pub const ImageStorage = struct {
/// Add an already-loaded image to the storage. This will automatically
/// free any existing image with the same ID.
pub fn addImage(self: *ImageStorage, alloc: Allocator, img: Image) Allocator.Error!void {
// Do the gop op first so if it fails we don't get a partial state
const gop = try self.images.getOrPut(alloc, img.id);
// If the image has an image number, we need to invalidate the last
// image with that same number.
if (img.number > 0) {
var it = self.images.iterator();
while (it.next()) |kv| {
if (kv.value_ptr.number == img.number) {
kv.value_ptr.number = 0;
break;
}
}
}
// Write our new image
if (gop.found_existing) gop.value_ptr.deinit(alloc);
gop.value_ptr.* = img;
}
@ -59,6 +74,16 @@ pub const ImageStorage = struct {
return self.images.get(image_id);
}
/// Get an image by its number. If the image doesn't exist, return null.
pub fn imageByNumber(self: *ImageStorage, image_number: u32) ?Image {
var it = self.images.iterator();
while (it.next()) |kv| {
if (kv.value_ptr.number == image_number) return kv.value_ptr.*;
}
return null;
}
/// Every placement is uniquely identified by the image ID and the
/// placement ID. If an image ID isn't specified it is assumed to be 0.
/// Likewise, if a placement ID isn't specified it is assumed to be 0.