2 Commits

Author SHA1 Message Date
Sebastian Unterschütz cdf750081e feat: show subcommands after hostnames in shell completion
Release / release (push) Successful in 48s
Use ShellCompDirectiveKeepOrder so fish/zsh/bash preserve the returned
order instead of sorting alphabetically. ValidArgsFunction now appends
subcommand names (with their short descriptions) after all hostname
entries, so hosts always appear first in the completion list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:42:41 +02:00
Sebastian Unterschütz 574c4dbf58 fix: completion install writes non-empty scripts
Release / release (push) Successful in 47s
GenBashCompletionV2/GenZshCompletion/GenFishCompletion write into the
buffer as a side effect; capturing buf.String() in the return statement
before the Gen* call runs means the buffer is always empty. Separate
the call from the return to fix evaluation order.

Also call InitDefaultCompletionCmd() before iterating root.Commands()
so the lazily-initialized completion subtree is visible before Execute().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 13:50:53 +02:00
+19 -9
View File
@@ -199,18 +199,25 @@ func rootCmd() *cobra.Command {
}
c := cache.New(cfg.Cache.Path, cfg.Cache.TTL)
_ = c.Load()
entries := c.Search(toComplete)
names := make([]cobra.Completion, len(entries))
for i, e := range entries {
names[i] = cobra.Completion(e.Name)
var completions []cobra.Completion
for _, e := range c.Search(toComplete) {
completions = append(completions, cobra.Completion(e.Name))
}
return names, cobra.ShellCompDirectiveNoFileComp
// Subcommands at the end, after all hostnames.
for _, sub := range cmd.Commands() {
if sub.IsAvailableCommand() && strings.HasPrefix(sub.Name(), toComplete) {
completions = append(completions, cobra.Completion(sub.Name()+"\t"+sub.Short))
}
}
return completions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveKeepOrder
},
}
// cobra automatically adds a "completion" subcommand; we extend it with "install".
root.AddCommand(configureCmd(), searchCmd(), cacheCmd())
// cobra builds the "completion" command lazily; force init so we can extend it.
root.InitDefaultCompletionCmd()
for _, cmd := range root.Commands() {
if cmd.Name() == "completion" {
cmd.AddCommand(completionInstallCmd(root))
@@ -244,7 +251,8 @@ func completionInstallCmd(root *cobra.Command) *cobra.Command {
file = filepath.Join(dir, "netssh")
gen = func() ([]byte, error) {
var buf strings.Builder
return []byte(buf.String()), root.GenBashCompletionV2(&buf, true)
err := root.GenBashCompletionV2(&buf, true)
return []byte(buf.String()), err
}
note = "Reload your shell or run: source " + file
case "zsh":
@@ -252,7 +260,8 @@ func completionInstallCmd(root *cobra.Command) *cobra.Command {
file = filepath.Join(dir, "_netssh")
gen = func() ([]byte, error) {
var buf strings.Builder
return []byte(buf.String()), root.GenZshCompletion(&buf)
err := root.GenZshCompletion(&buf)
return []byte(buf.String()), err
}
note = "Make sure ~/.zfunc is in your fpath:\n fpath=(~/.zfunc $fpath)\n autoload -Uz compinit && compinit"
case "fish":
@@ -261,7 +270,8 @@ func completionInstallCmd(root *cobra.Command) *cobra.Command {
file = filepath.Join(dir, "netssh.fish")
gen = func() ([]byte, error) {
var buf strings.Builder
return []byte(buf.String()), root.GenFishCompletion(&buf, true)
err := root.GenFishCompletion(&buf, true)
return []byte(buf.String()), err
}
note = "Reload your shell or start a new fish session."
default: