Use swift-format provided by Xcode as a Xcode plugin

Hi,

Is it possible to use swift-format (provided by Xcode) as a Xcode plugin?

Xcode version: 26.2 (17C52)

import PackagePlugin

@main
struct swift_format_plugin: BuildToolPlugin {
  func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
    return []
  }
}

#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin

extension swift_format_plugin: XcodeBuildToolPlugin {
  func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
    let directoryURL = context.xcodeProject.directoryURL;
    let configFile = directoryURL.appending(path: ".swift-format")
    return [
      .buildCommand(
        displayName: "Run swift format(xcode)",
        executable: try context.tool(named: "swift").url,
        arguments: [
          "format",
          "lint",
          "--configuration",
          configFile.path(),
          "-r",
          ".",
        ],
        inputFiles: [],
        outputFiles: []
      )
    ]
  }
}
#endif

I had used the following reference:

It seems to show the warnings but however doesn't make code changes.

Questions:

  1. Am I missing something?
  2. How can I fix it to ensure code gets changed instead of just showing warnings?
  3. Do I need write permissions or is there a way of requesting them?
1 Like

afaicr built tools aren’t allowed to alter source files anymore for security reasons

what code generators do is emit into the generated source directory (this change broke swiftgen at some point iirc)

what you can do instead is either add a shortcut to run swiftformat on save or perhaps a githook that runs format on commit (if your using git)


edit: it seems build tools cant but custom commands may work

Custom command plugins that need to modify the package source code can specify this requirement. If the user approves, package manager grants write access to the package directory. Build tool plugins can’t modify the package source code.

from:

https://docs.swift.org/ Swift Package Manager / Plugins

1 Like

Thanks a lot @andrekandore

Do you mean command plugins might be able to modify the source code?

might be, never tried myself but from the linked documentation it looks possible

i assume that a custom command plugin though dont run at built-time, so its not much better than a standalone script perhaps..

from the same doc:

Command Plugin
Custom commands that you run using the swift package command line interface.

and at

docs.swift.org / packagemanagerdocs / writingcommandplugin

it states

A command plugin specifies the semantic intent of the command — this might be one of the predefined intents such as “documentation generation” or “source code formatting”

so looks like thats the intended method for formatting..

1 Like

Thanks a lot @andrekandore! I will check the link.

Right now I have added a Run script build phase and I am doing the listing there. So it runs every time I compile. I have removed Sandbox for the run script.

I am not sure if it the right way, but works.

The only problem is when I am refactoring large amounts of code, the linter updates the code and sometimes there is that warning if you want to load from disk

There’s a few available out there, one I’ve used: GitHub - StarLard/SwiftFormatPlugins: Swift package plugins for Apple's swift-format tools

Also looks good: GitHub - Snapp-Mobile/SwiftFormatLintPlugin: A reusable Swift Package Manager plugin that integrates swift-format linting and formatting into your workflow

1 Like

Thanks a lot @markturnip!! will try that!

Speaking of formatting code in place via "swift-format", when would I need Xcode plugin instead of a build phase (e.g. as done here, changing the formatting string from lint to format --in-place and moving the build phase to happen before "Compile Sources"?

1 Like

Thanks @tera, I have some doubts

My understanding is (correct me if I am wrong):

  • format and lint are different, format does the code formatting, while linting can flag something like forced unwrap (if turned on)

Questions:

  1. Is Xcode Plugin (Run plug in Build Phase) is preferred over run script in Build phase?
  2. If so what benefits are there over the other?
  3. Is linting and formatting distinct or just doing linting will also do the formatting?

Correct.

These are the ones I don't know yet and would love an answer to. From my tests, both "lint" and "format" could be done either as a build phase or in Xcode plugin.

Yeah, they are different. Some things you could both "lint" (show warnings about) and "format" (autocorrect), while some other things you could only "lint" (show warnings about).

1 Like

Thanks a lot @tera for those clarifications