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

View File

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