>_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
dotnetCLI must be on$PATHand must support thedotnet completesubcommand (shipped by all modern SDK versions). Withoutdotnetinstalled, the completion callback returns nothing and the$HOME/.dotnet/toolsPATH 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.
| dt | dotnet test |
| dr | dotnet run |
| dcl | dotnet 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. Ifdotnetisn't on$PATH, the callback has nothing to call. - Plugin not loaded. Verify the callback is bound:
compctl | grep dotnetshould show_dotnet_zsh_complete. If not, the plugin file wasn't sourced — start a fresh zsh session after install. - Aliases missing.
alias dt dr dclshould print the three expansions. Re-source the plugin if they're absent. - Global tools not found.
$HOME/.dotnet/toolsis only added to$PATHif 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:
- zsh-better-npm-completion — cache-aware
npm installcompletion - zsh-cargo-completion — live
cargo add/cargo installcompletion - zsh-cpan-completion — live MetaCPAN
cpan/cpanmcompletion - zsh-expand — spacebar expansion (11,683 tests)
- zsh-gem-completion — ruby
gem installremote completion - zsh-git-acp — 159 git aliases + add/commit/push keybindings
- zsh-git-repo-cache — index every git repo on disk
- zsh-learn — MySQL-backed learning collection / quiz
- zsh-more-completions — 33,175-file mega completion corpus
- zsh-nginx — nginx commands + service-wrapper aliases
- zsh-pip-description-completion — pip remote completion with descriptions
- zsh-sed-sub — in-place sed substitution on the command line
- zsh-sudo — ESC ESC to prepend sudo
- zsh-xcode-completions — xcodebuild / xcrun / swift completion