forked from Shiloh/githaven
12a1f914f4
* update github.com/alecthomas/chroma v0.8.0 -> v0.8.1 * github.com/blevesearch/bleve v1.0.10 -> v1.0.12 * editorconfig-core-go v2.1.1 -> v2.3.7 * github.com/gliderlabs/ssh v0.2.2 -> v0.3.1 * migrate editorconfig.ParseBytes to Parse * github.com/shurcooL/vfsgen to 0d455de96546 * github.com/go-git/go-git/v5 v5.1.0 -> v5.2.0 * github.com/google/uuid v1.1.1 -> v1.1.2 * github.com/huandu/xstrings v1.3.0 -> v1.3.2 * github.com/klauspost/compress v1.10.11 -> v1.11.1 * github.com/markbates/goth v1.61.2 -> v1.65.0 * github.com/mattn/go-sqlite3 v1.14.0 -> v1.14.4 * github.com/mholt/archiver v3.3.0 -> v3.3.2 * github.com/microcosm-cc/bluemonday 4f7140c49acb -> v1.0.4 * github.com/minio/minio-go v7.0.4 -> v7.0.5 * github.com/olivere/elastic v7.0.9 -> v7.0.20 * github.com/urfave/cli v1.20.0 -> v1.22.4 * github.com/prometheus/client_golang v1.1.0 -> v1.8.0 * github.com/xanzy/go-gitlab v0.37.0 -> v0.38.1 * mvdan.cc/xurls v2.1.0 -> v2.2.0 Co-authored-by: Lauris BH <lauris@nix.lv>
195 lines
4.1 KiB
Go
Vendored
195 lines
4.1 KiB
Go
Vendored
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
// ToFishCompletion creates a fish completion string for the `*App`
|
|
// The function errors if either parsing or writing of the string fails.
|
|
func (a *App) ToFishCompletion() (string, error) {
|
|
var w bytes.Buffer
|
|
if err := a.writeFishCompletionTemplate(&w); err != nil {
|
|
return "", err
|
|
}
|
|
return w.String(), nil
|
|
}
|
|
|
|
type fishCompletionTemplate struct {
|
|
App *App
|
|
Completions []string
|
|
AllCommands []string
|
|
}
|
|
|
|
func (a *App) writeFishCompletionTemplate(w io.Writer) error {
|
|
const name = "cli"
|
|
t, err := template.New(name).Parse(FishCompletionTemplate)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
allCommands := []string{}
|
|
|
|
// Add global flags
|
|
completions := a.prepareFishFlags(a.VisibleFlags(), allCommands)
|
|
|
|
// Add help flag
|
|
if !a.HideHelp {
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishFlags([]Flag{HelpFlag}, allCommands)...,
|
|
)
|
|
}
|
|
|
|
// Add version flag
|
|
if !a.HideVersion {
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishFlags([]Flag{VersionFlag}, allCommands)...,
|
|
)
|
|
}
|
|
|
|
// Add commands and their flags
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishCommands(a.VisibleCommands(), &allCommands, []string{})...,
|
|
)
|
|
|
|
return t.ExecuteTemplate(w, name, &fishCompletionTemplate{
|
|
App: a,
|
|
Completions: completions,
|
|
AllCommands: allCommands,
|
|
})
|
|
}
|
|
|
|
func (a *App) prepareFishCommands(commands []Command, allCommands *[]string, previousCommands []string) []string {
|
|
completions := []string{}
|
|
for i := range commands {
|
|
command := &commands[i]
|
|
|
|
if command.Hidden {
|
|
continue
|
|
}
|
|
|
|
var completion strings.Builder
|
|
completion.WriteString(fmt.Sprintf(
|
|
"complete -r -c %s -n '%s' -a '%s'",
|
|
a.Name,
|
|
a.fishSubcommandHelper(previousCommands),
|
|
strings.Join(command.Names(), " "),
|
|
))
|
|
|
|
if command.Usage != "" {
|
|
completion.WriteString(fmt.Sprintf(" -d '%s'",
|
|
escapeSingleQuotes(command.Usage)))
|
|
}
|
|
|
|
if !command.HideHelp {
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishFlags([]Flag{HelpFlag}, command.Names())...,
|
|
)
|
|
}
|
|
|
|
*allCommands = append(*allCommands, command.Names()...)
|
|
completions = append(completions, completion.String())
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishFlags(command.Flags, command.Names())...,
|
|
)
|
|
|
|
// recursevly iterate subcommands
|
|
if len(command.Subcommands) > 0 {
|
|
completions = append(
|
|
completions,
|
|
a.prepareFishCommands(
|
|
command.Subcommands, allCommands, command.Names(),
|
|
)...,
|
|
)
|
|
}
|
|
}
|
|
|
|
return completions
|
|
}
|
|
|
|
func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string {
|
|
completions := []string{}
|
|
for _, f := range flags {
|
|
flag, ok := f.(DocGenerationFlag)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
completion := &strings.Builder{}
|
|
completion.WriteString(fmt.Sprintf(
|
|
"complete -c %s -n '%s'",
|
|
a.Name,
|
|
a.fishSubcommandHelper(previousCommands),
|
|
))
|
|
|
|
fishAddFileFlag(f, completion)
|
|
|
|
for idx, opt := range strings.Split(flag.GetName(), ",") {
|
|
if idx == 0 {
|
|
completion.WriteString(fmt.Sprintf(
|
|
" -l %s", strings.TrimSpace(opt),
|
|
))
|
|
} else {
|
|
completion.WriteString(fmt.Sprintf(
|
|
" -s %s", strings.TrimSpace(opt),
|
|
))
|
|
|
|
}
|
|
}
|
|
|
|
if flag.TakesValue() {
|
|
completion.WriteString(" -r")
|
|
}
|
|
|
|
if flag.GetUsage() != "" {
|
|
completion.WriteString(fmt.Sprintf(" -d '%s'",
|
|
escapeSingleQuotes(flag.GetUsage())))
|
|
}
|
|
|
|
completions = append(completions, completion.String())
|
|
}
|
|
|
|
return completions
|
|
}
|
|
|
|
func fishAddFileFlag(flag Flag, completion *strings.Builder) {
|
|
switch f := flag.(type) {
|
|
case GenericFlag:
|
|
if f.TakesFile {
|
|
return
|
|
}
|
|
case StringFlag:
|
|
if f.TakesFile {
|
|
return
|
|
}
|
|
case StringSliceFlag:
|
|
if f.TakesFile {
|
|
return
|
|
}
|
|
}
|
|
completion.WriteString(" -f")
|
|
}
|
|
|
|
func (a *App) fishSubcommandHelper(allCommands []string) string {
|
|
fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", a.Name)
|
|
if len(allCommands) > 0 {
|
|
fishHelper = fmt.Sprintf(
|
|
"__fish_seen_subcommand_from %s",
|
|
strings.Join(allCommands, " "),
|
|
)
|
|
}
|
|
return fishHelper
|
|
|
|
}
|
|
|
|
func escapeSingleQuotes(input string) string {
|
|
return strings.Replace(input, `'`, `\'`, -1)
|
|
}
|