Default behavior of "swift format"

Invoking swift format causes the Swift driver to look for the swift-format binary in the toolchain and spawn that with the same args, so if we decided we wanted swift format to do swift package format, we'd need swift-format to be able to distinguish whether it was invoked as swift format or swift-format and then do that invocation. I don't immediately know if the child process's argv reflects that, but it would certainly be worth exploring.

git clang-format (which formats all lines which have changed since a given base commit) refuses to do anything if it would modify a file that already has uncommitted changes.

1 Like

By comparison, based on the documentation of rustfmt, there is not a 1:1 coupling between cargo fmt and rustfmt when invoked without arguments. Invoking rustfmt directly does what swift-format currently does (read from stdin, write to stdout).

7 Likes

Another data point to consider here: Prettier (a code formatted for JS/CSS/HTML and related languages):

  • prettier by itself prints a usage description and exits with code 1.
  • cat foo.js | prettier formats the standard input and prints the formatted code to stdout (with an optional --stdin-filepath argument to configure which parser is inferred for the file)
  • prettier . outputs the formatted content of all files to stdout (although I understand this to be mainly for backwards compatibility)
  • prettier --check . outputs a success/failure message and a list of files that would be modified.
  • prettier --debug-check . reformats the files, then parses them again and compares the ASTs for equality, but doesn’t write anything out. This tells you if you’d hit a formatted bug that would change the meaning of your code.
  • prettier --write . prints out a list of files that were modified.

Also, when connected to a TTY, the last line shows a live-updating path of the current file being processed.

3 Likes

Would swift help format need to display the same global options (e.g. --package-path) as the build, package, run, and test subcommands? The toolchain uses symbolic links:

swift-build -> swift-package
swift-run   -> swift-package
swift-test  -> swift-package

The help description only reserves swift package plugin <verb>, so there should be different namespaces:

  • swift package format to invoke the built-in formatter.
  • swift package plugin format to invoke a command plugin with the format verb.

Existing verbs:


UPDATE: Another reason to use swift package plugin <verb> is that it might have avoided issue swift-format#668.

100% agree that the default behavior here needs to change so that running swift format does what the majority of users would expect.

If that means that swift format and running swift-format the tool have different behavior to preserve existing tools then that’s fine. But as it is today, requiring two flags and a directory makes the language and tooling confusing. It should work like it does in almost every other language with a built in formatter

I also don’t think this should be part of the package sub command as not everyone writing Swift code uses SPM.

Since swift-format predates even the existence of SwiftPM command plugins, it's worth asking if the better intention here is to have it be a top-level "swift command" (aka in the set of "swift run, repl, build, test, package), or should it be treated as a binary that's exposed in the toolchain, but invoked as a package plugin?

My preference would be seeing it exposed as a package manager style command, refining the swift package _format to a full operation, and as an initial flow doing any linting/reporting on mismatches rather than changing any content as a default. I prefer having the scope of what's going to be effected limited within the context of an existing package. This comes from more-than-one mistake invoking something that's purely CLI/directory recursive from the wrong location and stomping on formatting over a MUCH broader area than I intended.

If it works better being a package command plugin, and leveraging that context, then I'd suggest that the binary might be best renamed as well, moving away from swift-format which is set up with the existing tooling to expose top level commands.

This also begs the question of having system-provided built-in SwiftPM command plugins, which I think is desperately needed as well. Like docc-plugin, I think format should be one of those included with the toolchain.

To be clear, I wasn't suggesting that a command plugin be used here, when responding to Konrad's post.

(I assumed that the plugin subcommand might avoid having to rename --configuration to --swift-format-configuration. However, that doesn't seem to be the case, with the latest version of SwiftPM in Xcode 16 beta 6.)


Using git terminology:

  • swift format could remain as the low-level "plumbing" command.
  • swift package format and swift package lint could be the high-level "porcelain" commands.
1 Like

Seems unseemly to expose the plumbing more than the porcelain, no? I'd want to fire the plumber if I tripped on the pipes before I got to the toilet.

5 Likes

That was sort also the the way I was thinking about it - I get (and like) that it's a plumbing command with lots of controls, but it's presented fore-most by being swift-format.

I apologize for assuming incorrectly, but agree strongly that the more prominent the command, the more polish and ease of use it should have, especially to newcomers. As an existing example, docc is clearly a plumbing command as well, and it's not named swift-docc, which I think was a good choice.

1 Like

does this problem really just boil down to swift format squatting on the string “format”, that is motivating the desire to namespace it under swift package format?

i wonder if we might be better off with something like?

swift lint 
swift lint --fix

Yes same issue here as in my team i's the only swift dev the others need to run swift format on generated code. They often complain about the complexity and long runs. Have formatting build in makes it a lot better for them to accept the need for them to run it too.

I do feel I can improve with including formatting inside my codegen tool as that is also swift. I did however not do that as that would require adding formatting as a dependency and needing to build it in the tool. Do you think swift format as an import could be made available too? And while you are add it add swift-syntax maybe? :slight_smile:

2 Likes

Started to use swift format recently and can +1 here, also feel confused so far and think this could be improved.

  • Why there are swift-format and swift format?
  • Why swift format . just won't work?
  • swift package _format will give me a Error: 'blah/blah/blah' is a path to a directory, not a Swift source file. error.
  • swift format lint will just wait for stdin.
  • on top of it swift format . --recursive --in-place will just do nothing and swift-format . --recursive --in-place will work :eyes:

I do get now how things are working, but initial perception is quite strange.

1 Like

If you run swift format you are using it as a plugin to the build tooling. swift-format is a separate command-line tool that can be used for easier scripting and whatnot.

Apple seems to understand it's confusing and there is an open issue on it.

To be clear, this thread is a key part of the discussion that will or won't resolve the issue, so it's entirely appropriate to continue to conversation here. The existence of an open issue doesn't mean that something will just happen.

Oh 100% understood. This thread and that issue are what we have to work with.

(And the radar I guess, but most of us can’t see that.)

2 Likes