From 3f74a6a542125f8c725bdf1f08976f5a6ea8131a Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Sun, 19 May 2024 10:55:39 +0200 Subject: [PATCH] 1/4 Remember configUrl alongside config Needed for the next commits https://github.com/nikitabobko/AeroSpace/issues/215 --- Sources/AppBundle/MenuBar.swift | 4 +-- .../command/ReloadConfigCommand.swift | 27 ++++++++++--------- Sources/AppBundle/config/Config.swift | 13 ++++----- Sources/AppBundle/config/ConfigFile.swift | 2 +- Sources/AppBundle/config/parseConfig.swift | 20 +++++++------- Sources/AppBundle/initAppBundle.swift | 2 +- Sources/AppBundleTests/testUtil.swift | 1 + 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Sources/AppBundle/MenuBar.swift b/Sources/AppBundle/MenuBar.swift index cf7951ce..2c834f8b 100644 --- a/Sources/AppBundle/MenuBar.swift +++ b/Sources/AppBundle/MenuBar.swift @@ -35,7 +35,7 @@ public func menuBar(viewModel: TrayMenuModel) -> some Scene { let editor = getTextEditorToOpenConfig() Button("Open config in '\(editor.lastPathComponent)'") { let fallbackConfig: URL = FileManager.default.homeDirectoryForCurrentUser.appending(path: configDotfileName) - switch getConfigFileUrl() { + switch findCustomConfigUrl() { case .file(let url): url.open(with: editor) case .noCustomConfigExists: @@ -64,7 +64,7 @@ public func menuBar(viewModel: TrayMenuModel) -> some Scene { } func getTextEditorToOpenConfig() -> URL { - NSWorkspace.shared.urlForApplication(toOpen: getConfigFileUrl().urlOrNil ?? defaultConfigUrl)? + NSWorkspace.shared.urlForApplication(toOpen: findCustomConfigUrl().urlOrNil ?? defaultConfigUrl)? .takeIf { $0.lastPathComponent != "Xcode.app" } // Blacklist Xcode. It is too heavy to open plain text files ?? URL(filePath: "/System/Applications/TextEdit.app") } diff --git a/Sources/AppBundle/command/ReloadConfigCommand.swift b/Sources/AppBundle/command/ReloadConfigCommand.swift index f48b05c6..0d010f3b 100644 --- a/Sources/AppBundle/command/ReloadConfigCommand.swift +++ b/Sources/AppBundle/command/ReloadConfigCommand.swift @@ -13,23 +13,24 @@ struct ReloadConfigCommand: Command { } } -func reloadConfig() -> Bool { +func reloadConfig(forceConfigUrl: URL? = nil) -> Bool { var devNull = "" - return reloadConfig(stdout: &devNull) + return reloadConfig(forceConfigUrl: forceConfigUrl, stdout: &devNull) } -func loadConfig(_ newConfig: Config) { - resetHotKeys() - config = newConfig - activateMode(mainModeId) - syncStartAtLogin() -} - -func reloadConfig(args: ReloadConfigCmdArgs = ReloadConfigCmdArgs(), stdout: inout String) -> Bool { - switch readConfig() { - case .success(let parsedConfig): +func reloadConfig( + args: ReloadConfigCmdArgs = ReloadConfigCmdArgs(), + forceConfigUrl: URL? = nil, + stdout: inout String +) -> Bool { + switch readConfig(forceConfigUrl: forceConfigUrl) { + case .success(let (parsedConfig, url)): if !args.dryRun { - loadConfig(parsedConfig) + resetHotKeys() + config = parsedConfig + configUrl = url + activateMode(mainModeId) + syncStartAtLogin() } return true case .failure(let msg): diff --git a/Sources/AppBundle/config/Config.swift b/Sources/AppBundle/config/Config.swift index d032cbeb..b3335670 100644 --- a/Sources/AppBundle/config/Config.swift +++ b/Sources/AppBundle/config/Config.swift @@ -3,26 +3,27 @@ import HotKey import Common let mainModeId = "main" -var defaultConfigUrl: URL { Bundle.main.url(forResource: "default-config", withExtension: "toml")! } -let defaultConfig: Config = { - let defaultConfig: URL +var defaultConfigUrl: URL { if isUnitTest { var url = URL(filePath: #file) while !FileManager.default.fileExists(atPath: url.appending(component: ".git").path) { url.deleteLastPathComponent() } let projectRoot: URL = url - defaultConfig = projectRoot.appending(component: "docs/config-examples/default-config.toml") + return projectRoot.appending(component: "docs/config-examples/default-config.toml") } else { - defaultConfig = defaultConfigUrl + return Bundle.main.url(forResource: "default-config", withExtension: "toml")! } - let parsedConfig = parseConfig(try! String(contentsOf: defaultConfig)) +} +let defaultConfig: Config = { + let parsedConfig = parseConfig(try! String(contentsOf: defaultConfigUrl)) if !parsedConfig.errors.isEmpty { error("Can't parse default config: \(parsedConfig.errors)") } return parsedConfig.config }() var config: Config = defaultConfig +var configUrl: URL = defaultConfigUrl struct Config: Copyable { var afterLoginCommand: [any Command] = [] diff --git a/Sources/AppBundle/config/ConfigFile.swift b/Sources/AppBundle/config/ConfigFile.swift index 99378f18..73d41509 100644 --- a/Sources/AppBundle/config/ConfigFile.swift +++ b/Sources/AppBundle/config/ConfigFile.swift @@ -2,7 +2,7 @@ import Foundation import Common let configDotfileName = isDebug ? ".aerospace-debug.toml" : ".aerospace.toml" -func getConfigFileUrl() -> ConfigFile { +func findCustomConfigUrl() -> ConfigFile { let fileName = isDebug ? "aerospace-debug.toml" : "aerospace.toml" let xdgConfigHome = ProcessInfo.processInfo.environment["XDG_CONFIG_HOME"]?.lets { URL(filePath: $0) } ?? FileManager.default.homeDirectoryForCurrentUser.appending(path: ".config/") diff --git a/Sources/AppBundle/config/parseConfig.swift b/Sources/AppBundle/config/parseConfig.swift index 9123304e..02b19cfe 100644 --- a/Sources/AppBundle/config/parseConfig.swift +++ b/Sources/AppBundle/config/parseConfig.swift @@ -3,13 +3,11 @@ import AppKit import HotKey import TOMLKit -func readConfig() -> Result { - let configUrl: URL? - switch getConfigFileUrl() { - case .file(let url): - configUrl = url - case .noCustomConfigExists: - configUrl = nil +func readConfig(forceConfigUrl: URL? = nil) -> Result<(Config, URL), String> { + let customConfigUrl: URL + switch findCustomConfigUrl() { + case .file(let url): customConfigUrl = url + case .noCustomConfigExists: customConfigUrl = defaultConfigUrl case .ambiguousConfigError(let candidates): let msg = """ Ambiguous config error. Several configs found: @@ -17,14 +15,14 @@ func readConfig() -> Result { """ return .failure(msg) } - let (parsedConfig, errors) = configUrl.flatMap { try? String(contentsOf: $0) }.map { parseConfig($0) } - ?? (defaultConfig, []) + let configUrl: URL = forceConfigUrl ?? customConfigUrl + let (parsedConfig, errors) = (try? String(contentsOf: configUrl)).map { parseConfig($0) } ?? (defaultConfig, []) if errors.isEmpty { - return .success(parsedConfig) + return .success((parsedConfig, configUrl)) } else { let msg = """ - Failed to parse \(configUrl?.absoluteURL.path ?? "nil-configUrl") + Failed to parse \(configUrl.absoluteURL.path) \(errors.map(\.description).joined(separator: "\n\n")) """ diff --git a/Sources/AppBundle/initAppBundle.swift b/Sources/AppBundle/initAppBundle.swift index fb23f3c9..7c896d19 100644 --- a/Sources/AppBundle/initAppBundle.swift +++ b/Sources/AppBundle/initAppBundle.swift @@ -11,7 +11,7 @@ public func initAppBundle() { } let startedAtLogin = CommandLine.arguments.getOrNil(atIndex: 1) == "--started-at-login" if !reloadConfig() { - loadConfig(defaultConfig) + check(reloadConfig(forceConfigUrl: defaultConfigUrl)) } if startedAtLogin && !config.startAtLogin { terminateApp() diff --git a/Sources/AppBundleTests/testUtil.swift b/Sources/AppBundleTests/testUtil.swift index 89d485b0..e28019ce 100644 --- a/Sources/AppBundleTests/testUtil.swift +++ b/Sources/AppBundleTests/testUtil.swift @@ -13,6 +13,7 @@ let projectRoot: URL = { func setUpWorkspacesForTests() { config = defaultConfig + configUrl = defaultConfigUrl config.enableNormalizationFlattenContainers = false // Make layout tests more predictable config.enableNormalizationOppositeOrientationForNestedContainers = false // Make layout tests more predictable config.defaultRootContainerOrientation = .horizontal // Make default layout predictable