Add tab completion for fish shell (#364)

as title, fixes #361

Handling of fish shell is different in urfave/cli; urfave/cli provides a generator for the shell script needed (probably because the fish `completion` syntax isn't flexible enough to let the application handle the completion at runtime? idk)

This means that the fish completion can become out of sync with the tea binary.
If we want to account for that, on each application run we need to
- check if `~/.config/fish/conf.d/tea_completion.fish` exists; if so
- check if the tea version that wrote it is the currently running version
- if not, rewrite the file.

Not sure this is worth the complexity & cost

It generates a completion that also suggests file names, which looks kinda messy: Didn't find a way around this, but [there may be a way](5bb54ace57/fish.go (L160-L180))
![grafik](/attachments/b08541c9-0f37-4c70-a2e3-1ec9da15a430)

Co-authored-by: Norwin Roosen <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/364
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2021-05-24 04:42:21 +08:00 committed by 6543
parent ffdbdb3d02
commit df724b4006

View File

@ -22,7 +22,7 @@ var CmdAutocomplete = cli.Command{
Category: catSetup, Category: catSetup,
Usage: "Install shell completion for tea", Usage: "Install shell completion for tea",
Description: "Install shell completion for tea", Description: "Install shell completion for tea",
ArgsUsage: "<shell type> (bash, zsh, powershell)", ArgsUsage: "<shell type> (bash, zsh, powershell, fish)",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: "install", Name: "install",
@ -52,8 +52,14 @@ func runAutocompleteAdd(ctx *cli.Context) error {
localFile = "tea.ps1" localFile = "tea.ps1"
cmds = "\"& %s\" >> $profile" cmds = "\"& %s\" >> $profile"
case "fish":
// fish is different, in that urfave/cli provides a generator for the shell script needed.
// this also means that the fish completion can become out of sync with the tea binary!
// writing to this directory suffices, as fish reads files there on startup, no cmds needed.
return writeFishAutoCompleteFile(ctx)
default: default:
return fmt.Errorf("Must specify valid shell type") return fmt.Errorf("Must specify valid %s", ctx.Command.ArgsUsage)
} }
localPath, err := xdg.ConfigFile("tea/" + localFile) localPath, err := xdg.ConfigFile("tea/" + localFile)
@ -62,8 +68,7 @@ func runAutocompleteAdd(ctx *cli.Context) error {
} }
cmds = fmt.Sprintf(cmds, localPath) cmds = fmt.Sprintf(cmds, localPath)
if err = writeRemoteAutoCompleteFile(remoteFile, localPath); err != nil {
if err := saveAutoCompleteFile(remoteFile, localPath); err != nil {
return err return err
} }
@ -85,7 +90,7 @@ func runAutocompleteAdd(ctx *cli.Context) error {
return nil return nil
} }
func saveAutoCompleteFile(file, destPath string) error { func writeRemoteAutoCompleteFile(file, destPath string) error {
url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file) url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file)
fmt.Println("Fetching " + url) fmt.Println("Fetching " + url)
@ -104,3 +109,30 @@ func saveAutoCompleteFile(file, destPath string) error {
_, err = io.Copy(writer, res.Body) _, err = io.Copy(writer, res.Body)
return err return err
} }
func writeFishAutoCompleteFile(ctx *cli.Context) error {
// NOTE: to make sure this file is in sync with tea commands, we'd need to
// - check if the file exists
// - if it does, check if the tea version that wrote it is the currently running version
// - if not, rewrite the file
// on each application run
// NOTE: this generates a completion that also suggests file names, which looks kinda messy..
script, err := ctx.App.ToFishCompletion()
if err != nil {
return err
}
localPath, err := xdg.ConfigFile("fish/conf.d/tea_completion.fish")
if err != nil {
return err
}
writer, err := os.Create(localPath)
if err != nil {
return err
}
if _, err = io.WriteString(writer, script); err != nil {
return err
}
fmt.Printf("Installed tab completion to %s\n", localPath)
return nil
}