import Foundation import TOML extension PHLayout { /// Load the specified layouts from the resolved config directory (see `PHPaths`). /// If any of theme doesn't exist or fails to parse, the execution is interrupted. static func load(_ layouts: Set) throws -> [String: PHLayout] { var dictionary = [String: PHLayout]() for layout in layouts { dictionary.updateValue(try load(layout), forKey: layout) } return dictionary } /// Load a layout from the resolved config directory (see `PHPaths`). /// If the file doesn't exist or fails to parse, the execution is interrupted. static func load(_ layout: String) throws -> PHLayout { let url = PHPaths.layoutsDirectory.appending(path: "\(layout).toml") if FileManager.default.fileExists(atPath: url.relativePath) { return try load(from: url) } else { let layout = url.lastPathComponent throw PHBar.Error( """ Layout file not found. Make sure to have a file named `\(layout)` inside the directory: `\(PHPaths.layoutsDirectory.relativePath)` Tip: If you've never used phbar before, run `phbar generate config` to automatically generate the required configuration files. """ ) } } /// Load a layout from the file at URL. /// If the file doesn't exist or fails to parse, the execution is interrupted. static private func load(from url: URL) throws -> PHLayout { do { let data = try Data(contentsOf: url) guard let contents = String(data: data, encoding: .utf8) else { throw PHBar.Error("content is not UTF8 encoded.") } let decoder = TOMLDecoder() let layoutFile = contents.expanded(from: ProcessInfo.processInfo.environment) return try decoder.decode(PHLayout.self, from: layoutFile) } catch { let layout = url.lastPathComponent throw PHBar.Error("Layout file `\(layout)` not readable", underlyingError: error) } } }