@@ -23,8 +23,9 @@ fileprivate func main(_ arguments: [String]) -> Int32 {
2323 switch options. mode {
2424 case . format:
2525 var ret = 0
26- let configuration = decodedConfiguration ( fromFileAtPath: options. configurationPath)
2726 for path in options. paths {
27+ let configuration = loadConfiguration (
28+ forSwiftFile: path, configFilePath: options. configurationPath)
2829 ret |= formatMain (
2930 configuration: configuration,
3031 path: path,
@@ -34,8 +35,9 @@ fileprivate func main(_ arguments: [String]) -> Int32 {
3435 return Int32 ( ret)
3536 case . lint:
3637 var ret = 0
37- let configuration = decodedConfiguration ( fromFileAtPath: options. configurationPath)
3838 for path in options. paths {
39+ let configuration = loadConfiguration (
40+ forSwiftFile: path, configFilePath: options. configurationPath)
3941 ret |= lintMain ( configuration: configuration, path: path)
4042 }
4143 return Int32 ( ret)
@@ -48,6 +50,41 @@ fileprivate func main(_ arguments: [String]) -> Int32 {
4850 }
4951}
5052
53+ /// Load the configuration.
54+ private func loadConfiguration(
55+ forSwiftFile swiftFilePath: String , configFilePath: String ?
56+ ) -> Configuration {
57+ if let path = configFilePath {
58+ return decodedConfiguration ( fromFileAtPath: path)
59+ }
60+ else {
61+ // Search for a ".swift-format" configuration file in the directory of the current .swift file,
62+ // or its nearest parent.
63+ let swiftFileDir = URL ( fileURLWithPath: swiftFilePath)
64+ return decodedConfiguration (
65+ fromFileAtPath: findConfigurationFile ( forSwiftFile: swiftFileDir. path) )
66+ }
67+ }
68+
69+ /// Look for a ".swift-format" configuration file in the same directory as "forSwiftFile", or its
70+ /// nearest parent. If one is not found, return "nil".
71+ private func findConfigurationFile( forSwiftFile: String ) -> String ? {
72+ let cwd = FileManager . default. currentDirectoryPath
73+ var path = URL (
74+ fileURLWithPath: AbsolutePath ( forSwiftFile, relativeTo: AbsolutePath ( cwd) ) . asString)
75+ let configFilename = " .swift-format "
76+
77+ repeat {
78+ path = path. deletingLastPathComponent ( )
79+ let testPath = path. appendingPathComponent ( configFilename) . path
80+ if FileManager . default. isReadableFile ( atPath: testPath) {
81+ return testPath
82+ }
83+ } while path. path != " / "
84+
85+ return nil
86+ }
87+
5188/// Loads and returns a `Configuration` from the given JSON file if it is found and is valid. If the
5289/// file does not exist or there was an error decoding it, the program exits with a non-zero exit
5390/// code.
0 commit comments