fix: ColorList.clone not cloning colors_c (#9613)
### Problem Custom icon configuration (`macos-icon = custom-style` with `macos-icon-screen-color`) stopped working, reverting to the default icon. ### Root cause The `ColorList.clone()` method only cloned the `colors` array but not the `colors_c` array. The Swift code reads from `colors_c` via the C API (`ghostty_config_get`), so when configs were cloned, the C-accessible color list was empty. ### Why it broke This bug was introduced in the original implementation inpull/9626/head29929a473(Dec 2024), but remained dormant until commitf60bdb0fa(Sep 19, 2025), which moved the icon-setting `switch` statement into `syncAppearance()`. Since `syncAppearance()` is called with cloned configs from `ghosttyConfigDidChange()` (which receives cloned configs from `Ghostty.App.swift:1639`), the icon code now ran with cloned configs that had empty `colors_c` arrays. ### Fix Clone both arrays in `ColorList.clone()`: ```zig .colors = try self.colors.clone(alloc), .colors_c = try self.colors_c.clone(alloc), // Added ``` ### Testing - Added ColorList.test.clone test case that verifies both colors and colors_c arrays are properly cloned - Verified test fails without the fix (expected 3 colors_c items, found 0) - Verified test passes with the fix - Confirmed custom icon now persists correctly with both initial config load and subsequent config change notifications ### Discussion I opened a discussion to report this ([9616](https://github.com/ghostty-org/ghostty/discussions/9616)) that this PR will resolve. > [!NOTE] > **LLM Usage Disclosure** > This bug was investigated and debugged with assistance from Claude Code. The root cause analysis and fix were developed through interactive debugging.
commit
b7be27b1f5
|
|
@ -5203,6 +5203,7 @@ pub const ColorList = struct {
|
||||||
) Allocator.Error!Self {
|
) Allocator.Error!Self {
|
||||||
return .{
|
return .{
|
||||||
.colors = try self.colors.clone(alloc),
|
.colors = try self.colors.clone(alloc),
|
||||||
|
.colors_c = try self.colors_c.clone(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5281,6 +5282,26 @@ pub const ColorList = struct {
|
||||||
try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
|
try p.formatEntry(formatterpkg.entryFormatter("a", &buf.writer));
|
||||||
try std.testing.expectEqualSlices(u8, "a = #000000,#ffffff\n", buf.written());
|
try std.testing.expectEqualSlices(u8, "a = #000000,#ffffff\n", buf.written());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "clone" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
|
var source: Self = .{};
|
||||||
|
try source.parseCLI(alloc, "#ff0000,#00ff00,#0000ff");
|
||||||
|
|
||||||
|
const cloned = try source.clone(alloc);
|
||||||
|
|
||||||
|
try testing.expect(source.equal(cloned));
|
||||||
|
try testing.expectEqual(source.colors_c.items.len, cloned.colors_c.items.len);
|
||||||
|
for (source.colors_c.items, cloned.colors_c.items) |src_c, clone_c| {
|
||||||
|
try testing.expectEqual(src_c.r, clone_c.r);
|
||||||
|
try testing.expectEqual(src_c.g, clone_c.g);
|
||||||
|
try testing.expectEqual(src_c.b, clone_c.b);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Palette is the 256 color palette for 256-color mode. This is still
|
/// Palette is the 256 color palette for 256-color mode. This is still
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue