mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
vt: use get/set pattern for render state data access
Replace the individual ghostty_render_state_size_get, ghostty_render_state_dirty_get, and ghostty_render_state_dirty_set functions with generic ghostty_render_state_get and ghostty_render_state_set functions that use enum-dispatched data kinds and option kinds, following the same InType/OutType pattern used by the terminal and mouse encoder C APIs.
This commit is contained in:
@@ -95,6 +95,35 @@ typedef enum {
|
||||
GHOSTTY_RENDER_STATE_DIRTY_FULL = 2,
|
||||
} GhosttyRenderStateDirty;
|
||||
|
||||
/**
|
||||
* Queryable data kinds for ghostty_render_state_get().
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef enum {
|
||||
/** Invalid / sentinel value. */
|
||||
GHOSTTY_RENDER_STATE_DATA_INVALID = 0,
|
||||
|
||||
/** Viewport width in cells (uint16_t). */
|
||||
GHOSTTY_RENDER_STATE_DATA_COLS = 1,
|
||||
|
||||
/** Viewport height in cells (uint16_t). */
|
||||
GHOSTTY_RENDER_STATE_DATA_ROWS = 2,
|
||||
|
||||
/** Current dirty state (GhosttyRenderStateDirty). */
|
||||
GHOSTTY_RENDER_STATE_DATA_DIRTY = 3,
|
||||
} GhosttyRenderStateData;
|
||||
|
||||
/**
|
||||
* Settable options for ghostty_render_state_set().
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
typedef enum {
|
||||
/** Set dirty state (GhosttyRenderStateDirty). */
|
||||
GHOSTTY_RENDER_STATE_OPTION_DIRTY = 0,
|
||||
} GhosttyRenderStateOption;
|
||||
|
||||
/**
|
||||
* Render-state color information.
|
||||
*
|
||||
@@ -177,22 +206,41 @@ GhosttyResult ghostty_render_state_update(GhosttyRenderState state,
|
||||
GhosttyTerminal terminal);
|
||||
|
||||
/**
|
||||
* Get the current viewport size from a render state.
|
||||
* Get a value from a render state.
|
||||
*
|
||||
* The returned values are the render-state dimensions in cells. These
|
||||
* match the active viewport size from the most recent successful update.
|
||||
* The `out` pointer must point to a value of the type corresponding to the
|
||||
* requested data kind (see GhosttyRenderStateData).
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param[out] out_cols On success, receives the viewport width in cells
|
||||
* @param[out] out_rows On success, receives the viewport height in cells
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state`,
|
||||
* `out_cols`, or `out_rows` is NULL
|
||||
* @param data The data kind to query
|
||||
* @param[out] out Pointer to receive the queried value
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
|
||||
* NULL or `data` is not a recognized enum value
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_size_get(GhosttyRenderState state,
|
||||
uint16_t* out_cols,
|
||||
uint16_t* out_rows);
|
||||
GhosttyResult ghostty_render_state_get(GhosttyRenderState state,
|
||||
GhosttyRenderStateData data,
|
||||
void* out);
|
||||
|
||||
/**
|
||||
* Set an option on a render state.
|
||||
*
|
||||
* The `value` pointer must point to a value of the type corresponding to the
|
||||
* requested option kind (see GhosttyRenderStateOption).
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param option The option to set
|
||||
* @param[in] value Pointer to the value to set (NULL returns
|
||||
* GHOSTTY_INVALID_VALUE)
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` or
|
||||
* `value` is NULL
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_set(GhosttyRenderState state,
|
||||
GhosttyRenderStateOption option,
|
||||
const void* value);
|
||||
|
||||
/**
|
||||
* Get the current color information from a render state.
|
||||
@@ -212,34 +260,6 @@ GhosttyResult ghostty_render_state_size_get(GhosttyRenderState state,
|
||||
GhosttyResult ghostty_render_state_colors_get(GhosttyRenderState state,
|
||||
GhosttyRenderStateColors* out_colors);
|
||||
|
||||
/**
|
||||
* Get the current dirty state of a render state.
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param[out] out_dirty On success, receives the current dirty state
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
|
||||
* NULL
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_dirty_get(GhosttyRenderState state,
|
||||
GhosttyRenderStateDirty* out_dirty);
|
||||
|
||||
/**
|
||||
* Set the dirty state of a render state.
|
||||
*
|
||||
* This can be used by callers to clear dirty state after handling updates.
|
||||
*
|
||||
* @param state The render state handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||
* @param dirty The dirty state to set
|
||||
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if `state` is
|
||||
* NULL or `dirty` is not a recognized enum value
|
||||
*
|
||||
* @ingroup render
|
||||
*/
|
||||
GhosttyResult ghostty_render_state_dirty_set(GhosttyRenderState state,
|
||||
GhosttyRenderStateDirty dirty);
|
||||
|
||||
/**
|
||||
* Create a row iterator for a render state.
|
||||
*
|
||||
|
||||
@@ -189,10 +189,9 @@ comptime {
|
||||
@export(&c.formatter_free, .{ .name = "ghostty_formatter_free" });
|
||||
@export(&c.render_state_new, .{ .name = "ghostty_render_state_new" });
|
||||
@export(&c.render_state_update, .{ .name = "ghostty_render_state_update" });
|
||||
@export(&c.render_state_size_get, .{ .name = "ghostty_render_state_size_get" });
|
||||
@export(&c.render_state_get, .{ .name = "ghostty_render_state_get" });
|
||||
@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_dirty_get, .{ .name = "ghostty_render_state_dirty_get" });
|
||||
@export(&c.render_state_dirty_set, .{ .name = "ghostty_render_state_dirty_set" });
|
||||
@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_dirty_get, .{ .name = "ghostty_render_state_row_dirty_get" });
|
||||
|
||||
@@ -39,10 +39,9 @@ pub const formatter_free = formatter.free;
|
||||
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_size_get = render.size_get;
|
||||
pub const render_state_get = render.get;
|
||||
pub const render_state_set = render.set;
|
||||
pub const render_state_colors_get = render.colors_get;
|
||||
pub const render_state_dirty_get = render.dirty_get;
|
||||
pub const render_state_dirty_set = render.dirty_set;
|
||||
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_dirty_get = render.row_dirty_get;
|
||||
|
||||
@@ -12,6 +12,8 @@ const terminal_c = @import("terminal.zig");
|
||||
const renderpkg = @import("../render.zig");
|
||||
const Result = @import("result.zig").Result;
|
||||
|
||||
const log = std.log.scoped(.render_state_c);
|
||||
|
||||
const RenderStateWrapper = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
state: renderpkg.RenderState = .empty,
|
||||
@@ -38,6 +40,35 @@ pub const RowIterator = ?*RowIteratorWrapper;
|
||||
/// C: GhosttyRenderStateDirty
|
||||
pub const Dirty = renderpkg.RenderState.Dirty;
|
||||
|
||||
/// C: GhosttyRenderStateData
|
||||
pub const Data = enum(c_int) {
|
||||
invalid = 0,
|
||||
cols = 1,
|
||||
rows = 2,
|
||||
dirty = 3,
|
||||
|
||||
/// Output type expected for querying the data of the given kind.
|
||||
pub fn OutType(comptime self: Data) type {
|
||||
return switch (self) {
|
||||
.invalid => void,
|
||||
.cols, .rows => size.CellCountInt,
|
||||
.dirty => Dirty,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// C: GhosttyRenderStateOption
|
||||
pub const SetOption = enum(c_int) {
|
||||
dirty = 0,
|
||||
|
||||
/// Input type expected for setting the option.
|
||||
pub fn InType(comptime self: SetOption) type {
|
||||
return switch (self) {
|
||||
.dirty => Dirty,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// C: GhosttyRenderStateColors
|
||||
pub const Colors = extern struct {
|
||||
size: usize = @sizeOf(Colors),
|
||||
@@ -88,17 +119,74 @@ pub fn update(
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn size_get(
|
||||
pub fn get(
|
||||
state_: RenderState,
|
||||
out_cols_: ?*size.CellCountInt,
|
||||
out_rows_: ?*size.CellCountInt,
|
||||
data: Data,
|
||||
out: ?*anyopaque,
|
||||
) callconv(.c) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
const out_cols = out_cols_ orelse return .invalid_value;
|
||||
const out_rows = out_rows_ orelse return .invalid_value;
|
||||
if (comptime std.debug.runtime_safety) {
|
||||
_ = std.meta.intToEnum(Data, @intFromEnum(data)) catch {
|
||||
log.warn("render_state_get invalid data value={d}", .{@intFromEnum(data)});
|
||||
return .invalid_value;
|
||||
};
|
||||
}
|
||||
|
||||
return switch (data) {
|
||||
inline else => |comptime_data| getTyped(
|
||||
state_,
|
||||
comptime_data,
|
||||
@ptrCast(@alignCast(out)),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
fn getTyped(
|
||||
state_: RenderState,
|
||||
comptime data: Data,
|
||||
out: *data.OutType(),
|
||||
) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
switch (data) {
|
||||
.invalid => return .invalid_value,
|
||||
.cols => out.* = state.state.cols,
|
||||
.rows => out.* = state.state.rows,
|
||||
.dirty => out.* = state.state.dirty,
|
||||
}
|
||||
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn set(
|
||||
state_: RenderState,
|
||||
option: SetOption,
|
||||
value: ?*const anyopaque,
|
||||
) callconv(.c) Result {
|
||||
if (comptime std.debug.runtime_safety) {
|
||||
_ = std.meta.intToEnum(SetOption, @intFromEnum(option)) catch {
|
||||
log.warn("render_state_set invalid option value={d}", .{@intFromEnum(option)});
|
||||
return .invalid_value;
|
||||
};
|
||||
}
|
||||
|
||||
return switch (option) {
|
||||
inline else => |comptime_option| setTyped(
|
||||
state_,
|
||||
comptime_option,
|
||||
@ptrCast(@alignCast(value orelse return .invalid_value)),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
fn setTyped(
|
||||
state_: RenderState,
|
||||
comptime option: SetOption,
|
||||
value: *const option.InType(),
|
||||
) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
switch (option) {
|
||||
.dirty => state.state.dirty = value.*,
|
||||
}
|
||||
|
||||
out_cols.* = state.state.cols;
|
||||
out_rows.* = state.state.rows;
|
||||
return .success;
|
||||
}
|
||||
|
||||
@@ -164,25 +252,7 @@ pub fn colors_get(
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn dirty_get(
|
||||
state_: RenderState,
|
||||
out_dirty: *Dirty,
|
||||
) callconv(.c) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
out_dirty.* = state.state.dirty;
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn dirty_set(
|
||||
state_: RenderState,
|
||||
dirty_: c_int,
|
||||
) callconv(.c) Result {
|
||||
const state = state_ orelse return .invalid_value;
|
||||
const dirty = std.meta.intToEnum(Dirty, dirty_) catch
|
||||
return .invalid_value;
|
||||
state.state.dirty = dirty;
|
||||
return .success;
|
||||
}
|
||||
|
||||
pub fn row_iterator_new(
|
||||
alloc_: ?*const CAllocator,
|
||||
@@ -281,7 +351,12 @@ test "render: update invalid value" {
|
||||
try testing.expectEqual(Result.invalid_value, update(state, null));
|
||||
}
|
||||
|
||||
test "render: size get invalid value" {
|
||||
test "render: get invalid value" {
|
||||
var cols: size.CellCountInt = 0;
|
||||
try testing.expectEqual(Result.invalid_value, get(null, .cols, @ptrCast(&cols)));
|
||||
}
|
||||
|
||||
test "render: get invalid data" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
@@ -289,23 +364,7 @@ test "render: size get invalid value" {
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
var cols: size.CellCountInt = 0;
|
||||
var rows: size.CellCountInt = 0;
|
||||
try testing.expectEqual(Result.invalid_value, size_get(
|
||||
null,
|
||||
&cols,
|
||||
&rows,
|
||||
));
|
||||
try testing.expectEqual(Result.invalid_value, size_get(
|
||||
state,
|
||||
null,
|
||||
&rows,
|
||||
));
|
||||
try testing.expectEqual(Result.invalid_value, size_get(
|
||||
state,
|
||||
&cols,
|
||||
null,
|
||||
));
|
||||
try testing.expectEqual(Result.invalid_value, get(state, .invalid, null));
|
||||
}
|
||||
|
||||
test "render: colors get invalid value" {
|
||||
@@ -326,23 +385,14 @@ test "render: colors get invalid value" {
|
||||
try testing.expectEqual(Result.invalid_value, colors_get(state, &colors));
|
||||
}
|
||||
|
||||
test "render: dirty get/set invalid value" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
&state,
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
test "render: get/set dirty invalid value" {
|
||||
var dirty: Dirty = .false;
|
||||
try testing.expectEqual(Result.invalid_value, dirty_get(null, &dirty));
|
||||
try testing.expectEqual(Result.invalid_value, dirty_set(
|
||||
null,
|
||||
@intFromEnum(Dirty.full),
|
||||
));
|
||||
try testing.expectEqual(Result.invalid_value, get(null, .dirty, @ptrCast(&dirty)));
|
||||
const dirty_full: Dirty = .full;
|
||||
try testing.expectEqual(Result.invalid_value, set(null, .dirty, @ptrCast(&dirty_full)));
|
||||
}
|
||||
|
||||
test "render: dirty get/set" {
|
||||
test "render: get/set dirty" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
@@ -351,25 +401,21 @@ test "render: dirty get/set" {
|
||||
defer free(state);
|
||||
|
||||
var dirty: Dirty = undefined;
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
try testing.expectEqual(Result.success, get(state, .dirty, @ptrCast(&dirty)));
|
||||
try testing.expectEqual(Dirty.false, dirty);
|
||||
|
||||
try testing.expectEqual(Result.success, dirty_set(
|
||||
state,
|
||||
@intFromEnum(Dirty.partial),
|
||||
));
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
const dirty_partial: Dirty = .partial;
|
||||
try testing.expectEqual(Result.success, set(state, .dirty, @ptrCast(&dirty_partial)));
|
||||
try testing.expectEqual(Result.success, get(state, .dirty, @ptrCast(&dirty)));
|
||||
try testing.expectEqual(Dirty.partial, dirty);
|
||||
|
||||
try testing.expectEqual(Result.success, dirty_set(
|
||||
state,
|
||||
@intFromEnum(Dirty.full),
|
||||
));
|
||||
try testing.expectEqual(Result.success, dirty_get(state, &dirty));
|
||||
const dirty_full: Dirty = .full;
|
||||
try testing.expectEqual(Result.success, set(state, .dirty, @ptrCast(&dirty_full)));
|
||||
try testing.expectEqual(Result.success, get(state, .dirty, @ptrCast(&dirty)));
|
||||
try testing.expectEqual(Dirty.full, dirty);
|
||||
}
|
||||
|
||||
test "render: dirty set invalid enum value" {
|
||||
test "render: set null value" {
|
||||
var state: RenderState = null;
|
||||
try testing.expectEqual(Result.success, new(
|
||||
&lib_alloc.test_allocator,
|
||||
@@ -377,7 +423,7 @@ test "render: dirty set invalid enum value" {
|
||||
));
|
||||
defer free(state);
|
||||
|
||||
try testing.expectEqual(Result.invalid_value, dirty_set(state, 99));
|
||||
try testing.expectEqual(Result.invalid_value, set(state, .dirty, null));
|
||||
}
|
||||
|
||||
test "render: row iterator new invalid value" {
|
||||
@@ -650,14 +696,11 @@ test "render: update" {
|
||||
try testing.expectEqual(Result.success, update(state, terminal));
|
||||
|
||||
var cols: size.CellCountInt = 0;
|
||||
var rows: size.CellCountInt = 0;
|
||||
try testing.expectEqual(Result.success, size_get(
|
||||
state,
|
||||
&cols,
|
||||
&rows,
|
||||
));
|
||||
var rows_val: size.CellCountInt = 0;
|
||||
try testing.expectEqual(Result.success, get(state, .cols, @ptrCast(&cols)));
|
||||
try testing.expectEqual(Result.success, get(state, .rows, @ptrCast(&rows_val)));
|
||||
try testing.expectEqual(@as(size.CellCountInt, 80), cols);
|
||||
try testing.expectEqual(@as(size.CellCountInt, 24), rows);
|
||||
try testing.expectEqual(@as(size.CellCountInt, 24), rows_val);
|
||||
}
|
||||
|
||||
test "render: colors get" {
|
||||
|
||||
Reference in New Issue
Block a user