Skip to content
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

Merged
merged 1 commit into from
Nov 18, 2022
Merged

Support CommandPlugin #449

merged 1 commit into from
Nov 18, 2022

Conversation

zunda-pixel
Copy link
Contributor

@zunda-pixel zunda-pixel commented Nov 9, 2022

Add CommandPlugin for format/lint

@zunda-pixel zunda-pixel mentioned this pull request Nov 9, 2022
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.

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",
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Package.swift Outdated
.plugin(
name: "Lint Source Code",
capability: .command(
intent: .sourceCodeFormatting(),
Copy link
Member

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.

Copy link
Contributor Author

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",
Copy link
Member

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?

Copy link
Contributor Author

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?

Copy link
Member

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 {
Copy link
Member

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).

Copy link
Contributor Author

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 {
Copy link
Member

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.

Copy link
Contributor Author

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")
Copy link
Member

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.

Copy link
Contributor Author

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",
".",
Copy link
Member

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.

Copy link
Contributor Author

@zunda-pixel zunda-pixel Nov 10, 2022

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
Copy link
Member

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).


#endif

@resultBuilder
Copy link
Member

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",
Copy link
Member

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


try format(
tool: swiftFormatTool,
targetDirectories: sourceCodeTargets.map(\.directory).map(\.string),
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I fixed it. 28f9876

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.

Thank you! Waiting for CI results, which will be reported at swiftlang/swift-syntax#1086.

@allevato
Copy link
Member

CI looks good. Can you squash the commits and re-push them so we can keep the history (even after merge) a bit cleaner?

@zunda-pixel
Copy link
Contributor Author

I cleaned up git history.
I don't know git squash well, Is it ok?

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.

This looks great; thank you again for the contribution!

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.

2 participants