// ZSH-DOTNET-COMPLETION — TAB COMPLETION FOR THE dotnet CLI

zsh plugin · completion for the dotnet CLI

GitHub Issues
// Color scheme

>_ZSH-DOTNET-COMPLETION

dotnet, completed. Tab completion for the dotnet command-line tool. Source the plugin, restart zsh, hit TAB after dotnet. The plugin is 15 lines of zsh: it wires the SDK's own dotnet complete completer into zsh's legacy compctl system, registers three workflow aliases, and conditionally appends $HOME/.dotnet/tools to $PATH.

Overview

The .NET SDK ships its own completion engine. dotnet complete "<command line>" returns the candidate list for the current command line — subcommands, templates, NuGet packages, flag values — all computed by the SDK against the actual project in the current directory. This plugin does not maintain its own completion table; it forwards the SDK's output into zsh. The practical effect: every time you update the .NET SDK, completion updates with it. No plugin bump is needed when Microsoft adds a subcommand, a template, or a framework target.

The plugin uses zsh's legacy compctl -K callback binding rather than the modern compsys (#compdef / _arguments) framework, because dotnet complete returns a raw newline-separated candidate list that maps directly onto compctl's reply-array contract.

Requirements

  • zsh — the plugin is sourced as a zsh startup file.
  • .NET SDK — the dotnet CLI must be on $PATH and must support the dotnet complete subcommand (shipped by all modern SDK versions). Without dotnet installed, the completion callback returns nothing and the $HOME/.dotnet/tools PATH append is skipped (the directory won't exist).

Install

# Zinit
zinit ice lucid nocompile
zinit load MenkeTechnologies/zsh-dotnet-completion

# Oh My Zsh
git clone https://github.com/MenkeTechnologies/zsh-dotnet-completion \
    "$HOME/.oh-my-zsh/custom/plugins/zsh-dotnet-completion"
# then: plugins+=(zsh-dotnet-completion)

# Manual
git clone https://github.com/MenkeTechnologies/zsh-dotnet-completion
source zsh-dotnet-completion/zsh-dotnet-completion.plugin.zsh

After sourcing, start a new zsh session (or re-source your ~/.zshrc) and press TAB after dotnet.

How it works

The entire plugin is four surfaces in one file:

# 1. Guarded PATH append — only if the tools dir exists
if [[ -d "$HOME/.dotnet/tools" ]]; then
    export PATH="$PATH:$HOME/.dotnet/tools"
fi

# 2. Completion callback — delegate to the SDK's own completer
_dotnet_zsh_complete() {
  local completions=("$(dotnet complete "$words")")
  reply=( "${(ps:\n:)completions}" )
}

# 3. Workflow aliases
alias dt='dotnet test'
alias dcl='dotnet clean'
alias dr='dotnet run'

# 4. Bind the callback to the dotnet command
compctl -K _dotnet_zsh_complete dotnet

compctl -K _dotnet_zsh_complete dotnet tells zsh to call _dotnet_zsh_complete whenever TAB is pressed on a dotnet command line. The callback runs dotnet complete "$words" ($words is the current command line as a single argument), then splits the newline-separated result into the reply array using zsh's (ps:\n:) parameter-expansion flag. zsh presents the reply entries as the completion menu.

Aliases

Three shortcuts for the most-typed developer-workflow subcommands. These are the only aliases the plugin registers — it does not try to shadow every dotnet subcommand.

dtdotnet test
drdotnet run
dcldotnet clean

PATH augmentation

dotnet tool install --global <tool> installs binaries into $HOME/.dotnet/tools. The plugin appends that directory to $PATH — but only if it exists ([[ -d "$HOME/.dotnet/tools" ]]), so on hosts without the SDK the plugin adds no phantom PATH entry. The directory is appended, not prepended ($PATH:$HOME/.dotnet/tools), so a global dotnet tool can never shadow a same-named binary earlier on $PATH. If you want tool precedence, re-order in ~/.zshrc after sourcing the plugin.

Examples

The candidate lists below come from the SDK's dotnet complete output, not from a table inside this plugin — the exact entries depend on your installed SDK version and the project in the current directory.

dotnet <TAB>           # subcommand completion: new, build, run, test, restore, add, ...
dotnet new <TAB>       # template completion (console, classlib, web, webapi, ...)
dotnet add <TAB>       # add subcommands; dotnet add package <TAB> queries NuGet sources
dotnet build -c <TAB>  # configuration completion (Debug / Release)

Alias usage:

dt          # runs: dotnet test
dr          # runs: dotnet run
dcl         # runs: dotnet clean

Troubleshooting

  • No completions appear. Confirm the SDK supports the completer: dotnet complete "dotnet " should print a candidate list. If dotnet isn't on $PATH, the callback has nothing to call.
  • Plugin not loaded. Verify the callback is bound: compctl | grep dotnet should show _dotnet_zsh_complete. If not, the plugin file wasn't sourced — start a fresh zsh session after install.
  • Aliases missing. alias dt dr dcl should print the three expansions. Re-source the plugin if they're absent.
  • Global tools not found. $HOME/.dotnet/tools is only added to $PATH if it exists when the plugin is sourced. Install a tool first (dotnet tool install --global <tool>), then start a new shell.

For internals, the line-by-line plugin breakdown, the test matrix, and design tradeoffs, see the Engineering Report.

Sibling plugins

Part of the MenkeTechnologies zsh plugin family — the MenkeTechnologiesMeta umbrella: