Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search for configuration in config directories (dotfiles, etc) #749

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Documentation/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -92,7 +92,7 @@ top-level keys and values:

An example `.swift-format` configuration file is shown below.

```javascript
```json
{
"version": 1,
"lineLength": 100,
Expand All @@ -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`
Comment on lines +129 to +131

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to see $XDG_CONFIG_HOME / ~/.config first here. What's the thinking behind looking first in ~/Library/Application Support?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the default path for configuration files on MacOS


## API Configuration

The `SwiftConfiguration` module contains a `Configuration` type that is
Expand Down
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,12 @@ subcommands:
or off respectively, regardless of whether the output is going to a
terminal.

* `--configuration <file>`: The path to a JSON file that contains
* `--configuration <file|string>`: 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
Expand Down Expand Up @@ -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 <file>` option is passed to `swift-format`, then that
configuration will be used unconditionally and the file system will not be
searched.
If the `--configuration <file|string>` 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
Expand Down
55 changes: 54 additions & 1 deletion Sources/swift-format/Frontend/Frontend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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()
Expand Down