Skip to content

Conversation

andre-richter
Copy link
Contributor

closes #667

Implement the subcommand dump-effective-configuration, which dumps the configuration that would be used if swift-format was executed from the current working directory (cwd), incorporating configuration files found in the cwd or its parents, or input from the --configuration option.

This helps when composing a configuration or with configuration debugging/verification activities.

Copy link
Member

@allevato allevato left a comment

Choose a reason for hiding this comment

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

A high-level suggestion before I review this further: Since this is so similar to the existing dump-configuration command, I think this would be expressed more simply as an optional flag for that command instead of a completely separate command. Something like dump-configuration --effective would work and would probably cut down on the implementation complexity here.

@andre-richter
Copy link
Contributor Author

I thought about this initially, and wasn't happy that it would need to be explained that the --configuration option will only be valid in combination with the --effective flag, so I went with separate subcommand.

I'll give merging this into the dump-config subcommand a try and amend it to this PR.

@andre-richter
Copy link
Contributor Author

@allevato implemented your change request.

@ahoppen
Copy link
Member

ahoppen commented Feb 6, 2025

I’m curious what the real-world use case for that options is. swift-format doesn’t have a complicated search algorithm to find the format files (it just walks up the directory structure) and it doesn’t merge files either. So, IIUC, all this effectively does is to find the first .swift-format file in the directory structure and print it. Am I missing something?

@allevato
Copy link
Member

allevato commented Feb 7, 2025

I’m curious what the real-world use case for that options is. swift-format doesn’t have a complicated search algorithm to find the format files (it just walks up the directory structure) and it doesn’t merge files either. So, IIUC, all this effectively does is to find the first .swift-format file in the directory structure and print it. Am I missing something?

I'm not sure of the PR author's motivation, but one thought I've had in the past is that if we ever make a breaking change to the configuration and bump the version number, it would be nice to have a way for users to explicitly update their configuration to the new version. One way to handle that would be an option like this: since older versions of the config would be translated to the new model in-memory during decoding, printing back that in-memory model afterwards would render it as the latest version.

@andre-richter
Copy link
Contributor Author

andre-richter commented Feb 7, 2025

Sure, let me elaborate a bit on the motivation:

  • Closing a feature gap with similar tools like clang-format. Or git config -l as mentioned by the author of Add command to show the current configuration #667. For both examples, the default behavior is actually what --effective would do here (I am not implying this is a better or worse default).

  • What @allevato said. To extend on this: In general, having a quick way to verify that the configuration you're entering into the tool is actually being processed by the tool as intended is beneficial. This typically would be used while you're in the process of composing or modifying a .swift-format file or a --configuration JSON-string.

  • Tools or scripts that wrap around swift-format likely pass the configuration to the tool using the --configure option. --effective would allow authors of such wrappers to easily add an option to print the final configuration that would be used by swift-format, so that users get an option to easily retrieve it for review or re-use.

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks for your explanation of the use case @andre-richter. The change makes sense to me. I have a few comments regarding the implementation inline.

Comment on lines 53 to 57
let frontend = DumpConfigurationFrontend(
configurationOptions: configurationOptions,
lintFormatOptions: lintFormatOptions
)
frontend.run()
Copy link
Member

Choose a reason for hiding this comment

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

I’m not a big fan of running a dummy frontend that stores the configuration used as a side effect. I’d prefer to just call into Frontend.configuration(fromPathOrString:orInfoerredFromSwiftFileAt:) instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean by turning Frontend.configuration static somehow? Asking because the current implementation uses instance properties such as diagnosticsEngine.

Adding a dummy fronted seemed the least intrusive change for existing code to me, but I’m happy to make adaptions if needed.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, looks like it shouldn’t be too hard. It looks like ConfigurationLoader can be a local variable instead of a member and DiagnsoticsEngine can be passed in.

@andre-richter
Copy link
Contributor Author

@ahoppen, there was also checkForUnrecognizedRules(), which also employs a DiagnosticsEngine. Since Frontend.configuration() was the only user, passing DiagnosticsEngine references around in arguments several levels deep would have made the code quite convoluted in my opinion.

Therefore, I decided to carve out the whole configuration resolution logic into its own helper struct that saves a DiagnosticsEngine reference . I believe this also enhanced the frontend design slightly because it leads to a clearer division of responsibilities.

closes swiftlang#667

Implement the subcommand `dump-effective-configuration`, which dumps
the configuration that would be used if `swift-format` was executed
from the current working directory (cwd), incorporating configuration
files found in the cwd or its parents, or input from the
`--configuration` option.

This helps when composing a configuration or with configuration
debugging/verification activities.
Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks for addressing my comments @andre-richter, this seems a lot cleaner to me. I have a few more questions/comments inline.

Comment on lines +21 to +22
/// Loads formatter configuration files and chaches them in memory.
private var configurationLoader: ConfigurationLoader = ConfigurationLoader()
Copy link
Member

Choose a reason for hiding this comment

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

Actually, I don’t think this needs to be a member at all. A local variable in provide should be sufficient, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It stores the cache of previously loaded configurations. So it wouldn't work as a local variable (as in: stack-allocated inside provide, if that is what you meant?).

Comment on lines +19 to +20
/// Provides formatter configurations for given `.swift` source files, configuration files or configuration strings.
struct ConfigurationProvider {
Copy link
Member

Choose a reason for hiding this comment

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

Just wondering: Would it be simpler if we just had a static method (or global function) like func configuration(forConfigPathOrString pathOrString: String?, orForSwiftFileAt swiftFileURL: URL?, diagnosticsEngine: DiagnosticsEngine) and then either make checkForUnrecognizedRules a nested function or make it take a DiagnosticsEngine as well? To me, having a type here implies that there is some state being stored, which isn’t actually the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To me, having a type here implies that there is some state being stored, which isn’t actually the case.

There is state being stored in the form of configurationLoader, which stores the cache for previously loaded configs.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see. Fair enough then.

@ahoppen ahoppen enabled auto-merge February 14, 2025 00:17
auto-merge was automatically disabled February 14, 2025 16:34

Head branch was pushed to by a user without write access

@ahoppen ahoppen enabled auto-merge February 14, 2025 16:39
@ahoppen ahoppen merged commit 26930a6 into swiftlang:main Feb 14, 2025
19 checks passed
@andre-richter andre-richter deleted the dump-effective-conf branch February 14, 2025 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add command to show the current configuration
3 participants