terminal/kitty: add virtual placeholders placements

This commit is contained in:
Mitchell Hashimoto
2024-07-24 11:49:42 -07:00
parent a5c382633f
commit 7d9e50353b
2 changed files with 46 additions and 23 deletions

View File

@ -184,21 +184,26 @@ fn display(
// Make sure our response has the image id in case we looked up by number
result.id = img.id;
// Track a new pin for our cursor. The cursor is always tracked but we
// don't want this one to move with the cursor.
const placement_pin = terminal.screen.pages.trackPin(
terminal.screen.cursor.page_pin.*,
) catch |err| {
log.warn("failed to create pin for Kitty graphics err={}", .{err});
result.message = "EINVAL: failed to prepare terminal state";
return result;
// Location where the placement will go.
const location: ImageStorage.Placement.Location = location: {
// Virtual placements are not tracked
if (d.virtual_placement) break :location .{ .virtual = {} };
// Track a new pin for our cursor. The cursor is always tracked but we
// don't want this one to move with the cursor.
const pin = terminal.screen.pages.trackPin(
terminal.screen.cursor.page_pin.*,
) catch |err| {
log.warn("failed to create pin for Kitty graphics err={}", .{err});
result.message = "EINVAL: failed to prepare terminal state";
return result;
};
break :location .{ .pin = pin };
};
// Add the placement
const p: ImageStorage.Placement = .{
.location = .{
.pin = placement_pin,
},
.location = location,
.x_offset = d.x_offset,
.y_offset = d.y_offset,
.source_x = d.x,
@ -222,6 +227,7 @@ fn display(
// Apply cursor movement setting. This only applies to pin placements.
switch (p.location) {
.virtual => {},
.pin => |pin| switch (d.cursor_movement) {
.none => {},
.after => {

View File

@ -218,6 +218,7 @@ pub const ImageStorage = struct {
cmd: command.Delete,
) void {
switch (cmd) {
// TODO: virtual placeholders must not be deleted according to spec
.all => |delete_images| if (delete_images) {
// We just reset our entire state.
self.deinit(alloc, &t.screen);
@ -318,7 +319,7 @@ pub const ImageStorage = struct {
var it = self.placements.iterator();
while (it.next()) |entry| {
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
const rect = entry.value_ptr.rect(img, t);
const rect = entry.value_ptr.rect(img, t) orelse continue;
if (rect.top_left.x <= x and rect.bottom_right.x >= x) {
entry.value_ptr.deinit(&t.screen);
self.placements.removeByPtr(entry.key_ptr);
@ -345,7 +346,7 @@ pub const ImageStorage = struct {
var it = self.placements.iterator();
while (it.next()) |entry| {
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
const rect = entry.value_ptr.rect(img, t);
const rect = entry.value_ptr.rect(img, t) orelse continue;
// We need to copy our pin to ensure we are at least at
// the top-left x.
@ -365,6 +366,14 @@ pub const ImageStorage = struct {
.z => |v| {
var it = self.placements.iterator();
while (it.next()) |entry| {
switch (entry.value_ptr.location) {
.pin => {},
// Virtual placeholders cannot delete by z according
// to the spec.
.virtual => continue,
}
if (entry.value_ptr.z == v.z) {
const image_id = entry.key_ptr.image_id;
entry.value_ptr.deinit(&t.screen);
@ -451,7 +460,7 @@ pub const ImageStorage = struct {
var it = self.placements.iterator();
while (it.next()) |entry| {
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
const rect = entry.value_ptr.rect(img, t);
const rect = entry.value_ptr.rect(img, t) orelse continue;
if (target_pin.isBetween(rect.top_left, rect.bottom_right)) {
if (filter) |f| if (!f(filter_ctx, entry.value_ptr.*)) continue;
entry.value_ptr.deinit(&t.screen);
@ -577,10 +586,7 @@ pub const ImageStorage = struct {
pub const Placement = struct {
/// The location where this placement should be drawn.
location: union(enum) {
/// Exactly placed on a screen pin.
pin: *PageList.Pin,
},
location: Location,
/// Offset of the x/y from the top-left of the cell.
x_offset: u32 = 0,
@ -599,12 +605,21 @@ pub const ImageStorage = struct {
/// The z-index for this placement.
z: i32 = 0,
pub const Location = union(enum) {
/// Exactly placed on a screen pin.
pin: *PageList.Pin,
/// Virtual placement (U=1) for unicode placeholders.
virtual: void,
};
pub fn deinit(
self: *const Placement,
s: *terminal.Screen,
) void {
switch (self.location) {
.pin => |p| s.pages.untrackPin(p),
.virtual => {},
}
}
@ -647,16 +662,18 @@ pub const ImageStorage = struct {
}
/// Returns a selection of the entire rectangle this placement
/// occupies within the screen.
/// occupies within the screen. This can return null if the placement
/// doesn't have an associated rect (i.e. a virtual placement).
pub fn rect(
self: Placement,
image: Image,
t: *const terminal.Terminal,
) Rect {
assert(self.location == .pin);
) ?Rect {
const grid_size = self.gridSize(image, t);
const pin = self.location.pin;
const pin = switch (self.location) {
.pin => |p| p,
.virtual => return null,
};
var br = switch (pin.downOverflow(grid_size.rows - 1)) {
.offset => |v| v,