mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 11:35:48 +00:00
libghostty: add _get_multi to all _get APIs
Replace the ImageInfo and PlacementInfo sized structs and their associated .info enum variants with a new _get_multi pattern that batches multiple enum+pointer pairs into a single call. This avoids struct ABI concerns (field order, padding, alignment, GHOSTTY_INIT_SIZED) while preserving the single-call-crossing performance benefit for FFI and Cgo callers. Each _get_multi function takes an array of enum keys, an array of output pointers, and an optional out_written parameter that reports how many values were successfully written before any error. This applies uniformly to all _get APIs: terminal_get, cell_get, row_get, render_state_get, render_state_row_get, render_state_row_cells_get, kitty_graphics_image_get, and kitty_graphics_placement_get. The C example is updated to use compound-literal _get_multi calls, and tests cover both success and error paths for every new function.
This commit is contained in:
@@ -145,14 +145,15 @@ int main() {
|
||||
bool is_virtual = false;
|
||||
int32_t z = 0;
|
||||
|
||||
ghostty_kitty_graphics_placement_get(iter,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID, &image_id);
|
||||
ghostty_kitty_graphics_placement_get(iter,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID, &placement_id);
|
||||
ghostty_kitty_graphics_placement_get(iter,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL, &is_virtual);
|
||||
ghostty_kitty_graphics_placement_get(iter,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z, &z);
|
||||
ghostty_kitty_graphics_placement_get_multi(iter, 4,
|
||||
(GhosttyKittyGraphicsPlacementData[]){
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IMAGE_ID,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_PLACEMENT_ID,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_IS_VIRTUAL,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z,
|
||||
},
|
||||
(void*[]){ &image_id, &placement_id, &is_virtual, &z },
|
||||
NULL);
|
||||
|
||||
printf(" placement #%d: image_id=%u placement_id=%u virtual=%s z=%d\n",
|
||||
placement_count, image_id, placement_id,
|
||||
@@ -170,11 +171,16 @@ int main() {
|
||||
GhosttyKittyImageFormat format = 0;
|
||||
size_t data_len = 0;
|
||||
|
||||
ghostty_kitty_graphics_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_NUMBER, &number);
|
||||
ghostty_kitty_graphics_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_WIDTH, &width);
|
||||
ghostty_kitty_graphics_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_HEIGHT, &height);
|
||||
ghostty_kitty_graphics_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_FORMAT, &format);
|
||||
ghostty_kitty_graphics_image_get(image, GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN, &data_len);
|
||||
ghostty_kitty_graphics_image_get_multi(image, 5,
|
||||
(GhosttyKittyGraphicsImageData[]){
|
||||
GHOSTTY_KITTY_IMAGE_DATA_NUMBER,
|
||||
GHOSTTY_KITTY_IMAGE_DATA_WIDTH,
|
||||
GHOSTTY_KITTY_IMAGE_DATA_HEIGHT,
|
||||
GHOSTTY_KITTY_IMAGE_DATA_FORMAT,
|
||||
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN,
|
||||
},
|
||||
(void*[]){ &number, &width, &height, &format, &data_len },
|
||||
NULL);
|
||||
|
||||
printf(" image: number=%u size=%ux%u format=%d data_len=%zu\n",
|
||||
number, width, height, format, data_len);
|
||||
|
||||
@@ -215,17 +215,6 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_Z = 12,
|
||||
|
||||
/**
|
||||
* All placement metadata as a sized struct.
|
||||
*
|
||||
* This is an optimization over querying each field individually,
|
||||
* particularly useful in environments with high per-call overhead
|
||||
* such as FFI or Cgo.
|
||||
*
|
||||
* Output type: GhosttyKittyGraphicsPlacementInfo *
|
||||
* (initialize with GHOSTTY_INIT_SIZED)
|
||||
*/
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO = 13,
|
||||
GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsPlacementData;
|
||||
|
||||
@@ -354,96 +343,9 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_DATA_LEN = 8,
|
||||
|
||||
/**
|
||||
* All image metadata as a sized struct.
|
||||
*
|
||||
* This is an optimization over querying each field individually,
|
||||
* particularly useful in environments with high per-call overhead
|
||||
* such as FFI or Cgo.
|
||||
*
|
||||
* Output type: GhosttyKittyGraphicsImageInfo *
|
||||
* (initialize with GHOSTTY_INIT_SIZED)
|
||||
*/
|
||||
GHOSTTY_KITTY_IMAGE_DATA_INFO = 9,
|
||||
GHOSTTY_KITTY_IMAGE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||
} GhosttyKittyGraphicsImageData;
|
||||
|
||||
/**
|
||||
* All image metadata in a single sized struct.
|
||||
*
|
||||
* Returned by ghostty_kitty_graphics_image_get() with
|
||||
* GHOSTTY_KITTY_IMAGE_DATA_INFO. This is an optimization over
|
||||
* querying each field individually, particularly useful in
|
||||
* environments with high per-call overhead such as FFI or Cgo.
|
||||
*
|
||||
* This struct uses the sized-struct ABI pattern. Initialize with
|
||||
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsImageInfo).
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct {
|
||||
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsImageInfo). */
|
||||
size_t size;
|
||||
/** The image ID. */
|
||||
uint32_t id;
|
||||
/** The image number. */
|
||||
uint32_t number;
|
||||
/** Image width in pixels. */
|
||||
uint32_t width;
|
||||
/** Image height in pixels. */
|
||||
uint32_t height;
|
||||
/** Pixel format of the image. */
|
||||
GhosttyKittyImageFormat format;
|
||||
/** Compression of the image. */
|
||||
GhosttyKittyImageCompression compression;
|
||||
/** Borrowed pointer to the raw pixel data. */
|
||||
const uint8_t* data_ptr;
|
||||
/** Length of the raw pixel data in bytes. */
|
||||
size_t data_len;
|
||||
} GhosttyKittyGraphicsImageInfo;
|
||||
|
||||
/**
|
||||
* All placement metadata in a single sized struct.
|
||||
*
|
||||
* Returned by ghostty_kitty_graphics_placement_get() with
|
||||
* GHOSTTY_KITTY_GRAPHICS_PLACEMENT_DATA_INFO. This is an optimization
|
||||
* over querying each field individually, particularly useful in
|
||||
* environments with high per-call overhead such as FFI or Cgo.
|
||||
*
|
||||
* This struct uses the sized-struct ABI pattern. Initialize with
|
||||
* GHOSTTY_INIT_SIZED(GhosttyKittyGraphicsPlacementInfo).
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
typedef struct {
|
||||
/** Size of this struct in bytes. Must be set to sizeof(GhosttyKittyGraphicsPlacementInfo). */
|
||||
size_t size;
|
||||
/** The image ID this placement belongs to. */
|
||||
uint32_t image_id;
|
||||
/** The placement ID. */
|
||||
uint32_t placement_id;
|
||||
/** Whether this is a virtual placement (unicode placeholder). */
|
||||
bool is_virtual;
|
||||
/** Pixel offset from the left edge of the cell. */
|
||||
uint32_t x_offset;
|
||||
/** Pixel offset from the top edge of the cell. */
|
||||
uint32_t y_offset;
|
||||
/** Source rectangle x origin in pixels. */
|
||||
uint32_t source_x;
|
||||
/** Source rectangle y origin in pixels. */
|
||||
uint32_t source_y;
|
||||
/** Source rectangle width in pixels (0 = full image width). */
|
||||
uint32_t source_width;
|
||||
/** Source rectangle height in pixels (0 = full image height). */
|
||||
uint32_t source_height;
|
||||
/** Number of columns this placement occupies. */
|
||||
uint32_t columns;
|
||||
/** Number of rows this placement occupies. */
|
||||
uint32_t rows;
|
||||
/** Z-index for this placement. */
|
||||
int32_t z;
|
||||
} GhosttyKittyGraphicsPlacementInfo;
|
||||
|
||||
/**
|
||||
* Combined rendering geometry for a placement in a single sized struct.
|
||||
*
|
||||
@@ -542,6 +444,40 @@ GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get(
|
||||
GhosttyKittyGraphicsImageData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a Kitty graphics image in a single call.
|
||||
*
|
||||
* This is an optimization over calling ghostty_kitty_graphics_image_get()
|
||||
* repeatedly, particularly useful in environments with high per-call
|
||||
* overhead such as FFI or Cgo.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
* The type of each values[i] pointer must match the output type
|
||||
* documented for keys[i].
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param image The image handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_image_get_multi(
|
||||
GhosttyKittyGraphicsImage image,
|
||||
size_t count,
|
||||
const GhosttyKittyGraphicsImageData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Create a new placement iterator instance.
|
||||
*
|
||||
@@ -627,6 +563,40 @@ GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get(
|
||||
GhosttyKittyGraphicsPlacementData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from the current placement in a single call.
|
||||
*
|
||||
* This is an optimization over calling ghostty_kitty_graphics_placement_get()
|
||||
* repeatedly, particularly useful in environments with high per-call
|
||||
* overhead such as FFI or Cgo.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
* The type of each values[i] pointer must match the output type
|
||||
* documented for keys[i].
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup kitty_graphics
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_kitty_graphics_placement_get_multi(
|
||||
GhosttyKittyGraphicsPlacementIterator iterator,
|
||||
size_t count,
|
||||
const GhosttyKittyGraphicsPlacementData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Compute the grid rectangle occupied by the current placement.
|
||||
*
|
||||
|
||||
@@ -331,8 +331,36 @@ GHOSTTY_API GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
|
||||
* @ingroup render
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_render_state_get(GhosttyRenderState state,
|
||||
GhosttyRenderStateData data,
|
||||
void* out);
|
||||
GhosttyRenderStateData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a render state in a single call.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_render_state_get_multi(
|
||||
GhosttyRenderState state,
|
||||
size_t count,
|
||||
const GhosttyRenderStateData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Set an option on a render state.
|
||||
@@ -433,6 +461,34 @@ GHOSTTY_API GhosttyResult ghostty_render_state_row_get(
|
||||
GhosttyRenderStateRowData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from the current row in a single call.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param iterator The iterator handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_render_state_row_get_multi(
|
||||
GhosttyRenderStateRowIterator iterator,
|
||||
size_t count,
|
||||
const GhosttyRenderStateRowData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Set an option on the current row in a render-state row iterator.
|
||||
*
|
||||
@@ -571,6 +627,34 @@ GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get(
|
||||
GhosttyRenderStateRowCellsData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from the current cell in a single call.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param cells The row cells handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_render_state_row_cells_get_multi(
|
||||
GhosttyRenderStateRowCells cells,
|
||||
size_t count,
|
||||
const GhosttyRenderStateRowCellsData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Free a row cells instance.
|
||||
*
|
||||
|
||||
@@ -314,8 +314,35 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||
* @ingroup screen
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_cell_get(GhosttyCell cell,
|
||||
GhosttyCellData data,
|
||||
void *out);
|
||||
GhosttyCellData data,
|
||||
void *out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a cell in a single call.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param cell The cell value
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup screen
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_cell_get_multi(GhosttyCell cell,
|
||||
size_t count,
|
||||
const GhosttyCellData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Get data from a row.
|
||||
@@ -334,8 +361,35 @@ GHOSTTY_API GhosttyResult ghostty_cell_get(GhosttyCell cell,
|
||||
* @ingroup screen
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_row_get(GhosttyRow row,
|
||||
GhosttyRowData data,
|
||||
void *out);
|
||||
GhosttyRowData data,
|
||||
void *out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a row in a single call.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param row The row value
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup screen
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_row_get_multi(GhosttyRow row,
|
||||
size_t count,
|
||||
const GhosttyRowData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -1038,6 +1038,39 @@ GHOSTTY_API GhosttyResult ghostty_terminal_get(GhosttyTerminal terminal,
|
||||
GhosttyTerminalData data,
|
||||
void *out);
|
||||
|
||||
/**
|
||||
* Get multiple data fields from a terminal in a single call.
|
||||
*
|
||||
* This is an optimization over calling ghostty_terminal_get()
|
||||
* repeatedly, particularly useful in environments with high per-call
|
||||
* overhead such as FFI or Cgo.
|
||||
*
|
||||
* Each element in the keys array specifies a data kind, and the
|
||||
* corresponding element in the values array receives the result.
|
||||
* The type of each values[i] pointer must match the output type
|
||||
* documented for keys[i].
|
||||
*
|
||||
* Processing stops at the first error; on success out_written
|
||||
* is set to count, on error it is set to the index of the
|
||||
* failing key (i.e. the number of values successfully written).
|
||||
*
|
||||
* @param terminal The terminal handle (may be NULL)
|
||||
* @param count Number of key/value pairs
|
||||
* @param keys Array of data kinds to query
|
||||
* @param values Array of output pointers (types must match each key's
|
||||
* documented output type)
|
||||
* @param[out] out_written On return, receives the number of values
|
||||
* successfully written (may be NULL)
|
||||
* @return GHOSTTY_SUCCESS if all queries succeed
|
||||
*
|
||||
* @ingroup terminal
|
||||
*/
|
||||
GHOSTTY_API GhosttyResult ghostty_terminal_get_multi(GhosttyTerminal terminal,
|
||||
size_t count,
|
||||
const GhosttyTerminalData* keys,
|
||||
void** values,
|
||||
size_t* out_written);
|
||||
|
||||
/**
|
||||
* Resolve a point in the terminal grid to a grid reference.
|
||||
*
|
||||
|
||||
@@ -192,7 +192,9 @@ comptime {
|
||||
@export(&c.sys_log_stderr, .{ .name = "ghostty_sys_log_stderr" });
|
||||
@export(&c.sys_set, .{ .name = "ghostty_sys_set" });
|
||||
@export(&c.cell_get, .{ .name = "ghostty_cell_get" });
|
||||
@export(&c.cell_get_multi, .{ .name = "ghostty_cell_get_multi" });
|
||||
@export(&c.row_get, .{ .name = "ghostty_row_get" });
|
||||
@export(&c.row_get_multi, .{ .name = "ghostty_row_get_multi" });
|
||||
@export(&c.color_rgb_get, .{ .name = "ghostty_color_rgb_get" });
|
||||
@export(&c.sgr_new, .{ .name = "ghostty_sgr_new" });
|
||||
@export(&c.sgr_free, .{ .name = "ghostty_sgr_free" });
|
||||
@@ -210,17 +212,20 @@ comptime {
|
||||
@export(&c.render_state_new, .{ .name = "ghostty_render_state_new" });
|
||||
@export(&c.render_state_update, .{ .name = "ghostty_render_state_update" });
|
||||
@export(&c.render_state_get, .{ .name = "ghostty_render_state_get" });
|
||||
@export(&c.render_state_get_multi, .{ .name = "ghostty_render_state_get_multi" });
|
||||
@export(&c.render_state_set, .{ .name = "ghostty_render_state_set" });
|
||||
@export(&c.render_state_colors_get, .{ .name = "ghostty_render_state_colors_get" });
|
||||
@export(&c.render_state_row_iterator_new, .{ .name = "ghostty_render_state_row_iterator_new" });
|
||||
@export(&c.render_state_row_iterator_next, .{ .name = "ghostty_render_state_row_iterator_next" });
|
||||
@export(&c.render_state_row_get, .{ .name = "ghostty_render_state_row_get" });
|
||||
@export(&c.render_state_row_get_multi, .{ .name = "ghostty_render_state_row_get_multi" });
|
||||
@export(&c.render_state_row_set, .{ .name = "ghostty_render_state_row_set" });
|
||||
@export(&c.render_state_row_iterator_free, .{ .name = "ghostty_render_state_row_iterator_free" });
|
||||
@export(&c.render_state_row_cells_new, .{ .name = "ghostty_render_state_row_cells_new" });
|
||||
@export(&c.render_state_row_cells_next, .{ .name = "ghostty_render_state_row_cells_next" });
|
||||
@export(&c.render_state_row_cells_select, .{ .name = "ghostty_render_state_row_cells_select" });
|
||||
@export(&c.render_state_row_cells_get, .{ .name = "ghostty_render_state_row_cells_get" });
|
||||
@export(&c.render_state_row_cells_get_multi, .{ .name = "ghostty_render_state_row_cells_get_multi" });
|
||||
@export(&c.render_state_row_cells_free, .{ .name = "ghostty_render_state_row_cells_free" });
|
||||
@export(&c.render_state_free, .{ .name = "ghostty_render_state_free" });
|
||||
@export(&c.terminal_new, .{ .name = "ghostty_terminal_new" });
|
||||
@@ -233,16 +238,19 @@ comptime {
|
||||
@export(&c.terminal_mode_get, .{ .name = "ghostty_terminal_mode_get" });
|
||||
@export(&c.terminal_mode_set, .{ .name = "ghostty_terminal_mode_set" });
|
||||
@export(&c.terminal_get, .{ .name = "ghostty_terminal_get" });
|
||||
@export(&c.terminal_get_multi, .{ .name = "ghostty_terminal_get_multi" });
|
||||
@export(&c.terminal_grid_ref, .{ .name = "ghostty_terminal_grid_ref" });
|
||||
@export(&c.terminal_point_from_grid_ref, .{ .name = "ghostty_terminal_point_from_grid_ref" });
|
||||
@export(&c.kitty_graphics_get, .{ .name = "ghostty_kitty_graphics_get" });
|
||||
@export(&c.kitty_graphics_image, .{ .name = "ghostty_kitty_graphics_image" });
|
||||
@export(&c.kitty_graphics_image_get, .{ .name = "ghostty_kitty_graphics_image_get" });
|
||||
@export(&c.kitty_graphics_image_get_multi, .{ .name = "ghostty_kitty_graphics_image_get_multi" });
|
||||
@export(&c.kitty_graphics_placement_iterator_new, .{ .name = "ghostty_kitty_graphics_placement_iterator_new" });
|
||||
@export(&c.kitty_graphics_placement_iterator_free, .{ .name = "ghostty_kitty_graphics_placement_iterator_free" });
|
||||
@export(&c.kitty_graphics_placement_iterator_set, .{ .name = "ghostty_kitty_graphics_placement_iterator_set" });
|
||||
@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_get_multi, .{ .name = "ghostty_kitty_graphics_placement_get_multi" });
|
||||
@export(&c.kitty_graphics_placement_rect, .{ .name = "ghostty_kitty_graphics_placement_rect" });
|
||||
@export(&c.kitty_graphics_placement_pixel_size, .{ .name = "ghostty_kitty_graphics_placement_pixel_size" });
|
||||
@export(&c.kitty_graphics_placement_grid_size, .{ .name = "ghostty_kitty_graphics_placement_grid_size" });
|
||||
|
||||
@@ -120,6 +120,27 @@ pub fn get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_multi(
|
||||
cell_: CCell,
|
||||
count: usize,
|
||||
keys: ?[*]const CellData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = get(cell_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn getTyped(
|
||||
cell_: CCell,
|
||||
comptime data: CellData,
|
||||
@@ -176,3 +197,42 @@ test "get wide" {
|
||||
try testing.expectEqual(Result.success, get(cell, .wide, @ptrCast(&w)));
|
||||
try testing.expectEqual(Wide.wide, w);
|
||||
}
|
||||
|
||||
test "get_multi success" {
|
||||
const cell: CCell = @bitCast(Cell.init('B'));
|
||||
var cp: u32 = 0;
|
||||
var has_text: bool = false;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]CellData{ .codepoint, .has_text };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&cp), @ptrCast(&has_text) };
|
||||
try testing.expectEqual(Result.success, get_multi(cell, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expectEqual(@as(u32, 'B'), cp);
|
||||
try testing.expect(has_text);
|
||||
}
|
||||
|
||||
test "get_multi error sets out_written" {
|
||||
const cell: CCell = @bitCast(Cell.init('C'));
|
||||
var cp: u32 = 0;
|
||||
var written: usize = 99;
|
||||
|
||||
const keys = [_]CellData{ .codepoint, .invalid };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&cp), @ptrCast(&cp) };
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(cell, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(1, written);
|
||||
try testing.expectEqual(@as(u32, 'C'), cp);
|
||||
}
|
||||
|
||||
test "get_multi null keys returns invalid_value" {
|
||||
const cell: CCell = @bitCast(Cell.init('A'));
|
||||
var cp: u32 = 0;
|
||||
var values = [_]?*anyopaque{@ptrCast(&cp)};
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(cell, 1, null, &values, null));
|
||||
}
|
||||
|
||||
test "get_multi null values returns invalid_value" {
|
||||
const cell: CCell = @bitCast(Cell.init('A'));
|
||||
const keys = [_]CellData{.codepoint};
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(cell, 1, &keys, null, null));
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ pub const PlacementData = enum(c_int) {
|
||||
columns = 10,
|
||||
rows = 11,
|
||||
z = 12,
|
||||
info = 13,
|
||||
|
||||
pub fn OutType(comptime self: PlacementData) type {
|
||||
return switch (self) {
|
||||
@@ -93,7 +92,6 @@ pub const PlacementData = enum(c_int) {
|
||||
.rows,
|
||||
=> u32,
|
||||
.z => i32,
|
||||
.info => PlacementInfo,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -180,7 +178,6 @@ pub const ImageData = enum(c_int) {
|
||||
compression = 6,
|
||||
data_ptr = 7,
|
||||
data_len = 8,
|
||||
info = 9,
|
||||
|
||||
pub fn OutType(comptime self: ImageData) type {
|
||||
return switch (self) {
|
||||
@@ -190,7 +187,6 @@ pub const ImageData = enum(c_int) {
|
||||
.compression => ImageCompression,
|
||||
.data_ptr => [*]const u8,
|
||||
.data_len => usize,
|
||||
.info => ImageInfo,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -222,6 +218,29 @@ pub fn image_get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn image_get_multi(
|
||||
image_: ImageHandle,
|
||||
count: usize,
|
||||
keys: ?[*]const ImageData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
if (comptime !build_options.kitty_graphics) return .no_value;
|
||||
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = image_get(image_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn imageGetTyped(
|
||||
image_: ImageHandle,
|
||||
comptime data: ImageData,
|
||||
@@ -239,17 +258,6 @@ fn imageGetTyped(
|
||||
.compression => out.* = image.compression,
|
||||
.data_ptr => out.* = image.data.ptr,
|
||||
.data_len => out.* = image.data.len,
|
||||
.info => {
|
||||
if (out.size < @sizeOf(ImageInfo)) return .invalid_value;
|
||||
out.id = image.id;
|
||||
out.number = image.number;
|
||||
out.width = image.width;
|
||||
out.height = image.height;
|
||||
out.format = image.format;
|
||||
out.compression = image.compression;
|
||||
out.data_ptr = image.data.ptr;
|
||||
out.data_len = image.data.len;
|
||||
},
|
||||
}
|
||||
|
||||
return .success;
|
||||
@@ -343,6 +351,29 @@ pub fn placement_get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn placement_get_multi(
|
||||
iter_: PlacementIterator,
|
||||
count: usize,
|
||||
keys: ?[*]const PlacementData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
if (comptime !build_options.kitty_graphics) return .no_value;
|
||||
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = placement_get(iter_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn placementGetTyped(
|
||||
iter_: PlacementIterator,
|
||||
comptime data: PlacementData,
|
||||
@@ -368,21 +399,6 @@ fn placementGetTyped(
|
||||
.columns => out.* = val.columns,
|
||||
.rows => out.* = val.rows,
|
||||
.z => out.* = val.z,
|
||||
.info => {
|
||||
if (out.size < @sizeOf(PlacementInfo)) return .invalid_value;
|
||||
out.image_id = key.image_id;
|
||||
out.placement_id = key.placement_id.id;
|
||||
out.is_virtual = val.location == .virtual;
|
||||
out.x_offset = val.x_offset;
|
||||
out.y_offset = val.y_offset;
|
||||
out.source_x = val.source_x;
|
||||
out.source_y = val.source_y;
|
||||
out.source_width = val.source_width;
|
||||
out.source_height = val.source_height;
|
||||
out.columns = val.columns;
|
||||
out.rows = val.rows;
|
||||
out.z = val.z;
|
||||
},
|
||||
}
|
||||
|
||||
return .success;
|
||||
@@ -508,36 +524,6 @@ pub fn placement_source_rect(
|
||||
return .success;
|
||||
}
|
||||
|
||||
/// C: GhosttyKittyGraphicsImageInfo
|
||||
pub const ImageInfo = extern struct {
|
||||
size: usize = @sizeOf(ImageInfo),
|
||||
id: u32 = 0,
|
||||
number: u32 = 0,
|
||||
width: u32 = 0,
|
||||
height: u32 = 0,
|
||||
format: ImageFormat = .rgb,
|
||||
compression: ImageCompression = .none,
|
||||
data_ptr: [*]const u8 = @as([*]const u8, @ptrFromInt(1)),
|
||||
data_len: usize = 0,
|
||||
};
|
||||
|
||||
/// C: GhosttyKittyGraphicsPlacementInfo
|
||||
pub const PlacementInfo = extern struct {
|
||||
size: usize = @sizeOf(PlacementInfo),
|
||||
image_id: u32 = 0,
|
||||
placement_id: u32 = 0,
|
||||
is_virtual: bool = false,
|
||||
x_offset: u32 = 0,
|
||||
y_offset: u32 = 0,
|
||||
source_x: u32 = 0,
|
||||
source_y: u32 = 0,
|
||||
source_width: u32 = 0,
|
||||
source_height: u32 = 0,
|
||||
columns: u32 = 0,
|
||||
rows: u32 = 0,
|
||||
z: i32 = 0,
|
||||
};
|
||||
|
||||
/// C: GhosttyKittyGraphicsPlacementRenderInfo
|
||||
pub const PlacementRenderInfo = extern struct {
|
||||
size: usize = @sizeOf(PlacementRenderInfo),
|
||||
@@ -1523,83 +1509,6 @@ test "image_get on null returns invalid_value" {
|
||||
try testing.expectEqual(Result.invalid_value, image_get(null, .id, @ptrCast(&id)));
|
||||
}
|
||||
|
||||
test "image_get info returns all fields" {
|
||||
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);
|
||||
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
|
||||
|
||||
const cmd = "\x1b_Ga=T,t=d,f=24,i=1,p=1,s=1,v=2;////////\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 info: ImageInfo = .{};
|
||||
try testing.expectEqual(Result.success, image_get(img, .info, @ptrCast(&info)));
|
||||
try testing.expectEqual(1, info.id);
|
||||
try testing.expectEqual(1, info.width);
|
||||
try testing.expectEqual(2, info.height);
|
||||
try testing.expectEqual(ImageFormat.rgb, info.format);
|
||||
try testing.expectEqual(ImageCompression.none, info.compression);
|
||||
try testing.expectEqual(6, info.data_len);
|
||||
}
|
||||
|
||||
test "image_get info null returns invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var info: ImageInfo = .{};
|
||||
try testing.expectEqual(Result.invalid_value, image_get(null, .info, @ptrCast(&info)));
|
||||
}
|
||||
|
||||
test "placement_get info returns all fields" {
|
||||
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);
|
||||
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
|
||||
|
||||
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)));
|
||||
|
||||
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 info: PlacementInfo = .{};
|
||||
try testing.expectEqual(Result.success, placement_get(iter, .info, @ptrCast(&info)));
|
||||
try testing.expectEqual(1, info.image_id);
|
||||
try testing.expectEqual(1, info.placement_id);
|
||||
try testing.expect(!info.is_virtual);
|
||||
try testing.expectEqual(10, info.columns);
|
||||
try testing.expectEqual(1, info.rows);
|
||||
}
|
||||
|
||||
test "placement_get info null returns invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var info: PlacementInfo = .{};
|
||||
try testing.expectEqual(Result.invalid_value, placement_get(null, .info, @ptrCast(&info)));
|
||||
}
|
||||
|
||||
test "placement_render_info returns all fields" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
@@ -1687,3 +1596,115 @@ test "placement_render_info null returns invalid_value" {
|
||||
var ri: PlacementRenderInfo = .{};
|
||||
try testing.expectEqual(Result.invalid_value, placement_render_info(null, null, null, &ri));
|
||||
}
|
||||
|
||||
test "image_get_multi success" {
|
||||
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);
|
||||
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
|
||||
|
||||
const cmd = "\x1b_Ga=T,t=d,f=24,i=1,p=1,s=1,v=2;////////\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 id: u32 = 0;
|
||||
var width: u32 = 0;
|
||||
var height: u32 = 0;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]ImageData{ .id, .width, .height };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&id), @ptrCast(&width), @ptrCast(&height) };
|
||||
try testing.expectEqual(Result.success, image_get_multi(img, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expectEqual(1, id);
|
||||
try testing.expectEqual(1, width);
|
||||
try testing.expectEqual(2, height);
|
||||
}
|
||||
|
||||
test "image_get_multi error sets out_written" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var id: u32 = 0;
|
||||
var written: usize = 99;
|
||||
|
||||
const keys = [_]ImageData{ .id, .invalid };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&id), @ptrCast(&id) };
|
||||
try testing.expectEqual(Result.invalid_value, image_get_multi(null, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(0, written);
|
||||
}
|
||||
|
||||
test "image_get_multi null keys returns invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var id: u32 = 0;
|
||||
var values = [_]?*anyopaque{@ptrCast(&id)};
|
||||
try testing.expectEqual(Result.invalid_value, image_get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
test "placement_get_multi success" {
|
||||
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);
|
||||
try testing.expectEqual(Result.success, terminal_c.resize(t, 80, 24, 10, 20));
|
||||
|
||||
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)));
|
||||
|
||||
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 image_id: u32 = 0;
|
||||
var columns: u32 = 0;
|
||||
var z: i32 = 99;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]PlacementData{ .image_id, .columns, .z };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&image_id), @ptrCast(&columns), @ptrCast(&z) };
|
||||
try testing.expectEqual(Result.success, placement_get_multi(iter, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expectEqual(1, image_id);
|
||||
try testing.expectEqual(10, columns);
|
||||
try testing.expectEqual(0, z);
|
||||
}
|
||||
|
||||
test "placement_get_multi error sets out_written" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var id: u32 = 0;
|
||||
var written: usize = 99;
|
||||
|
||||
const keys = [_]PlacementData{ .image_id, .invalid };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&id), @ptrCast(&id) };
|
||||
try testing.expectEqual(Result.invalid_value, placement_get_multi(null, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(0, written);
|
||||
}
|
||||
|
||||
test "placement_get_multi null keys returns invalid_value" {
|
||||
if (comptime !build_options.kitty_graphics) return error.SkipZigTest;
|
||||
|
||||
var id: u32 = 0;
|
||||
var values = [_]?*anyopaque{@ptrCast(&id)};
|
||||
try testing.expectEqual(Result.invalid_value, placement_get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@ pub const kitty_graphics = @import("kitty_graphics.zig");
|
||||
pub const kitty_graphics_get = kitty_graphics.get;
|
||||
pub const kitty_graphics_image = kitty_graphics.image_get_handle;
|
||||
pub const kitty_graphics_image_get = kitty_graphics.image_get;
|
||||
pub const kitty_graphics_image_get_multi = kitty_graphics.image_get_multi;
|
||||
pub const kitty_graphics_placement_iterator_new = kitty_graphics.placement_iterator_new;
|
||||
pub const kitty_graphics_placement_iterator_free = kitty_graphics.placement_iterator_free;
|
||||
pub const kitty_graphics_placement_iterator_set = kitty_graphics.placement_iterator_set;
|
||||
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_get_multi = kitty_graphics.placement_get_multi;
|
||||
pub const kitty_graphics_placement_rect = kitty_graphics.placement_rect;
|
||||
pub const kitty_graphics_placement_pixel_size = kitty_graphics.placement_pixel_size;
|
||||
pub const kitty_graphics_placement_grid_size = kitty_graphics.placement_grid_size;
|
||||
@@ -66,17 +68,20 @@ pub const render_state_new = render.new;
|
||||
pub const render_state_free = render.free;
|
||||
pub const render_state_update = render.update;
|
||||
pub const render_state_get = render.get;
|
||||
pub const render_state_get_multi = render.get_multi;
|
||||
pub const render_state_set = render.set;
|
||||
pub const render_state_colors_get = render.colors_get;
|
||||
pub const render_state_row_iterator_new = render.row_iterator_new;
|
||||
pub const render_state_row_iterator_next = render.row_iterator_next;
|
||||
pub const render_state_row_get = render.row_get;
|
||||
pub const render_state_row_get_multi = render.row_get_multi;
|
||||
pub const render_state_row_set = render.row_set;
|
||||
pub const render_state_row_iterator_free = render.row_iterator_free;
|
||||
pub const render_state_row_cells_new = render.row_cells_new;
|
||||
pub const render_state_row_cells_next = render.row_cells_next;
|
||||
pub const render_state_row_cells_select = render.row_cells_select;
|
||||
pub const render_state_row_cells_get = render.row_cells_get;
|
||||
pub const render_state_row_cells_get_multi = render.row_cells_get_multi;
|
||||
pub const render_state_row_cells_free = render.row_cells_free;
|
||||
|
||||
pub const sgr_new = sgr.new;
|
||||
@@ -142,8 +147,10 @@ pub const alloc_free = allocator.free;
|
||||
pub const size_report_encode = size_report.encode;
|
||||
|
||||
pub const cell_get = cell.get;
|
||||
pub const cell_get_multi = cell.get_multi;
|
||||
|
||||
pub const row_get = row.get;
|
||||
pub const row_get_multi = row.get_multi;
|
||||
|
||||
pub const style_default = style.default_style;
|
||||
pub const style_is_default = style.style_is_default;
|
||||
@@ -161,6 +168,7 @@ pub const terminal_scroll_viewport = terminal.scroll_viewport;
|
||||
pub const terminal_mode_get = terminal.mode_get;
|
||||
pub const terminal_mode_set = terminal.mode_set;
|
||||
pub const terminal_get = terminal.get;
|
||||
pub const terminal_get_multi = terminal.get_multi;
|
||||
pub const terminal_grid_ref = terminal.grid_ref;
|
||||
pub const terminal_point_from_grid_ref = terminal.point_from_grid_ref;
|
||||
|
||||
|
||||
@@ -201,6 +201,27 @@ pub fn get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_multi(
|
||||
state_: RenderState,
|
||||
count: usize,
|
||||
keys: ?[*]const Data,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = get(state_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn getTyped(
|
||||
state_: RenderState,
|
||||
comptime data: Data,
|
||||
@@ -468,6 +489,27 @@ pub fn row_cells_get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn row_cells_get_multi(
|
||||
cells_: RowCells,
|
||||
count: usize,
|
||||
keys: ?[*]const RowCellsData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = row_cells_get(cells_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn rowCellsGetTyped(
|
||||
cells_: RowCells,
|
||||
comptime data: RowCellsData,
|
||||
@@ -568,6 +610,27 @@ pub fn row_get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn row_get_multi(
|
||||
iterator_: RowIterator,
|
||||
count: usize,
|
||||
keys: ?[*]const RowData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = row_get(iterator_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn rowGetTyped(
|
||||
iterator_: RowIterator,
|
||||
comptime data: RowData,
|
||||
@@ -1380,3 +1443,137 @@ test "render: colors get supports truncated sized struct" {
|
||||
try testing.expectEqual(state_colors.palette[1].cval(), colors.palette[1]);
|
||||
try testing.expectEqual(sentinel, colors.palette[2]);
|
||||
}
|
||||
|
||||
test "render: get_multi success" {
|
||||
var terminal: terminal_c.Terminal = null;
|
||||
try testing.expectEqual(Result.success, terminal_c.new(
|
||||
&lib.alloc.test_allocator,
|
||||
&terminal,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 10_000 },
|
||||
));
|
||||
defer terminal_c.free(terminal);
|
||||
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib.alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
try testing.expectEqual(Result.success, update(state, terminal));
|
||||
|
||||
var cols: u16 = 0;
|
||||
var rows: u16 = 0;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]Data{ .cols, .rows };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&cols), @ptrCast(&rows) };
|
||||
try testing.expectEqual(Result.success, get_multi(state, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expectEqual(80, cols);
|
||||
try testing.expectEqual(24, rows);
|
||||
}
|
||||
|
||||
test "render: get_multi null returns invalid_value" {
|
||||
var cols: u16 = 0;
|
||||
var values = [_]?*anyopaque{@ptrCast(&cols)};
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
test "render: row_get_multi success" {
|
||||
var terminal: terminal_c.Terminal = null;
|
||||
try testing.expectEqual(Result.success, terminal_c.new(
|
||||
&lib.alloc.test_allocator,
|
||||
&terminal,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 10_000 },
|
||||
));
|
||||
defer terminal_c.free(terminal);
|
||||
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib.alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
try testing.expectEqual(Result.success, update(state, terminal));
|
||||
|
||||
var it: RowIterator = null;
|
||||
try testing.expectEqual(Result.success, row_iterator_new(
|
||||
&lib.alloc.test_allocator,
|
||||
&it,
|
||||
));
|
||||
defer row_iterator_free(it);
|
||||
|
||||
try testing.expectEqual(Result.success, get(state, .row_iterator, @ptrCast(&it)));
|
||||
try testing.expect(row_iterator_next(it));
|
||||
|
||||
var dirty: bool = true;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]RowData{.dirty};
|
||||
var values = [_]?*anyopaque{@ptrCast(&dirty)};
|
||||
try testing.expectEqual(Result.success, row_get_multi(it, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
}
|
||||
|
||||
test "render: row_get_multi null returns invalid_value" {
|
||||
var dirty: bool = false;
|
||||
var values = [_]?*anyopaque{@ptrCast(&dirty)};
|
||||
try testing.expectEqual(Result.invalid_value, row_get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
test "render: row_cells_get_multi success" {
|
||||
var terminal: terminal_c.Terminal = null;
|
||||
try testing.expectEqual(Result.success, terminal_c.new(
|
||||
&lib.alloc.test_allocator,
|
||||
&terminal,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 10_000 },
|
||||
));
|
||||
defer terminal_c.free(terminal);
|
||||
|
||||
terminal_c.vt_write(terminal, "A", 1);
|
||||
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib.alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
try testing.expectEqual(Result.success, update(state, terminal));
|
||||
|
||||
var it: RowIterator = null;
|
||||
try testing.expectEqual(Result.success, row_iterator_new(
|
||||
&lib.alloc.test_allocator,
|
||||
&it,
|
||||
));
|
||||
defer row_iterator_free(it);
|
||||
|
||||
try testing.expectEqual(Result.success, get(state, .row_iterator, @ptrCast(&it)));
|
||||
try testing.expect(row_iterator_next(it));
|
||||
|
||||
var cells: RowCells = null;
|
||||
try testing.expectEqual(Result.success, row_cells_new(
|
||||
&lib.alloc.test_allocator,
|
||||
&cells,
|
||||
));
|
||||
defer row_cells_free(cells);
|
||||
|
||||
try testing.expectEqual(Result.success, row_get(it, .cells, @ptrCast(&cells)));
|
||||
try testing.expect(row_cells_next(cells));
|
||||
|
||||
var raw: row.CRow = undefined;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]RowCellsData{.raw};
|
||||
var values = [_]?*anyopaque{@ptrCast(&raw)};
|
||||
try testing.expectEqual(Result.success, row_cells_get_multi(cells, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
}
|
||||
|
||||
test "render: row_cells_get_multi null returns invalid_value" {
|
||||
var raw: row.CRow = undefined;
|
||||
var values = [_]?*anyopaque{@ptrCast(&raw)};
|
||||
try testing.expectEqual(Result.invalid_value, row_cells_get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
@@ -83,6 +83,27 @@ pub fn get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_multi(
|
||||
row_: CRow,
|
||||
count: usize,
|
||||
keys: ?[*]const RowData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = get(row_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn getTyped(
|
||||
row_: CRow,
|
||||
comptime data: RowData,
|
||||
@@ -130,3 +151,43 @@ test "get dirty" {
|
||||
try testing.expectEqual(Result.success, get(row, .dirty, @ptrCast(&dirty)));
|
||||
try testing.expect(dirty);
|
||||
}
|
||||
|
||||
test "get_multi success" {
|
||||
var zig_row: Row = @bitCast(@as(u64, 0));
|
||||
zig_row.wrap = true;
|
||||
zig_row.dirty = true;
|
||||
const row_val: CRow = @bitCast(zig_row);
|
||||
|
||||
var wrap: bool = false;
|
||||
var dirty: bool = false;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]RowData{ .wrap, .dirty };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&wrap), @ptrCast(&dirty) };
|
||||
try testing.expectEqual(Result.success, get_multi(row_val, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expect(wrap);
|
||||
try testing.expect(dirty);
|
||||
}
|
||||
|
||||
test "get_multi error sets out_written" {
|
||||
var zig_row: Row = @bitCast(@as(u64, 0));
|
||||
zig_row.wrap = true;
|
||||
const row_val: CRow = @bitCast(zig_row);
|
||||
|
||||
var wrap: bool = false;
|
||||
var written: usize = 99;
|
||||
|
||||
const keys = [_]RowData{ .wrap, .invalid };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&wrap), @ptrCast(&wrap) };
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(row_val, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(1, written);
|
||||
try testing.expect(wrap);
|
||||
}
|
||||
|
||||
test "get_multi null keys returns invalid_value" {
|
||||
const row_val: CRow = @bitCast(@as(u64, 0));
|
||||
var wrap: bool = false;
|
||||
var values = [_]?*anyopaque{@ptrCast(&wrap)};
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(row_val, 1, null, &values, null));
|
||||
}
|
||||
|
||||
@@ -612,6 +612,27 @@ pub fn get(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_multi(
|
||||
terminal_: Terminal,
|
||||
count: usize,
|
||||
keys: ?[*]const TerminalData,
|
||||
values: ?[*]?*anyopaque,
|
||||
out_written: ?*usize,
|
||||
) callconv(lib.calling_conv) Result {
|
||||
const k = keys orelse return .invalid_value;
|
||||
const v = values orelse return .invalid_value;
|
||||
|
||||
for (0..count) |i| {
|
||||
const result = get(terminal_, k[i], v[i]);
|
||||
if (result != .success) {
|
||||
if (out_written) |w| w.* = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (out_written) |w| w.* = count;
|
||||
return .success;
|
||||
}
|
||||
|
||||
fn getTyped(
|
||||
terminal_: Terminal,
|
||||
comptime data: TerminalData,
|
||||
@@ -2537,3 +2558,49 @@ test "set color sets dirty flag" {
|
||||
try testing.expectEqual(Result.success, set(t, .color_foreground, @ptrCast(&fg)));
|
||||
try testing.expect(zt.flags.dirty.palette);
|
||||
}
|
||||
|
||||
test "get_multi success" {
|
||||
var t: Terminal = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib.alloc.test_allocator,
|
||||
&t,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 0 },
|
||||
));
|
||||
defer free(t);
|
||||
|
||||
var cols: u16 = 0;
|
||||
var rows: u16 = 0;
|
||||
var written: usize = 0;
|
||||
|
||||
const keys = [_]TerminalData{ .cols, .rows };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&cols), @ptrCast(&rows) };
|
||||
try testing.expectEqual(Result.success, get_multi(t, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(keys.len, written);
|
||||
try testing.expectEqual(80, cols);
|
||||
try testing.expectEqual(24, rows);
|
||||
}
|
||||
|
||||
test "get_multi error sets out_written" {
|
||||
var t: Terminal = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib.alloc.test_allocator,
|
||||
&t,
|
||||
.{ .cols = 80, .rows = 24, .max_scrollback = 0 },
|
||||
));
|
||||
defer free(t);
|
||||
|
||||
var cols: u16 = 0;
|
||||
var written: usize = 99;
|
||||
|
||||
const keys = [_]TerminalData{ .cols, .invalid };
|
||||
var values = [_]?*anyopaque{ @ptrCast(&cols), @ptrCast(&cols) };
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(t, keys.len, &keys, &values, &written));
|
||||
try testing.expectEqual(1, written);
|
||||
try testing.expectEqual(80, cols);
|
||||
}
|
||||
|
||||
test "get_multi null keys returns invalid_value" {
|
||||
var cols: u16 = 0;
|
||||
var values = [_]?*anyopaque{@ptrCast(&cols)};
|
||||
try testing.expectEqual(Result.invalid_value, get_multi(null, 1, null, &values, null));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user