Skip to content

Support async custom completion functions for AsyncParsableCommand via async/await#855

Merged
natecook1000 merged 3 commits intoapple:mainfrom
rgoldberg:852-async-custom-completions
Apr 6, 2026
Merged

Support async custom completion functions for AsyncParsableCommand via async/await#855
natecook1000 merged 3 commits intoapple:mainfrom
rgoldberg:852-async-custom-completions

Conversation

@rgoldberg
Copy link
Copy Markdown
Contributor

@rgoldberg rgoldberg commented Jan 16, 2026

  • Support async custom completion functions for AsyncParsableCommand via async/await.
    • Resolve Hangs for async custom completions #852.
    • No longer use DispatchSemaphore, so more modern standards compliant & will work for platforms that do not have DispatchSemaphore.
    • The existing DispatchSemaphore implementation hangs when any async custom completions run if the root command is a sync ParsableCommand; async custom completions do not hang because of DispatchSemaphore if the root command is an AsyncParsableCommand, regardless if the command containing the property for the completing argument is a sync ParsableCommand or an AsyncParsableCommand.
    • Async custom completions are thus not supported for root ParsableCommand.
  • Make some related code more concise & consistent.
  • Improve ParsableArguments#_errorLabel DocC (unrelated, but just noticed it should be improved).

A few potential issues with / questions about what you want from this PR:

  • Async custom completions are supported only for AsyncParsableCommand root commands.
    • That seems OK to me because:
      • The existing implementation doesn't support root sync ParsableCommand.
      • I doubt there's any penalty to switch a root command from ParsableCommand to AsyncParsableCommand, since Swift Concurrency must be available, since the code is trying to use an async function for completion.
  • If the root command is a sync ParsableCommand, a ParserError.invalidState is thrown during runtime when completion candidates are requested from an async custom completion function.
    • Do you want this detected at build time or completion script generation time?
      • If so, are there any utilities to facilitate detection at build time or completion script generation time?
    • Do you want a different error?
  • Is the minor cleanup for tangentially related code acceptable here?
  • Is the unrelated DocC update acceptable here?

Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary

@rgoldberg rgoldberg marked this pull request as ready for review January 16, 2026 13:05
@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch from b258097 to 5abed1e Compare January 18, 2026 14:03
@rgoldberg
Copy link
Copy Markdown
Contributor Author

Are there any changes that you would like for this PR?

@rgoldberg rgoldberg mentioned this pull request Mar 12, 2026
4 tasks
@natecook1000
Copy link
Copy Markdown
Member

If the root command is a sync ParsableCommand, a ParserError.invalidState is thrown during runtime when completion candidates are requested from an async custom completion function.

This should be detected at build time, if possible. There are a series of validators in the Validators directory that you can add to – they run on every execution in debug mode and effectively act as runtime compilation errors.

@rgoldberg
Copy link
Copy Markdown
Contributor Author

Thanks. I'll look into Validators soon, then add the check.

@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch 3 times, most recently from 613d0b2 to a0a6d77 Compare March 19, 2026 16:21
@rgoldberg
Copy link
Copy Markdown
Contributor Author

rgoldberg commented Mar 19, 2026

@natecook1000 I've added AsyncCompletionsValidator & tests for it.

I've rebased on current main.

Is there any way in the longterm to change SAP to run some or all of the ParsableArgumentsValidators via build plugins, so they always run at build time (for debug, release, whatever…) instead of requiring subsequent tests on a debug build?

If possible, I'll log an issue.

@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch from a0a6d77 to ed816dd Compare March 20, 2026 12:25
@natecook1000 natecook1000 added the additive change A change that requires a minor version increase label Mar 20, 2026
@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch 4 times, most recently from 858faf7 to 75c00d6 Compare March 23, 2026 16:15
@natecook1000 natecook1000 added this to the ArgumentParser 1.8.0 milestone Mar 24, 2026
try parse(try self.asCommand.parseAsRoot(arguments))
}

public static func parse(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@rgoldberg Is this intended to be public API? Could you add documentation to explain/show the intended use?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this. Sorry for overlooking it.

I just pushed a change that makes this internal instead of public (a new push after my recent rebase).

Is there any way to run various SAP CI checks locally other than using https://github.com/nektos/act, so I can avoid wasting your time?

If so, how? If not, I'll look into using act (I've heard of act, but haven't yet used it); if you have any act configuration for SAP, please let me know (and maybe it could be included in the repo).

Currently, I just run:

command Scripts/format.sh
swift test

Am I missing anything?

Thanks.

@natecook1000
Copy link
Copy Markdown
Member

Is there any way in the longterm to change SAP to run some or all of the ParsableArgumentsValidators via build plugins, so they always run at build time (for debug, release, whatever…) instead of requiring subsequent tests on a debug build?

I haven't written any build plugins, but from scanning the documentation it doesn't seem like an exact fit. A post-build plugin could be perfect, if such a thing existed? But if I'm wrong and there's a path to this, that would be great!

Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch from 75c00d6 to 03a03b3 Compare April 6, 2026 15:44
@rgoldberg
Copy link
Copy Markdown
Contributor Author

I think the build failures were because I needed to rebase on current main. Just pushed my rebase, so hopefully all checks should succeed now.

I'll look into your review comments, then push updated code; I just wanted to push my rebase first (without having yet addressed your comments) so we could find any other issues that CI might detect.

I've written one build plugin. It generated virtual Swift source before the rest of the code was compiled. I don't know all the options for build plugins; I'll try to take a cursory look, then get back to you, but it might be a bit before I can dedicate time to properly research. I don't know everything that AsyncCompletionsValidators require, etc.

Thanks for reviewing this.

…a async/await.

Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
@rgoldberg rgoldberg force-pushed the 852-async-custom-completions branch from 03a03b3 to 8c0d240 Compare April 6, 2026 16:00
@rgoldberg
Copy link
Copy Markdown
Contributor Author

If I need to do anything to fix the 2 CI failures, please let me know, & I'll fix things & resubmit.

The failures look like Docker failures that seem likely outside the scope of my PR's changes, though.

@natecook1000
Copy link
Copy Markdown
Member

Those passed in previous runs – merging to unblock the next bits. Thanks, @rgoldberg! 👏🏻👏🏻👏🏻

@natecook1000 natecook1000 merged commit d6f4e7a into apple:main Apr 6, 2026
31 of 33 checks passed
@rgoldberg rgoldberg deleted the 852-async-custom-completions branch April 6, 2026 18:45
@rgoldberg
Copy link
Copy Markdown
Contributor Author

Thanks for reviewing & merging.

I will try to submit some fish shell improvements soon. I'll try to polish those up in time for 1.8.0.

If Tool Info V1 is merged (see #817), I can update completions to use that instead of V0 to save you guys the work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

additive change A change that requires a minor version increase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hangs for async custom completions

2 participants