aerospace fork
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177import AppKitimport Common
struct ConfigCommand: Command { let args: ConfigCmdArgs /*conforms*/ let shouldResetClosedWindowsCache = false
func run(_ env: CmdEnv, _ io: CmdIo) -> BinaryExitCode { switch args.mode { case .getKey(let key): return getKey(io, args: args, key: key) case .majorKeys: let out = """ . mode \(config.modes.keys.map { "mode.\($0).binding" }.joined(separator: "\n")) """ return .succ(io.out(out)) case .allKeys: let configMap = buildConfigMap() var allKeys: [String] = [] configMap.dumpAllKeysRecursive(path: ".", result: &allKeys) return .succ(io.out(allKeys.joined(separator: "\n"))) case .configPath: return .succ(io.out(configUrl.absoluteURL.path)) } }}
extension String { fileprivate func toKeyPath() -> Result<[String], String> { if self == "." { return .success([]) } if isEmpty { return .failure("Invalid empty key") } if self.contains("..") { return .failure("Invalid key '\(self)'") } if self.hasSuffix(".") { return .failure("Invalid key '\(self)'") } return .success(self.split(separator: ".", omittingEmptySubsequences: false).map(String.init)) }}
@MainActor private func getKey(_ io: CmdIo, args: ConfigCmdArgs, key: String) -> BinaryExitCode { guard let keyPath = key.toKeyPath().getOrNil(appendErrorTo: &io.stderr) else { return .fail } guard var configMap = buildConfigMap().find(keyPath: keyPath.slice).getOrNil(appendErrorTo: &io.stderr) else { return .fail } if args.keys { switch configMap { case .scalar(let scalar): return .fail(io.err("--keys flag cannot be applied to scalar object '\(scalar)'")) case .map(let map): configMap = .array(map.keys.map { .scalar(.string($0)) }) case .array(let array): configMap = .array((0 ..< array.count).map { .scalar(.int($0)) }) } } if args.json { return switch JSONEncoder.aeroSpaceDefault.encodeToString(configMap) { case let json?: .succ(io.out(json)) case nil: .fail(io.err("Can't convert json Data to String")) } } else { switch configMap { case .scalar(let scalar): return .succ(io.out(scalar.describe)) case .map: let msg = "Complicated objects can be printed only with --json flag. Alternatively, you can try to inspect keys of the object with --keys flag" return .fail(io.err(msg)) case .array(let array): let plainArray: Result<[String], String> = array.mapAllOrFailure { switch $0 { case .scalar(let scalar): .success(scalar.describe) default: .failure("Printing array of non-string objects is supported only with --json flag." + "Alternatively, you can try to inspect keys of the object with --keys flag") } } return switch plainArray { case .success(let array): .succ(io.out(array.sorted().joined(separator: "\n"))) case .failure(let error): .fail(io.err(error)) } } }}
extension ConfigMapValue { func find(keyPath: StrArrSlice) -> Result<ConfigMapValue, String> { if let key = keyPath.first { switch self { case .scalar(let scalar): return .failure("Can't dereference scalar value '\(scalar.describe)'") case .map(let map): return switch map[key] { case let child?: child.find(keyPath: keyPath.slice(1...).orDie()) case nil: .failure("No value at key token '\(key)'") } case .array(let array): if let key = Int(key) { return switch array.getOrNil(atIndex: key) { case let child?: child.find(keyPath: keyPath.slice(1...).orDie()) case nil: .failure("Index out of bounds. Index: \(key), Size: \(array.count)") } } else { return .failure("Can't convert key token '\(key)' to Int") } } } else { return .success(self) } }
func dumpAllKeysRecursive(path: String, result: inout [String]) { result.append(path) switch self { case .scalar: break case .map(let map): for (key, value) in map { let path = path == "." ? key : path + "." + key value.dumpAllKeysRecursive(path: path, result: &result) } case .array(let array): for (index, value) in array.enumerated() { let path = path == "." ? String(index) : path + "." + String(index) value.dumpAllKeysRecursive(path: path, result: &result) } } }}
extension Shell<any Command> { var shellOfCommandsDescription: String { buildDescription { $0.args.description } }}
@MainActor func buildConfigMap() -> ConfigMapValue { let mode = config.modes.mapValues { (mode: Mode) -> ConfigMapValue in var keyNotationToScript: [String: ConfigMapValue] = [:] for binding in mode.bindings.values { keyNotationToScript[binding.descriptionWithKeyNotation] = .scalar(.string(binding.commands.shellOfCommandsDescription)) } return .map(["binding": .map(keyNotationToScript)]) } return .map(["mode": .map(mode)])}
enum ConfigScalarValue: Encodable { case string(String) case int(Int)
var describe: String { return switch self { case .string(let string): string case .int(let int): String(int) } }
func encode(to encoder: Encoder) throws { let value: Encodable = switch self { case .string(let string): string case .int(let int): int } var container = encoder.singleValueContainer() try container.encode(value) }}
enum ConfigMapValue: Encodable { case scalar(ConfigScalarValue) case map([String: ConfigMapValue]) case array([ConfigMapValue])
func encode(to encoder: Encoder) throws { let value: Encodable = switch self { case .scalar(let scalar): scalar case .map(let map): map case .array(let array): array } var container = encoder.singleValueContainer() try container.encode(value) }}