From ab84a02152b7f9d4e7bfbe4555bda0b2550e32ac Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:30:21 -0800 Subject: [PATCH] Fix reload config to honor legacy Ghostty config fallback (#202) --- Sources/GhosttyTerminalView.swift | 31 +++++++++++++++++-------- cmuxTests/GhosttyConfigTests.swift | 36 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Sources/GhosttyTerminalView.swift b/Sources/GhosttyTerminalView.swift index fb23ab7f..7bc8194f 100644 --- a/Sources/GhosttyTerminalView.swift +++ b/Sources/GhosttyTerminalView.swift @@ -288,9 +288,7 @@ class GhosttyApp { // Load default config (includes user config). If this fails hard (e.g. due to // invalid user config), ghostty_app_new may return nil; we fall back below. - ghostty_config_load_default_files(primaryConfig) - loadLegacyGhosttyConfigIfNeeded(primaryConfig) - ghostty_config_finalize(primaryConfig) + loadDefaultConfigFilesWithLegacyFallback(primaryConfig) updateDefaultBackground(from: primaryConfig) // Create runtime config with callbacks @@ -458,6 +456,21 @@ class GhosttyApp { #endif } + private func loadDefaultConfigFilesWithLegacyFallback(_ config: ghostty_config_t) { + ghostty_config_load_default_files(config) + loadLegacyGhosttyConfigIfNeeded(config) + ghostty_config_finalize(config) + } + + static func shouldLoadLegacyGhosttyConfig( + newConfigFileSize: Int?, + legacyConfigFileSize: Int? + ) -> Bool { + guard let newConfigFileSize, newConfigFileSize == 0 else { return false } + guard let legacyConfigFileSize, legacyConfigFileSize > 0 else { return false } + return true + } + private func loadLegacyGhosttyConfigIfNeeded(_ config: ghostty_config_t) { #if os(macOS) // Ghostty 1.3+ prefers `config.ghostty`, but some users still have their real @@ -475,8 +488,10 @@ class GhosttyApp { return size.intValue } - guard let newSize = fileSize(configNew), newSize == 0 else { return } - guard let legacySize = fileSize(configLegacy), legacySize > 0 else { return } + guard Self.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: fileSize(configNew), + legacyConfigFileSize: fileSize(configLegacy) + ) else { return } configLegacy.path.withCString { path in ghostty_config_load_file(config, path) @@ -512,8 +527,7 @@ class GhosttyApp { } guard let newConfig = ghostty_config_new() else { return } - ghostty_config_load_default_files(newConfig) - ghostty_config_finalize(newConfig) + loadDefaultConfigFilesWithLegacyFallback(newConfig) ghostty_app_update_config(app, newConfig) updateDefaultBackground(from: newConfig) DispatchQueue.main.async { @@ -533,8 +547,7 @@ class GhosttyApp { } guard let newConfig = ghostty_config_new() else { return } - ghostty_config_load_default_files(newConfig) - ghostty_config_finalize(newConfig) + loadDefaultConfigFilesWithLegacyFallback(newConfig) ghostty_surface_update_config(surface, newConfig) ghostty_config_free(newConfig) } diff --git a/cmuxTests/GhosttyConfigTests.swift b/cmuxTests/GhosttyConfigTests.swift index b6f13d4d..dddecf16 100644 --- a/cmuxTests/GhosttyConfigTests.swift +++ b/cmuxTests/GhosttyConfigTests.swift @@ -126,6 +126,42 @@ final class GhosttyConfigTests: XCTestCase { XCTAssertEqual(rgb255(config.backgroundColor), RGB(red: 253, green: 246, blue: 227)) } + func testLegacyConfigFallbackUsesLegacyFileWhenConfigGhosttyIsEmpty() { + XCTAssertTrue( + GhosttyApp.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: 0, + legacyConfigFileSize: 42 + ) + ) + } + + func testLegacyConfigFallbackSkipsWhenNewFileMissingOrLegacyEmpty() { + XCTAssertFalse( + GhosttyApp.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: nil, + legacyConfigFileSize: 42 + ) + ) + XCTAssertFalse( + GhosttyApp.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: 10, + legacyConfigFileSize: 42 + ) + ) + XCTAssertFalse( + GhosttyApp.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: 0, + legacyConfigFileSize: 0 + ) + ) + XCTAssertFalse( + GhosttyApp.shouldLoadLegacyGhosttyConfig( + newConfigFileSize: 0, + legacyConfigFileSize: nil + ) + ) + } + private func rgb255(_ color: NSColor) -> RGB { let srgb = color.usingColorSpace(.sRGB)! var red: CGFloat = 0