2020-12-17 00:01:59 +08:00
|
|
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
2023-09-08 09:40:02 +08:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-12-17 00:01:59 +08:00
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
|
|
|
|
"github.com/adrg/xdg"
|
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
// CmdAutocomplete manages autocompletion
|
|
|
|
var CmdAutocomplete = cli.Command{
|
|
|
|
Name: "shellcompletion",
|
|
|
|
Aliases: []string{"autocomplete"},
|
2020-12-21 21:37:20 +08:00
|
|
|
Category: catSetup,
|
2020-12-17 00:01:59 +08:00
|
|
|
Usage: "Install shell completion for tea",
|
|
|
|
Description: "Install shell completion for tea",
|
2021-05-24 04:42:21 +08:00
|
|
|
ArgsUsage: "<shell type> (bash, zsh, powershell, fish)",
|
2020-12-17 00:01:59 +08:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "install",
|
|
|
|
Usage: "Persist in shell config instead of printing commands",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: runAutocompleteAdd,
|
|
|
|
}
|
|
|
|
|
|
|
|
func runAutocompleteAdd(ctx *cli.Context) error {
|
|
|
|
var remoteFile, localFile, cmds string
|
|
|
|
shell := ctx.Args().First()
|
|
|
|
|
|
|
|
switch shell {
|
|
|
|
case "zsh":
|
|
|
|
remoteFile = "contrib/autocomplete.zsh"
|
|
|
|
localFile = "autocomplete.zsh"
|
2021-07-24 00:14:23 +08:00
|
|
|
cmds = "echo 'PROG=tea _CLI_ZSH_AUTOCOMPLETE_HACK=1 source \"%s\"' >> ~/.zshrc && source ~/.zshrc"
|
2020-12-17 00:01:59 +08:00
|
|
|
|
|
|
|
case "bash":
|
|
|
|
remoteFile = "contrib/autocomplete.sh"
|
|
|
|
localFile = "autocomplete.sh"
|
2021-07-24 00:14:23 +08:00
|
|
|
cmds = "echo 'PROG=tea source \"%s\"' >> ~/.bashrc && source ~/.bashrc"
|
2020-12-17 00:01:59 +08:00
|
|
|
|
|
|
|
case "powershell":
|
|
|
|
remoteFile = "contrib/autocomplete.ps1"
|
|
|
|
localFile = "tea.ps1"
|
|
|
|
cmds = "\"& %s\" >> $profile"
|
|
|
|
|
2021-05-24 04:42:21 +08:00
|
|
|
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)
|
|
|
|
|
2020-12-17 00:01:59 +08:00
|
|
|
default:
|
2021-05-24 04:42:21 +08:00
|
|
|
return fmt.Errorf("Must specify valid %s", ctx.Command.ArgsUsage)
|
2020-12-17 00:01:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
localPath, err := xdg.ConfigFile("tea/" + localFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmds = fmt.Sprintf(cmds, localPath)
|
2021-05-24 04:42:21 +08:00
|
|
|
if err = writeRemoteAutoCompleteFile(remoteFile, localPath); err != nil {
|
2020-12-17 00:01:59 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ctx.Bool("install") {
|
|
|
|
fmt.Println("Installing in your shellrc")
|
|
|
|
installer := exec.Command(shell, "-c", cmds)
|
|
|
|
if shell == "powershell" {
|
|
|
|
installer = exec.Command("powershell.exe", "-Command", cmds)
|
|
|
|
}
|
|
|
|
out, err := installer.CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Couldn't run the commands: %s %s", err, out)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Println("\n# Run the following commands to install autocompletion (or use --install)")
|
|
|
|
fmt.Println(cmds)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-24 04:42:21 +08:00
|
|
|
func writeRemoteAutoCompleteFile(file, destPath string) error {
|
2020-12-17 00:01:59 +08:00
|
|
|
url := fmt.Sprintf("https://gitea.com/gitea/tea/raw/branch/master/%s", file)
|
|
|
|
fmt.Println("Fetching " + url)
|
|
|
|
|
|
|
|
res, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
|
|
|
writer, err := os.Create(destPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer writer.Close()
|
|
|
|
|
|
|
|
_, err = io.Copy(writer, res.Body)
|
|
|
|
return err
|
|
|
|
}
|
2021-05-24 04:42:21 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|