From 4eefa53c83edcbf6d5bbab567462687a05170dde Mon Sep 17 00:00:00 2001 From: WuerfelDev Date: Wed, 5 Jun 2024 13:51:07 +0200 Subject: [PATCH 1/2] [config] Search in OS config directories Searches for: - ~/Library/Application Support/swift-format/config.json - $XDG_CONFIG_HOME/swift-format/config.json - ~/.config/swift-format/config.json --- Sources/swift-format/Frontend/Frontend.swift | 55 +++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Sources/swift-format/Frontend/Frontend.swift b/Sources/swift-format/Frontend/Frontend.swift index 99ecef09..5ef514c0 100644 --- a/Sources/swift-format/Frontend/Frontend.swift +++ b/Sources/swift-format/Frontend/Frontend.swift @@ -181,7 +181,9 @@ class Frontend { /// it was provided, or by searching in paths inferred by `swiftFilePath` if one exists, or the /// default configuration otherwise. If an error occurred when reading the configuration, a /// diagnostic is emitted and `nil` is returned. If neither `pathOrString` nor `swiftFilePath` - /// were provided, a default `Configuration()` will be returned. + /// were provided, a configuration is searched at the current working directory or upwards the + /// path. Next the configuration is searched for at the OS default config locations as + /// swift-format/config.json. Finally the default `Configuration()` will be returned. private func configuration( fromPathOrString pathOrString: String?, orInferredFromSwiftFileAt swiftFileURL: URL? @@ -241,6 +243,57 @@ class Frontend { } } + // Load global configuration file + // First URLs are created, then they are queried. First match is loaded + var configLocations: [URL] = [] + + if #available(macOS 13.0, iOS 16.0, *) { + // From "~/Library/Application Support/" directory + configLocations.append(URL.applicationSupportDirectory) + // From $XDG_CONFIG_HOME directory + if let xdgConfig: String = ProcessInfo.processInfo.environment["XDG_CONFIG_HOME"] { + configLocations.append(URL(filePath: xdgConfig, directoryHint: .isDirectory)) + } + // From "~/.config/" directory + var dotconfig: URL = URL.homeDirectory + dotconfig.append(component: ".config", directoryHint: .isDirectory) + configLocations.append(dotconfig) + } else { + // From "~/Library/Application Support/" directory + var appSupport: URL = FileManager.default.homeDirectoryForCurrentUser + appSupport.appendPathComponent("Library", isDirectory: true) + appSupport.appendPathComponent("Application Support", isDirectory: true) + configLocations.append(appSupport) + // From $XDG_CONFIG_HOME directory + if let xdgConfig: String = ProcessInfo.processInfo.environment["XDG_CONFIG_HOME"] { + configLocations.append(URL(fileURLWithPath: xdgConfig)) + } + // From "~/.config/" directory + var dotconfig: URL = FileManager.default.homeDirectoryForCurrentUser + dotconfig.appendPathComponent(".config") + configLocations.append(dotconfig) + } + + for var location: URL in configLocations { + if #available(macOS 13.0, iOS 16.0, *) { + location.append(components: "swift-format", "config.json") + } else { + location.appendPathComponent("swift-format", isDirectory: true) + location.appendPathComponent("config.json", isDirectory: false) + } + if FileManager.default.fileExists(atPath: location.path) { + do { + let configuration = try configurationLoader.configuration(at: location) + self.checkForUnrecognizedRules(in: configuration) + return configuration + } catch { + diagnosticsEngine.emitError( + "Unable to read configuration for \(location.path): \(error.localizedDescription)") + return nil + } + } + } + // An explicit configuration has not been given, and one cannot be found. // Return the default configuration. return Configuration() From 46b1d475fd4cb038e2c836b2b390a92120dbefaa Mon Sep 17 00:00:00 2001 From: WuerfelDev Date: Wed, 5 Jun 2024 14:30:26 +0200 Subject: [PATCH 2/2] Documentation for global configuration --- Documentation/Configuration.md | 16 ++++++++++++++-- README.md | 18 ++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Documentation/Configuration.md b/Documentation/Configuration.md index 1035286c..6de4c3b5 100644 --- a/Documentation/Configuration.md +++ b/Documentation/Configuration.md @@ -5,7 +5,7 @@ used as a command line tool or as an API. ## Command Line Configuration -A `swift-format` configuration file is a JSON file with the following +A `.swift-format` configuration file is a JSON file with the following top-level keys and values: * `version` _(number)_: The version of the configuration file. For now, this @@ -92,7 +92,7 @@ top-level keys and values: An example `.swift-format` configuration file is shown below. -```javascript +```json { "version": 1, "lineLength": 100, @@ -118,6 +118,18 @@ You can also run this command to see the list of rules in the default $ swift-format dump-configuration +## Global Configuration + +If no `.swift-format` can be found for the current project/file, the configuration directories +are searched for a `swift-format/config.json` file. While the filename is different,the +configuration format stays the same. + +Locations that are searched, in this order: + +- `~/Library/Application Support/swift-format/config.json` +- `$XDG_CONFIG_HOME/swift-format/config.json` +- `~/.config/swift-format/config.json` + ## API Configuration The `SwiftConfiguration` module contains a `Configuration` type that is diff --git a/README.md b/README.md index 6b29d73e..54615583 100644 --- a/README.md +++ b/README.md @@ -167,10 +167,12 @@ subcommands: or off respectively, regardless of whether the output is going to a terminal. -* `--configuration `: The path to a JSON file that contains +* `--configuration `: The path to a JSON file that contains [configurable settings](#configuring-the-command-line-tool) for - `swift-format`. If omitted, a default configuration is use (which - can be seen by running `swift-format dump-configuration`). + `swift-format`. If no file is found, `swift-format` tries to load the json + data as a string, if valid. If the parameter is omitted, a default + configuration is used (which can be seen by running + `swift-format dump-configuration`). * `--ignore-unparsable-files`: If this option is specified and a source file contains syntax errors or can otherwise not be parsed successfully by the @@ -202,14 +204,18 @@ JSON-formatted file named `.swift-format` in the same directory. If one is found, then that file is loaded to determine the tool's configuration. If the file is not found, then it looks in the parent directory, and so on. +If there is no project specific configuration file, the +[config directories](Documentation/Configuration.md#Global-Configuration) +are checked for a `swift-format/config.json` configuration file. + If no configuration file is found, a default configuration is used. The settings in the default configuration can be viewed by running `swift-format dump-configuration`, which will dump it to standard output. -If the `--configuration ` option is passed to `swift-format`, then that -configuration will be used unconditionally and the file system will not be -searched. +If the `--configuration ` option is passed to `swift-format`, +then that configuration will be used unconditionally and the file system will +not be searched. See [Documentation/Configuration.md](Documentation/Configuration.md) for a description of the configuration file format and the settings that are