mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 11:35:48 +00:00
libghostty: add placement_rect and centralize opaque typedefs
Expose Placement.rect() from the Zig kitty graphics storage as a new C API function ghostty_kitty_graphics_placement_rect(). It takes the terminal, image handle, and a positioned placement iterator, and writes the bounding grid rectangle into a GhosttySelection out param. Virtual placements return GHOSTTY_NO_VALUE. Move all opaque handle typedefs (GhosttyTerminal, GhosttyKittyGraphics, GhosttyRenderState, GhosttySgrParser, GhosttyFormatter, GhosttyOsc*) into types.h so they are available everywhere without circular includes and Doxygen renders them in the correct @ingroup sections.
This commit is contained in:
@@ -107,13 +107,6 @@ typedef struct {
|
||||
GhosttyFormatterScreenExtra screen;
|
||||
} GhosttyFormatterTerminalExtra;
|
||||
|
||||
/**
|
||||
* Opaque handle to a formatter instance.
|
||||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
typedef struct GhosttyFormatterImpl* GhosttyFormatter;
|
||||
|
||||
/**
|
||||
* Options for creating a terminal formatter.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
#include <ghostty/vt/selection.h>
|
||||
#include <ghostty/vt/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -24,36 +25,6 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics image storage.
|
||||
*
|
||||
* Obtained via ghostty_terminal_get() with
|
||||
* GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS. The pointer is borrowed from
|
||||
* the terminal and remains valid until the next mutating terminal call
|
||||
* (e.g. ghostty_terminal_vt_write() or ghostty_terminal_reset()).
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct GhosttyKittyGraphicsImpl* GhosttyKittyGraphics;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics image.
|
||||
*
|
||||
* Obtained via ghostty_kitty_graphics_image() with an image ID. The
|
||||
* pointer is borrowed from the storage and remains valid until the next
|
||||
* mutating terminal call.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef const struct GhosttyKittyGraphicsImageImpl* GhosttyKittyGraphicsImage;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics placement iterator.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct GhosttyKittyGraphicsPlacementIteratorImpl* GhosttyKittyGraphicsPlacementIterator;
|
||||
|
||||
/**
|
||||
* Queryable data kinds for ghostty_kitty_graphics_get().
|
||||
*
|
||||
@@ -369,6 +340,30 @@ GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get(
|
||||
GhosttyKittyGraphicsPlacementData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Compute the grid rectangle occupied by the current placement.
|
||||
*
|
||||
* Uses the placement's pin, the image dimensions, and the terminal's
|
||||
* cell/pixel geometry to calculate the bounding rectangle. Virtual
|
||||
* placements (unicode placeholders) return GHOSTTY_NO_VALUE.
|
||||
*
|
||||
* @param terminal The terminal handle
|
||||
* @param image The image handle for this placement's image
|
||||
* @param iterator The placement iterator positioned on a placement
|
||||
* @param[out] out_selection On success, receives the bounding rectangle
|
||||
* as a selection with rectangle=true
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if any handle
|
||||
* is NULL or the iterator is not positioned, GHOSTTY_NO_VALUE for
|
||||
* virtual placements or when Kitty graphics are disabled
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_rect(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
GhosttyKittyGraphicsImage image,
|
||||
GhosttyTerminal terminal,
|
||||
GhosttySelection* out_selection);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -13,26 +13,6 @@
|
||||
#include <ghostty/vt/types.h>
|
||||
#include <ghostty/vt/allocator.h>
|
||||
|
||||
/**
|
||||
* Opaque handle to an OSC parser instance.
|
||||
*
|
||||
* This handle represents an OSC (Operating System Command) parser that can
|
||||
* be used to parse the contents of OSC sequences.
|
||||
*
|
||||
* @ingroup osc
|
||||
*/
|
||||
typedef struct GhosttyOscParserImpl *GhosttyOscParser;
|
||||
|
||||
/**
|
||||
* Opaque handle to a single OSC command.
|
||||
*
|
||||
* This handle represents a parsed OSC (Operating System Command) command.
|
||||
* The command can be queried for its type and associated data.
|
||||
*
|
||||
* @ingroup osc
|
||||
*/
|
||||
typedef struct GhosttyOscCommandImpl *GhosttyOscCommand;
|
||||
|
||||
/** @defgroup osc OSC Parser
|
||||
*
|
||||
* OSC (Operating System Command) sequence parser and command handling.
|
||||
|
||||
@@ -81,27 +81,6 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opaque handle to a render state instance.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateImpl* GhosttyRenderState;
|
||||
|
||||
/**
|
||||
* Opaque handle to a render-state row iterator.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateRowIteratorImpl* GhosttyRenderStateRowIterator;
|
||||
|
||||
/**
|
||||
* Opaque handle to render-state row cells.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateRowCellsImpl* GhosttyRenderStateRowCells;
|
||||
|
||||
/**
|
||||
* Dirty state of a render state after update.
|
||||
*
|
||||
|
||||
@@ -47,16 +47,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opaque handle to an SGR parser instance.
|
||||
*
|
||||
* This handle represents an SGR (Select Graphic Rendition) parser that can
|
||||
* be used to parse SGR sequences and extract individual text attributes.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct GhosttySgrParserImpl* GhosttySgrParser;
|
||||
|
||||
/**
|
||||
* SGR attribute tags.
|
||||
*
|
||||
|
||||
@@ -155,13 +155,6 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opaque handle to a terminal instance.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct GhosttyTerminalImpl* GhosttyTerminal;
|
||||
|
||||
/**
|
||||
* Terminal initialization options.
|
||||
*
|
||||
|
||||
@@ -48,6 +48,105 @@ typedef enum {
|
||||
GHOSTTY_NO_VALUE = -4,
|
||||
} GhosttyResult;
|
||||
|
||||
/* ---- Opaque handles ---- */
|
||||
|
||||
/**
|
||||
* Opaque handle to a terminal instance.
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
typedef struct GhosttyTerminalImpl* GhosttyTerminal;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics image storage.
|
||||
*
|
||||
* Obtained via ghostty_terminal_get() with
|
||||
* GHOSTTY_TERMINAL_DATA_KITTY_GRAPHICS. The pointer is borrowed from
|
||||
* the terminal and remains valid until the next mutating terminal call
|
||||
* (e.g. ghostty_terminal_vt_write() or ghostty_terminal_reset()).
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct GhosttyKittyGraphicsImpl* GhosttyKittyGraphics;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics image.
|
||||
*
|
||||
* Obtained via ghostty_kitty_graphics_image() with an image ID. The
|
||||
* pointer is borrowed from the storage and remains valid until the next
|
||||
* mutating terminal call.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef const struct GhosttyKittyGraphicsImageImpl* GhosttyKittyGraphicsImage;
|
||||
|
||||
/**
|
||||
* Opaque handle to a Kitty graphics placement iterator.
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct GhosttyKittyGraphicsPlacementIteratorImpl* GhosttyKittyGraphicsPlacementIterator;
|
||||
|
||||
/**
|
||||
* Opaque handle to a render state instance.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateImpl* GhosttyRenderState;
|
||||
|
||||
/**
|
||||
* Opaque handle to a render-state row iterator.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateRowIteratorImpl* GhosttyRenderStateRowIterator;
|
||||
|
||||
/**
|
||||
* Opaque handle to render-state row cells.
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef struct GhosttyRenderStateRowCellsImpl* GhosttyRenderStateRowCells;
|
||||
|
||||
/**
|
||||
* Opaque handle to an SGR parser instance.
|
||||
*
|
||||
* This handle represents an SGR (Select Graphic Rendition) parser that can
|
||||
* be used to parse SGR sequences and extract individual text attributes.
|
||||
*
|
||||
* @ingroup sgr
|
||||
*/
|
||||
typedef struct GhosttySgrParserImpl* GhosttySgrParser;
|
||||
|
||||
/**
|
||||
* Opaque handle to a formatter instance.
|
||||
*
|
||||
* @ingroup formatter
|
||||
*/
|
||||
typedef struct GhosttyFormatterImpl* GhosttyFormatter;
|
||||
|
||||
/**
|
||||
* Opaque handle to an OSC parser instance.
|
||||
*
|
||||
* This handle represents an OSC (Operating System Command) parser that can
|
||||
* be used to parse the contents of OSC sequences.
|
||||
*
|
||||
* @ingroup osc
|
||||
*/
|
||||
typedef struct GhosttyOscParserImpl* GhosttyOscParser;
|
||||
|
||||
/**
|
||||
* Opaque handle to a single OSC command.
|
||||
*
|
||||
* This handle represents a parsed OSC (Operating System Command) command.
|
||||
* The command can be queried for its type and associated data.
|
||||
*
|
||||
* @ingroup osc
|
||||
*/
|
||||
typedef struct GhosttyOscCommandImpl* GhosttyOscCommand;
|
||||
|
||||
/* ---- Common value types ---- */
|
||||
|
||||
/**
|
||||
* A borrowed byte string (pointer + length).
|
||||
*
|
||||
|
||||
@@ -240,6 +240,7 @@ comptime {
|
||||
@export(&c.kitty_graphics_placement_iterator_free, .{ .name = "ghostty_kitty_graphics_placement_iterator_free" });
|
||||
@export(&c.kitty_graphics_placement_next, .{ .name = "ghostty_kitty_graphics_placement_next" });
|
||||
@export(&c.kitty_graphics_placement_get, .{ .name = "ghostty_kitty_graphics_placement_get" });
|
||||
@export(&c.kitty_graphics_placement_rect, .{ .name = "ghostty_kitty_graphics_placement_rect" });
|
||||
@export(&c.grid_ref_cell, .{ .name = "ghostty_grid_ref_cell" });
|
||||
@export(&c.grid_ref_row, .{ .name = "ghostty_grid_ref_row" });
|
||||
@export(&c.grid_ref_graphemes, .{ .name = "ghostty_grid_ref_graphemes" });
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const build_options = @import("terminal_options");
|
||||
const lib = @import("../lib.zig");
|
||||
const CAllocator = lib.alloc.Allocator;
|
||||
const kitty_storage = @import("../kitty/graphics_storage.zig");
|
||||
const kitty_cmd = @import("../kitty/graphics_command.zig");
|
||||
const Image = @import("../kitty/graphics_image.zig").Image;
|
||||
const grid_ref = @import("grid_ref.zig");
|
||||
const selection_c = @import("selection.zig");
|
||||
const terminal_c = @import("terminal.zig");
|
||||
const Result = @import("result.zig").Result;
|
||||
|
||||
/// C: GhosttyKittyGraphics
|
||||
@@ -267,8 +271,31 @@ fn placementGetTyped(
|
||||
return .success;
|
||||
}
|
||||
|
||||
const testing = std.testing;
|
||||
const terminal_c = @import("terminal.zig");
|
||||
pub fn placement_rect(
|
||||
iter_: PlacementIterator,
|
||||
image_: ImageHandle,
|
||||
terminal_: terminal_c.Terminal,
|
||||
out: *selection_c.CSelection,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
if (comptime !build_options.kitty_graphics) return .no_value;
|
||||
|
||||
const wrapper = terminal_ orelse return .invalid_value;
|
||||
const image = image_ orelse return .invalid_value;
|
||||
const iter = iter_ orelse return .invalid_value;
|
||||
const entry = iter.entry orelse return .invalid_value;
|
||||
const r = entry.value_ptr.rect(
|
||||
image.*,
|
||||
wrapper.terminal,
|
||||
) orelse return .no_value;
|
||||
|
||||
out.* = .{
|
||||
.start = grid_ref.CGridRef.fromPin(r.top_left),
|
||||
.end = grid_ref.CGridRef.fromPin(r.bottom_right),
|
||||
.rectangle = true,
|
||||
};
|
||||
|
||||
return .success;
|
||||
}
|
||||
|
||||
test "placement_iterator new/free" {
|
||||
var iter: PlacementIterator = null;
|
||||
@@ -525,6 +552,67 @@ test "image_get_handle and image_get with transmitted image" {
|
||||
try testing.expect(data_len > 0);
|
||||
}
|
||||
|
||||
test "placement_rect with transmit and display" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var t: terminal_c.Terminal = null;
|
||||
try testing.expectEqual(Result.success, terminal_c.new(
|
||||
&lib.alloc.test_allocator,
|
||||
&t,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 0 },
|
||||
));
|
||||
defer terminal_c.free(t);
|
||||
|
||||
// Set cell size so grid calculations are deterministic.
|
||||
// 80 cols * 10px = 800px, 24 rows * 20px = 480px.
|
||||
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
|
||||
|
||||
// Transmit and display a 1x2 RGB image at cursor (0,0).
|
||||
// c=10,r=1 => 10 columns, 1 row.
|
||||
const cmd = "\x1b_Ga=T,t=d,f=24,i=1,p=1,s=1,v=2,c=10,r=1;////////\x1b\\";
|
||||
terminal_c.vt_write(t, cmd.ptr, cmd.len);
|
||||
|
||||
var graphics: KittyGraphics = undefined;
|
||||
try testing.expectEqual(Result.success, terminal_c.get(
|
||||
t,
|
||||
.kitty_graphics,
|
||||
@ptrCast(&graphics),
|
||||
));
|
||||
|
||||
const img = image_get_handle(graphics, 1);
|
||||
try testing.expect(img != null);
|
||||
|
||||
var iter: PlacementIterator = null;
|
||||
try testing.expectEqual(Result.success, placement_iterator_new(
|
||||
&lib.alloc.test_allocator,
|
||||
&iter,
|
||||
));
|
||||
defer placement_iterator_free(iter);
|
||||
|
||||
try testing.expectEqual(Result.success, get(graphics, .placement_iterator, @ptrCast(&iter)));
|
||||
try testing.expect(placement_iterator_next(iter));
|
||||
|
||||
var sel: selection_c.CSelection = undefined;
|
||||
try testing.expectEqual(Result.success, placement_rect(iter, img, t, &sel));
|
||||
|
||||
// Placement starts at cursor origin (0,0).
|
||||
try testing.expectEqual(0, sel.start.x);
|
||||
try testing.expectEqual(0, sel.start.y);
|
||||
|
||||
// 10 columns wide, 1 row tall => bottom-right is (9, 0).
|
||||
try testing.expectEqual(9, sel.end.x);
|
||||
try testing.expectEqual(0, sel.end.y);
|
||||
|
||||
try testing.expect(sel.rectangle);
|
||||
}
|
||||
|
||||
test "placement_rect null args return invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var sel: selection_c.CSelection = undefined;
|
||||
try testing.expectEqual(Result.invalid_value, placement_rect(null, null, null, &sel));
|
||||
}
|
||||
|
||||
test "image_get on null returns invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ pub const kitty_graphics_placement_iterator_new = kitty_graphics.placement_itera
|
||||
pub const kitty_graphics_placement_iterator_free = kitty_graphics.placement_iterator_free;
|
||||
pub const kitty_graphics_placement_next = kitty_graphics.placement_iterator_next;
|
||||
pub const kitty_graphics_placement_get = kitty_graphics.placement_get;
|
||||
pub const kitty_graphics_placement_rect = kitty_graphics.placement_rect;
|
||||
pub const types = @import("types.zig");
|
||||
pub const modes = @import("modes.zig");
|
||||
pub const osc = @import("osc.zig");
|
||||
|
||||
Reference in New Issue
Block a user