Hidden Gems in the Swift Argument Parser - Part I

Published: August 15, 2025
Written by:
Natan Rolnik
Natan Rolnik

Previously, we’ve covered in our Argument Parser Guide and other posts the basics of the Swift Argument Parser, showing you how to build tools with it and use all the customizations it offers: commands, subcommands, arguments, options, and flags.

In this first of two posts, we’ll explore some lesser-known features that the argument parser provides to the tools using it.

This post will focus on how you can generate completion scripts from any tool built with the argument parser, and install them. Additionally, if you have your own tools, either private or open source, you’ll learn how to customize the completion suggestions to make them even more useful!

Generating Completion Scripts

Every CLI tool backed by the argument parser receives, by default, a command that generates the files needed to enable shell completion, depending on the shell you’re using. The command --generate-completion-script will print to the standard output the completion script for the shell you’re using, supporting Bash, Zsh and Fish.

For example, for Swift’s official swift-format tool (which you can install with brew install swift-format), you can generate the completion script for Zsh with the following command:

swift-format --generate-completion-script zsh

This is how the output looks like:

The Zsh completion scripts for swift-format
The Zsh completion scripts for swift-format

The greater the number of commands and arguments, the longer this output will be. It contains methods that will be called by the running shell and will be responsible for suggesting the next arguments and options to the user.

Installing Completion Scripts

While you can copy and paste the output manually, you can also redirect it to a file using the > operator in the folder where the shell will look for the completion scripts.

Since the default shell in macOS is Zsh, we’ll focus on it in this post - natively or with oh-my-zsh. If you’re using a different shell, such as Bash or Fish, the process will be similar.

Zsh

For a regular Zsh shell, without oh-my-zsh, you need to add the completion scripts in the ~/.zsh/completion folder. If it doesn’t exist yet, create it first:

mkdir -p ~/.zsh/completion

Then, redirect the output to the file:

swift-format --generate-completion-script zsh > ~/.zsh/completion/_swift-format

Finally, if this is your first time using completion scripts, you’ll need to configure your ~/.zshrc file and tell Zsh where to look for the completion scripts, and initialize the completion system. Open the ~/.zshrc file in the text editor of your choice, and add the following lines:

fpath=(~/.zsh/completion $fpath)
autoload -U compinit
compinit

oh-my-zsh

For oh-my-zsh, you can place it in the ~/.oh-my-zsh/completions folder. If it doesn’t exist yet, create it first:

mkdir -p ~/.oh-my-zsh/completions

Then, redirect the output to the file:

swift-format --generate-completion-script zsh > ~/.oh-my-zsh/completions/_swift-format

Completions in Action

Once you have installed the completion scripts, you can test them by reloading the shell by running source ~/.zshrc first or by opening a new terminal. Whenever you hit the Tab key, the shell will suggest the available commands or arguments.

This is what you get when using completion scripts for both swift-format and tuist:

Improving Completion Suggestions

If you own a tool that uses the argument parser, you can make the code completion experience even better by specifying what type of completion suggestions a property is associated with.

For example, if you have an input argument or option, you might want only file paths to be suggested, and not directories. You can do so by using the completion parameter of the property wrapper:

@Option(help: "The input file to process", completion: .file())
var input: String

Similarly, if you want only a directory to be scanned (or a directory to be used as output):

@Option(help: "The directory to scan", completion: .directory())
var directory: String

The last option is a set of values. For example, if you have a format property that can be json, yaml or xml, you can use the following API:

@Option(help: "The output format", completion: .values(["json", "yaml", "xml"]))
var format: String

If you prefer using enums, you get this functionality for free if you conform your String or numeric enum to CaseIterable and ExpressibleByArgument.

enum OutputFormat: String, CaseIterable, ExpressibleByArgument {
    case json, yaml, xml
}

@Option(help: "The output format")
var format: OutputFormat

Reader Feedback

As commented by Danny Mösch, when installing Swift command-line tools with Homebrew, the completion scripts are generated automatically! The only requirement is to enable completion support once, as the Homebrew documentation explains.

Explore Further

If you are a user or a developer of a tool, having better completion with CLIs improves the developer experience significantly!

You can check out the official documentation to learn more about the completion scripts.

The second part of this series covers manual page and Docc generation, and also the ArgumentParserInfo library.

If you haven’t yet checked out our Argument Parser Guide, go ahead and explore the live terminal simulators to understand how the argument parser works!

See you at the next post. Have a good one!
Swift, Xcode, the Swift Package Manager, iOS, macOS, watchOS and Mac are trademarks of Apple Inc., registered in the U.S. and other countries.

© Swift Toolkit, 2024-2025