Zsh zstyle: Match Completion Policy to Command Context
Use zstyle context patterns to tune Zsh completion by command, argument, and match tag without rewriting completer functions or leaking global policy.
Zsh’s completion system separates the code that generates candidates from the policy that decides how those candidates are presented and filtered. zstyle is the configuration interface for that policy. A style is a named value, such as menu, matcher-list, or verbose, associated with a context pattern. Completion functions query styles while they run, so one shell can use different behavior for command names, options, files, jobs, or a particular subcommand without replacing the completion function itself.
This is a different task from writing a completion function. A function describes how to discover candidates; a style configures behavior at a point where the function consults that style. If a completion function never asks for a particular style, adding a zstyle line cannot make it honor that setting. Treat style names and tags as the completion system’s documented interface, not as a universal set of options shared by every function.
Understand the context string
The completion system builds a context as the cursor position becomes meaningful. The standard context contains colon-separated fields in this order: :completion:function:completer:command:argument:tag. Some fields can be empty, but their separators remain. The function field describes a completion widget when relevant; the completer field describes the current strategy; the command field can include a subcommand; the argument field identifies the position; and the tag classifies candidate types such as files, directories, jobs, or processes.
Styles match these contexts through patterns. For example, Zsh documents a command-specific setting for the kill completion:
zstyle ':completion:*:*:kill:*:*' verbose no
zstyle ':completion:*:*:kill:*:jobs' verbose no
The first pattern affects the verbose style for matching kill contexts; the second narrows the policy to the jobs tag. In this system, a tag is not merely a label shown to the user. It can select a different configuration branch because completion code queries styles with the context currently in use.
Do not construct patterns by guessing the number of colons. Start with a working configuration from the manual or the completion function’s documentation, then narrow one field at a time. A pattern that is too broad may affect contexts that happen to reuse the same style name. A pattern that is too narrow may never match because a context field is different from the one you assumed.
Prefer a narrow policy before a global default
An intentionally broad style can establish a default across the completion system:
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
zstyle ':completion:*:default' menu select=2
The matcher example makes lowercase input match uppercase candidates in contexts where the completion functions use matcher-list. The menu style controls menu selection behavior for a default completion tag. These are still completion-specific policies because the pattern starts with :completion:. A bare * would match more than completion contexts and could collide with other zstyle users in the shell or loaded modules.
For a command-specific exception, define a more specific context pattern:
zstyle ':completion:*:*:kill:*:*' verbose no
The specificity rule matters more than the order in which lines appear. The style lookup chooses the best-fitting context pattern for the queried style; a more specific pattern can override a general default even if the general rule was defined later. This makes policy easier to read when the defaults and exceptions are grouped by intent rather than ordered as an imperative sequence.
Use compinstall to configure common settings when its generated choices cover the requirement. For project or team dotfiles, keep custom zstyle lines together in a documented completion configuration section, after the relevant completion initialization is guaranteed to run. If a startup file returns early before compinit, the style might be defined in a context where the user never actually initialized the functions that query it.
Know what styles and tags actually do
The completion manual distinguishes styles from tags: styles control how completion is performed, while tags describe the kind of match currently being generated. A tag-order style can ask a function to group or prioritize tags; a matcher-list style can alter matching rules; menu affects selection; format influences descriptions. Their precise effect depends on the completion function and the stage at which it checks the style.
# Inspect current style definitions rather than guessing which file set them.
zstyle -L
# A scoped policy can be removed by its pattern and style name.
zstyle -d ':completion:*:*:kill:*:*' verbose
The listing is useful when a framework has loaded a large collection of settings. Search for the exact style and pattern, then compare it with the context used by the completion function. Deleting a style is a configuration change, so test the resulting behavior in a clean shell before editing several startup files. A plugin may re-add the definition during later initialization.
Not every tag applies to every command. The jobs and processes tags in the manual’s kill example are meaningful because the completion function can generate those classes of candidates. If a command only produces files, a process-specific setting will have no visible effect. Consult the relevant completion function’s documentation or source to see which tags and styles it uses.
Use dynamic styles sparingly
zstyle -e allows the value of a style to be computed by shell code at lookup time. This is useful when a candidate set depends on a value that can change during the session, but the expression runs when completion asks for it. A costly computation in a frequently queried context can make every Tab press slower.
zstyle -e ':completion:*' hosts 'reply=($myhosts)'
This illustrates the documented dynamic-style form. The completion system evaluates the expression and reads its reply array. Use this only when a static value cannot represent the desired behavior. Keep the code short, deterministic, and safe to execute repeatedly; do not run a network request, scan a huge tree, or invoke an untrusted command from a style expression. Cache expensive data outside the completion hot path and update that cache deliberately.
Static styles should remain static. Use zstyle with a value directly instead of wrapping a constant in -e. Dynamic values are a shell-code execution interface, not a quoting mechanism for arbitrary strings. Validate any data that can enter the expression and avoid concatenating user input into code.
Debug a style that appears to be ignored
First confirm that completion is initialized and that the command has a completion definition. Check the style’s exact name, its context pattern, and whether the completion function queries it. Then test the narrowest possible setting against one command and one tag. A style that is valid syntactically can still be inert because its pattern does not match or because that function uses a different policy name.
Start an isolated shell with the normal user framework disabled, define only the minimal completion setup, and compare behavior before and after adding the style. In an already-running terminal, a plugin may have redefined widgets or added later initialization code. Restarting a clean process removes that hidden state from the test. Avoid editing a large generated block until the small example works.
If a broad rule unexpectedly affects unrelated completions, tighten the pattern to include the command field and, where applicable, the tag. If a narrow rule never triggers, temporarily inspect the completion context and the style value requested by the function using the shell’s completion debugging tools. Do not turn all styles into global * rules as a workaround; that can create conflicts with unrelated zsh/zutil consumers.
Keep configuration maintainable
Write comments that explain the behavior being changed and the scope of the context. A bare line like zstyle '*foo*' menu yes is difficult to audit because it neither declares a completion context nor explains which function depends on it. Prefer literal structure in the pattern and keep the value itself understandable.
When a command’s interface changes, its completion definitions may change their context or tag use. Upgrade review should test representative command positions: the command word, option values, subcommands, and file arguments. A style that was relevant to the old function may remain in the configuration but stop affecting anything after an update.
Zstyle’s key benefit is separating policy from implementation. Use it when the completion system exposes a documented style, choose the narrowest context that expresses the requirement, and verify the function actually consults it. This keeps user preferences out of completion code while avoiding a maze of global settings whose effects are impossible to predict.
Related:
- Zsh Completion Functions: compdef, _arguments, and Match Metadata
- Zsh compinit Security: Auditing Completion Paths Before Startup
Sources: