Skip to content

fix: only offer language names in zsh tab completion for -l#3737

Merged
keith-hall merged 3 commits into
sharkdp:masterfrom
truffle-dev:fix/zsh-completion-language-only
May 11, 2026
Merged

fix: only offer language names in zsh tab completion for -l#3737
keith-hall merged 3 commits into
sharkdp:masterfrom
truffle-dev:fix/zsh-completion-language-only

Conversation

@truffle-dev
Copy link
Copy Markdown
Contributor

Closes #3735.

bat --list-languages prints <name>:<file-matchers>, where the matcher
column is a comma-separated mix of plain extensions (rs), globs
(*.rs), absolute paths (/etc/profile), and full filenames
(Containerfile). The zsh completion's awk script split each line on
: or , and emitted every field as a completion value, so tab
completion offered candidates that -l cannot parse:

$ bat -l '*.bash_login' /dev/null
[bat error]: unknown syntax: '*.bash_login'

Switch to splitting on : only, emit the language name as the
completion value, and use the matcher list as its description. This
matches the bash completion's behavior, which already keeps only the
first column (assets/completions/bat.bash.in:80-89).

After the change, the completion menu shows just language names with
their extensions as descriptive context:

ASP                            -- (asa)
ActionScript                   -- (as)
Ada                            -- (adb,ads)
...

Verified locally with cargo build and cargo test --test integration_tests -- --test-threads=1 (232 passed). Unit tests (cargo test --lib) also pass (124).

The fish completion has a similar but partially-mitigated bug; out of scope here.

The previous awk script in `bat.zsh.in` split each line of
`bat --list-languages` on `:` or `,` and emitted every field as a
completion candidate, including the second column. That column lists
file matchers, which can be plain extensions (`rs`), globs (`*.rs`),
absolute paths (`/etc/profile`), or filenames (`Containerfile`). None
of those parse as `-l` arguments, so completing them produces
`unknown syntax` errors.

Switch to splitting on `:` only and emit the language name as the
completion value with the file-matcher list as its description, which
matches the bash completion's behavior.

Closes sharkdp#3735.
@LangLangBart
Copy link
Copy Markdown

LangLangBart commented May 10, 2026

The patch works for me.

I initially thought the right fix would be not pulling in the built-in mappings,
but the benefit of the status quo is the informative value on what files a given
syntax will be auto applied.

I particularly like the reduced number of items to choose from, less duplicated
values for a given syntax.

Bad thing, a value like bat -l zsh is supported and would no longer be listed
in the completion as a value, but hopefully in the future syntect will get an
upgrade and Zsh.sublime-syntax can finally be used.

So I am ok with it.

Verified locally with cargo build and cargo test --test integration_tests -- --test-threads=1 (232 passed). Unit tests (cargo test --lib) also pass (124).

There are no zsh completion tests.

EDIT1: syntect note updated

Comment thread assets/completions/bat.zsh.in Outdated
# absolute paths (`/etc/profile`), and full filenames
# (`Containerfile`); none of those parse as `-l` arguments. See
# https://github.com/sharkdp/bat/issues/3735.
languages=( ${(f)"$({{PROJECT_EXECUTABLE}} --color=never --decorations=never --list-languages | awk -F: '{ printf("%s:%s\n", $1, $2) }')"} )
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

wouldn't the awk part become redundant ?

`bat --list-languages` already emits each entry in `name:matchers`
form, which is the format `_describe` consumes directly. The previous
awk script split each line on `:` and re-emitted `$1:$2`, which is
byte-identical to the input.

Verified with `diff <(bat --list-languages) <(bat --list-languages |
awk -F: '{ printf("%s:%s\\n", $1, $2) }')` against the current
syntax set.
@truffle-dev
Copy link
Copy Markdown
Contributor Author

Yes, you're right. bat --list-languages already emits each entry in name:matchers form, which is exactly what _describe consumes, so the awk pipeline is byte-identical to the input.

I verified against the current syntax set:

$ diff <(bat --list-languages) \
       <(bat --list-languages | awk -F: '{ printf("%s:%s\n", $1, $2) }')
$ echo $?
0

Dropped the awk and refreshed the comment in 138d70f.

@keith-hall keith-hall merged commit 2cec8cd into sharkdp:master May 11, 2026
24 checks passed
leno23 pushed a commit to leno23/bat that referenced this pull request May 17, 2026
…anguage-only

fix: only offer language names in zsh tab completion for `-l`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invalid values listed in --list-languages that fail with -l

3 participants