Merge branch 'fix-fish-completion-multiline-descriptions' of https://github.com/devangpratap/kitty
Some checks are pending
CI / Linux (python=3.14 cc=clang sanitize=1) (push) Waiting to run
CI / Linux (python=3.12 cc=gcc sanitize=0) (push) Waiting to run
CI / Linux (python=3.13 cc=gcc sanitize=1) (push) Waiting to run
CI / Linux package (push) Waiting to run
CI / Bundle test (macos-latest) (push) Waiting to run
CI / Bundle test (ubuntu-latest) (push) Waiting to run
CI / macOS Brew (push) Waiting to run
CI / Test ./dev.sh and benchmark (push) Waiting to run
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, macos-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Waiting to run
Depscan / Scan dependencies for vulnerabilities (push) Waiting to run

This commit is contained in:
Kovid Goyal 2026-09-25 06:07:09 +05:30
commit c7d4eab814
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
2 changed files with 32 additions and 2 deletions

View file

@ -52,10 +52,15 @@ func fish_output_serializer(completions []*Completions, shell_state map[string]s
n := completions[0].Delegate.NumToRemove
fm := markup.New(false) // fish freaks out if there are escape codes in the description strings
legacy_completion := shell_state["_legacy_completion"]
// fish splits the output of the completion function on newlines, so a description
// spanning multiple lines adds its continuation lines as spurious candidates.
candidate := func(m *Match) string {
return strings.ReplaceAll(m.Word+"\t"+fm.Prettify(m.Description), "\n", " ")
}
if legacy_completion == "fish2" {
for _, mg := range completions[0].Groups {
for _, m := range mg.Matches {
f("%s", strings.ReplaceAll(m.Word+"\t"+fm.Prettify(m.Description), "\n", " "))
f("%s", candidate(m))
}
}
} else if n > 0 {
@ -72,7 +77,7 @@ func fish_output_serializer(completions []*Completions, shell_state map[string]s
} else {
for _, mg := range completions[0].Groups {
for _, m := range mg.Matches {
f("echo -- %s", utils.QuoteStringForFish(m.Word+"\t"+fm.Prettify(m.Description)))
f("echo -- %s", utils.QuoteStringForFish(candidate(m)))
}
}
}

25
tools/cli/fish_test.go Normal file
View file

@ -0,0 +1,25 @@
// License: GPLv3 Copyright: 2026, Kovid Goyal, <kovid at kovidgoyal.net>
package cli
import (
"strings"
"testing"
)
func TestFishCompletionMultilineDescription(t *testing.T) {
completions := []*Completions{{Groups: []*MatchGroup{{Title: "Options", Matches: []*Match{
{Word: "--config", Description: "Specify a path to the configuration file.\n\nIf it is not specified, config files are searched for."},
}}}}}
for _, shell_state := range []map[string]string{{}, {"_legacy_completion": "fish2"}} {
data, err := fish_output_serializer(completions, shell_state)
if err != nil {
t.Fatal(err)
}
// each candidate must be a single line, since fish splits the output of the
// completion function on newlines to get the candidate list
if q := strings.TrimRight(string(data), "\n"); strings.Contains(q, "\n") {
t.Fatalf("A multi line description produced more than one candidate with shell state %#v:\n%s", shell_state, q)
}
}
}