libghostty: optimize bits for selection gesture validation fields

pull/12833/head
Mitchell Hashimoto 2026-05-27 11:05:20 -07:00
parent 3e0477a14a
commit 4e2d7c314b
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
1 changed files with 27 additions and 34 deletions

View File

@ -35,25 +35,18 @@ const EventWrapper = struct {
deep_press: SelectionGesture.DeepPress, deep_press: SelectionGesture.DeepPress,
}, },
// Press.pin has no safe sentinel value: PageList.Pin contains a non-null // Validation sidecar for required event fields that don't have safe
// node pointer and is undefined until the C caller provides a GhosttyGridRef. // sentinels in the real SelectionGesture payloads. For example, PageList.Pin
// Track that separately so event execution can reject a press whose required // contains a non-null node pointer and Geometry has no meaningful zero
// ref option was never set, or was later cleared. // value. Keep these as one-bit flags so dispatch can reject incomplete C
press_pin_set: bool = false, // events instead of using undefined placeholder data.
event_validation: packed struct {
// Drag.pin and Drag.geometry are required by SelectionGesture.drag but have press_pin_set: bool = false,
// no meaningful zero/sentinel value. Track whether the C caller set them so drag_pin_set: bool = false,
// dispatch can reject incomplete drag events instead of using placeholder drag_geometry_set: bool = false,
// data. autoscroll_tick_viewport_set: bool = false,
drag_pin_set: bool = false, autoscroll_tick_geometry_set: bool = false,
drag_geometry_set: bool = false, } = .{},
// AutoscrollTick.viewport and AutoscrollTick.geometry are required by
// SelectionGesture.autoscrollTick but have no meaningful zero/sentinel
// value. Track whether the C caller set them so dispatch can reject
// incomplete tick events instead of using placeholder data.
autoscroll_tick_viewport_set: bool = false,
autoscroll_tick_geometry_set: bool = false,
// Backing storage for Press/Drag/AutoscrollTick.word_boundary_codepoints. // Backing storage for Press/Drag/AutoscrollTick.word_boundary_codepoints.
// The C API receives codepoints as borrowed uint32_t values, but // The C API receives codepoints as borrowed uint32_t values, but
@ -305,7 +298,7 @@ pub fn handle_event(
return switch (event_wrapper.event) { return switch (event_wrapper.event) {
.press => |press| { .press => |press| {
if (!event_wrapper.press_pin_set) return .invalid_value; if (!event_wrapper.event_validation.press_pin_set) return .invalid_value;
const sel = wrapper.gesture.press(t, press) catch return .out_of_memory; const sel = wrapper.gesture.press(t, press) catch return .out_of_memory;
if (out_selection) |out| { if (out_selection) |out| {
out.* = selection_c.CSelection.fromZig(sel orelse return .no_value); out.* = selection_c.CSelection.fromZig(sel orelse return .no_value);
@ -317,8 +310,8 @@ pub fn handle_event(
return .no_value; return .no_value;
}, },
.drag => |drag| { .drag => |drag| {
if (!event_wrapper.drag_pin_set) return .invalid_value; if (!event_wrapper.event_validation.drag_pin_set) return .invalid_value;
if (!event_wrapper.drag_geometry_set) return .invalid_value; if (!event_wrapper.event_validation.drag_geometry_set) return .invalid_value;
const sel = wrapper.gesture.drag(t, drag); const sel = wrapper.gesture.drag(t, drag);
if (out_selection) |out| { if (out_selection) |out| {
out.* = selection_c.CSelection.fromZig(sel orelse return .no_value); out.* = selection_c.CSelection.fromZig(sel orelse return .no_value);
@ -326,8 +319,8 @@ pub fn handle_event(
return .success; return .success;
}, },
.autoscroll_tick => |tick| { .autoscroll_tick => |tick| {
if (!event_wrapper.autoscroll_tick_viewport_set) return .invalid_value; if (!event_wrapper.event_validation.autoscroll_tick_viewport_set) return .invalid_value;
if (!event_wrapper.autoscroll_tick_geometry_set) return .invalid_value; if (!event_wrapper.event_validation.autoscroll_tick_geometry_set) return .invalid_value;
const sel = wrapper.gesture.autoscrollTick(t, tick); const sel = wrapper.gesture.autoscrollTick(t, tick);
if (out_selection) |out| { if (out_selection) |out| {
out.* = selection_c.CSelection.fromZig(sel orelse return .no_value); out.* = selection_c.CSelection.fromZig(sel orelse return .no_value);
@ -458,7 +451,7 @@ fn pressSetTyped(
) Result { ) Result {
const v = value orelse { const v = value orelse {
switch (option) { switch (option) {
.ref => event.press_pin_set = false, .ref => event.event_validation.press_pin_set = false,
.position => { .position => {
press.xpos = 0; press.xpos = 0;
press.ypos = 0; press.ypos = 0;
@ -485,7 +478,7 @@ fn pressSetTyped(
switch (option) { switch (option) {
.ref => { .ref => {
press.pin = v.toPin() orelse return .invalid_value; press.pin = v.toPin() orelse return .invalid_value;
event.press_pin_set = true; event.event_validation.press_pin_set = true;
}, },
.position => { .position => {
press.xpos = v.x; press.xpos = v.x;
@ -552,7 +545,7 @@ fn dragSetTyped(
) Result { ) Result {
const v = value orelse { const v = value orelse {
switch (option) { switch (option) {
.ref => event.drag_pin_set = false, .ref => event.event_validation.drag_pin_set = false,
.position => { .position => {
drag.xpos = 0; drag.xpos = 0;
drag.ypos = 0; drag.ypos = 0;
@ -562,7 +555,7 @@ fn dragSetTyped(
&drag.word_boundary_codepoints, &drag.word_boundary_codepoints,
), ),
.rectangle => drag.rectangle = false, .rectangle => drag.rectangle = false,
.geometry => event.drag_geometry_set = false, .geometry => event.event_validation.drag_geometry_set = false,
.viewport => return .invalid_value, .viewport => return .invalid_value,
.repeat_distance, .repeat_distance,
@ -577,7 +570,7 @@ fn dragSetTyped(
switch (option) { switch (option) {
.ref => { .ref => {
drag.pin = v.toPin() orelse return .invalid_value; drag.pin = v.toPin() orelse return .invalid_value;
event.drag_pin_set = true; event.event_validation.drag_pin_set = true;
}, },
.position => { .position => {
drag.xpos = v.x; drag.xpos = v.x;
@ -591,7 +584,7 @@ fn dragSetTyped(
.rectangle => drag.rectangle = v.*, .rectangle => drag.rectangle = v.*,
.geometry => { .geometry => {
drag.geometry = v.toZig() orelse return .invalid_value; drag.geometry = v.toZig() orelse return .invalid_value;
event.drag_geometry_set = true; event.event_validation.drag_geometry_set = true;
}, },
.viewport => return .invalid_value, .viewport => return .invalid_value,
@ -613,7 +606,7 @@ fn autoscrollTickSetTyped(
) Result { ) Result {
const v = value orelse { const v = value orelse {
switch (option) { switch (option) {
.viewport => event.autoscroll_tick_viewport_set = false, .viewport => event.event_validation.autoscroll_tick_viewport_set = false,
.position => { .position => {
tick.xpos = 0; tick.xpos = 0;
tick.ypos = 0; tick.ypos = 0;
@ -623,7 +616,7 @@ fn autoscrollTickSetTyped(
&tick.word_boundary_codepoints, &tick.word_boundary_codepoints,
), ),
.rectangle => tick.rectangle = false, .rectangle => tick.rectangle = false,
.geometry => event.autoscroll_tick_geometry_set = false, .geometry => event.event_validation.autoscroll_tick_geometry_set = false,
.ref, .ref,
.repeat_distance, .repeat_distance,
@ -638,7 +631,7 @@ fn autoscrollTickSetTyped(
switch (option) { switch (option) {
.viewport => { .viewport => {
tick.viewport = v.*; tick.viewport = v.*;
event.autoscroll_tick_viewport_set = true; event.event_validation.autoscroll_tick_viewport_set = true;
}, },
.position => { .position => {
tick.xpos = v.x; tick.xpos = v.x;
@ -652,7 +645,7 @@ fn autoscrollTickSetTyped(
.rectangle => tick.rectangle = v.*, .rectangle => tick.rectangle = v.*,
.geometry => { .geometry => {
tick.geometry = v.toZig() orelse return .invalid_value; tick.geometry = v.toZig() orelse return .invalid_value;
event.autoscroll_tick_geometry_set = true; event.event_validation.autoscroll_tick_geometry_set = true;
}, },
.ref, .ref,