mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #2761 from ghostty-org/push-zspzyylxlsvr
input: Binding set clone must deep clone actions
This commit is contained in:
@ -421,6 +421,8 @@ pub const Action = union(enum) {
|
|||||||
///
|
///
|
||||||
crash: CrashThread,
|
crash: CrashThread,
|
||||||
|
|
||||||
|
pub const Key = @typeInfo(Action).Union.tag_type.?;
|
||||||
|
|
||||||
pub const CrashThread = enum {
|
pub const CrashThread = enum {
|
||||||
main,
|
main,
|
||||||
io,
|
io,
|
||||||
@ -430,6 +432,16 @@ pub const Action = union(enum) {
|
|||||||
pub const CursorKey = struct {
|
pub const CursorKey = struct {
|
||||||
normal: []const u8,
|
normal: []const u8,
|
||||||
application: []const u8,
|
application: []const u8,
|
||||||
|
|
||||||
|
pub fn clone(
|
||||||
|
self: CursorKey,
|
||||||
|
alloc: Allocator,
|
||||||
|
) Allocator.Error!CursorKey {
|
||||||
|
return .{
|
||||||
|
.normal = try alloc.dupe(u8, self.normal),
|
||||||
|
.application = try alloc.dupe(u8, self.application),
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AdjustSelection = enum {
|
pub const AdjustSelection = enum {
|
||||||
@ -773,6 +785,50 @@ pub const Action = union(enum) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clone this action with the given allocator. The allocator
|
||||||
|
/// should be an arena-style allocator since fine-grained
|
||||||
|
/// deallocation is not possible.
|
||||||
|
pub fn clone(self: Action, alloc: Allocator) Allocator.Error!Action {
|
||||||
|
return switch (self) {
|
||||||
|
inline else => |value, tag| @unionInit(
|
||||||
|
Action,
|
||||||
|
@tagName(tag),
|
||||||
|
try cloneValue(alloc, value),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cloneValue(
|
||||||
|
alloc: Allocator,
|
||||||
|
value: anytype,
|
||||||
|
) Allocator.Error!@TypeOf(value) {
|
||||||
|
return switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.Void,
|
||||||
|
.Int,
|
||||||
|
.Float,
|
||||||
|
.Enum,
|
||||||
|
=> value,
|
||||||
|
|
||||||
|
.Pointer => |info| slice: {
|
||||||
|
comptime assert(info.size == .Slice);
|
||||||
|
break :slice try alloc.dupe(
|
||||||
|
info.child,
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
.Struct => |info| if (info.is_tuple)
|
||||||
|
value
|
||||||
|
else
|
||||||
|
try value.clone(alloc),
|
||||||
|
|
||||||
|
else => {
|
||||||
|
@compileLog(@TypeOf(value));
|
||||||
|
@compileError("unexpected type");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a hash code that can be used to uniquely identify this
|
/// Returns a hash code that can be used to uniquely identify this
|
||||||
/// action.
|
/// action.
|
||||||
pub fn hash(self: Action) u64 {
|
pub fn hash(self: Action) u64 {
|
||||||
@ -1101,6 +1157,16 @@ pub const Set = struct {
|
|||||||
action: Action,
|
action: Action,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
|
|
||||||
|
pub fn clone(
|
||||||
|
self: Leaf,
|
||||||
|
alloc: Allocator,
|
||||||
|
) Allocator.Error!Leaf {
|
||||||
|
return .{
|
||||||
|
.action = try self.action.clone(alloc),
|
||||||
|
.flags = self.flags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hash(self: Leaf) u64 {
|
pub fn hash(self: Leaf) u64 {
|
||||||
var hasher = std.hash.Wyhash.init(0);
|
var hasher = std.hash.Wyhash.init(0);
|
||||||
self.action.hash(&hasher);
|
self.action.hash(&hasher);
|
||||||
@ -1390,8 +1456,9 @@ pub const Set = struct {
|
|||||||
// If we have any leaders we need to clone them.
|
// If we have any leaders we need to clone them.
|
||||||
var it = result.bindings.iterator();
|
var it = result.bindings.iterator();
|
||||||
while (it.next()) |entry| switch (entry.value_ptr.*) {
|
while (it.next()) |entry| switch (entry.value_ptr.*) {
|
||||||
// No data to clone
|
// Leaves could have data to clone (i.e. text actions
|
||||||
.leaf => {},
|
// contain allocated strings).
|
||||||
|
.leaf => |*s| s.* = try s.clone(alloc),
|
||||||
|
|
||||||
// Must be deep cloned.
|
// Must be deep cloned.
|
||||||
.leader => |*s| {
|
.leader => |*s| {
|
||||||
@ -2128,3 +2195,22 @@ test "set: consumed state" {
|
|||||||
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.* == .leaf);
|
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.* == .leaf);
|
||||||
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf.flags.consumed);
|
try testing.expect(s.get(.{ .key = .{ .translated = .a } }).?.value_ptr.*.leaf.flags.consumed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Action: clone" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
|
{
|
||||||
|
var a: Action = .ignore;
|
||||||
|
const b = try a.clone(alloc);
|
||||||
|
try testing.expect(b == .ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a: Action = .{ .text = "foo" };
|
||||||
|
const b = try a.clone(alloc);
|
||||||
|
try testing.expect(b == .text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user