-
Notifications
You must be signed in to change notification settings - Fork 229
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
Support CommandPlugin #449
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for starting this! I haven't explored the plugin space much yet but this looks useful to have.
I'll caution you that the previous time I tried adding a plugin, we had to revert it because of CI and Windows-related failures: #424. But that was a build tool plugin that was generated sources to use during swift-format's own build, so that might have been different. Either way, once this is in shape, we'll see if CI has any problems with it. 🤞🏻
Package.swift
Outdated
@@ -33,6 +33,14 @@ let package = Package( | |||
name: "SwiftFormatConfiguration", | |||
targets: ["SwiftFormatConfiguration"] | |||
), | |||
.plugin( | |||
name: "Format Source Code", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove the spaces from the target names and subdirectory names. Names like FormatPlugin
and LintPlugin
would align well with the naming we've used elsewhere.
For the name
argument of the .plugin
, I'm less sure. I believe this surfaces in the Xcode UI? Is there anywhere else that this string is used (like a command line) where spaces would cause problems?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed with reference to swift-argument-parser
zunda-pixel/swift-format/pull/1
Xcode uses Package.targets.plugin.name as UI
Package.swift
Outdated
.plugin( | ||
name: "Lint Source Code", | ||
capability: .command( | ||
intent: .sourceCodeFormatting(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the behavior of swift package format-source-code
when there are two plugins with this intent?
I wonder if we should use something like .custom(verb: "lint-source-code")
here instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed it. https://github.com/zunda-pixel/swift-format/commit/8bcb0bb94af287b080aa5d631360cc24737d9ba0
swift-format$ swift package plugin --list
‘format-source-code’ (plugin ‘Format Source Code’ in package ‘swift-format’)
‘generate-manual’ (plugin ‘Generate Manual’ in package ‘swift-argument-parser’)
‘lint-source-code’ (plugin ‘Lint Source Code’ in package ‘swift-format’)
var swiftFormatArgs = [ | ||
"format", | ||
target.directory.string, | ||
"-r", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and throughout, can you use the --long-form
of the flags instead, so it's easier for a reader to understand when they quickly scan it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know --long-form
. what is this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every flag that has a short form (like -r
) has a longer form (--recursive
). Using the longer ones will make the usage clearer. They're documented here: https://github.com/apple/swift-format#command-line-usage
"-i", | ||
] | ||
|
||
if let configuration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere, let's avoid using new Swift 5.7 syntax for now; Package.swift still specifies a 5.6 tools version, and I'm not sure how it plays with CI (some other projects avoid it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
let configuration = argExtractor.extractOption(named: "configuration").first | ||
|
||
for target in targetsToFormat { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of spawning swift-format
once for each target, it would be more efficient to collect the directory paths in an array and then pass them all at once in the args array to just do a single invocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed It.
|
||
extension FormatSourceCode: XcodeCommandPlugin { | ||
func performCommand(context: XcodeProjectPlugin.XcodePluginContext, arguments: [String]) throws { | ||
let swiftFormatTool = try context.tool(named: "swift-format") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is mostly duplicated from the function above. Can you factor out the commonalities into a file-scoped function and just have the plugins call that?
I think a single function that takes the tool returned by context.tool
, the arguments, and the list of directories to format would do the trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made func format(tool: PluginContext.Tool, targetDirectories: [String], configurationFilePath: String?) throws
https://github.com/zunda-pixel/swift-format/blob/36c8e5bff9a01cb96c5f013ca021f79263f13ea7/Plugins/FormatPlugin/plugin.swift#L6
let swiftFormatExec = URL(fileURLWithPath: swiftFormatTool.path.string) | ||
var swiftFormatArgs = [ | ||
"format", | ||
".", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the XcodePluginContext
you can reach through context.xcodeProject.directory
, which might be safer than assuming the working directory of the plugin will always be the project directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,92 @@ | |||
import PackagePlugin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments from the Format Source Code file apply here (factoring out the common implementations, making a single invocation to swift-format, accessing the Xcode project directory).
Plugins/FormatPlugin/plugin.swift
Outdated
|
||
#endif | ||
|
||
@resultBuilder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like overkill; I don't think it improves the readability much. Let's just use regular array construction/appending above; it's more obvious to the reader what's going on without having to look for the builder (which has to be repeated in both plugins).
var swiftFormatArgs = [ | ||
"format", | ||
target.directory.string, | ||
"-r", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every flag that has a short form (like -r
) has a longer form (--recursive
). Using the longer ones will make the usage clearer. They're documented here: https://github.com/apple/swift-format#command-line-usage
Plugins/FormatPlugin/plugin.swift
Outdated
|
||
try format( | ||
tool: swiftFormatTool, | ||
targetDirectories: sourceCodeTargets.map(\.directory).map(\.string), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be combined into a single map call, map(\.directory.string)
? That would avoid unnecessary array allocations.
Same in the lint plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed it. 28f9876
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Waiting for CI results, which will be reported at swiftlang/swift-syntax#1086.
CI looks good. Can you squash the commits and re-push them so we can keep the history (even after merge) a bit cleaner? |
I cleaned up git history. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great; thank you again for the contribution!
Add CommandPlugin for format/lint