mirror of
https://github.com/rsteube/carapace-bin.git
synced 2025-05-14 11:44:32 +00:00
243 lines
10 KiB
Go
243 lines
10 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/rsteube/carapace"
|
|
"github.com/rsteube/carapace-bin/pkg/actions/tools/git"
|
|
"github.com/rsteube/carapace-bridge/pkg/actions/bridge"
|
|
"github.com/rsteube/carapace-shlex"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
var rootCmd = &cobra.Command{
|
|
Use: "git",
|
|
Short: "the stupid content tracker",
|
|
Long: "https://git-scm.com/",
|
|
}
|
|
|
|
const (
|
|
group_main = iota
|
|
group_manipulator
|
|
group_interrogator
|
|
group_interaction
|
|
group_alias
|
|
group_external
|
|
group_low_level_manipulator
|
|
group_low_level_interrogator
|
|
group_low_level_synching
|
|
group_low_level_helper
|
|
)
|
|
|
|
var groups = []*cobra.Group{
|
|
{ID: "main", Title: "Main Commands"},
|
|
{ID: "manipulator", Title: "Manipulator Commands"},
|
|
{ID: "interrogator", Title: "Interrogator Commands"},
|
|
{ID: "interaction", Title: "Interaction Commands"},
|
|
{ID: "alias", Title: "Alias Commands"},
|
|
{ID: "external", Title: "External Commands"},
|
|
{ID: "low-level manipulator", Title: "Low-level Manipulator Commands"},
|
|
{ID: "low-level interrogator", Title: "Low-level Interrogator Commands"},
|
|
{ID: "low-level synching", Title: "Low-level Synching Commands"},
|
|
{ID: "low-level helper", Title: "Low-level Helper Commands"},
|
|
}
|
|
|
|
func Execute() error {
|
|
return rootCmd.Execute()
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddGroup(groups...)
|
|
|
|
carapace.Gen(rootCmd).Standalone()
|
|
rootCmd.Flags().StringS("C", "C", "", "run as if git was started in given path")
|
|
rootCmd.Flags().Bool("bare", false, "use $PWD as repository")
|
|
rootCmd.Flags().StringS("c", "c", "", "pass configuration parameter to command")
|
|
rootCmd.Flags().String("exec-path", "", "path containing core git-programs")
|
|
rootCmd.Flags().String("git-dir", "", "path to repository")
|
|
rootCmd.Flags().Bool("help", false, "display help message")
|
|
rootCmd.Flags().Bool("html-path", false, "display path to HTML documentation and exit")
|
|
rootCmd.Flags().Bool("info-path", false, "print the path where the info files are installed and exit")
|
|
rootCmd.Flags().String("list-cmds", "", "list commands")
|
|
rootCmd.Flags().Bool("literal-pathspecs", false, "treat pathspecs literally, rather than as glob patterns")
|
|
rootCmd.Flags().Bool("man-path", false, "print the manpath for the man pages for this version of Git and exit")
|
|
rootCmd.Flags().String("namespace", "", "set the Git namespace")
|
|
rootCmd.Flags().BoolP("no-pager", "P", false, "don't pipe git output into a pager")
|
|
rootCmd.Flags().Bool("no-replace-objects", false, "do not use replacement refs to replace git objects")
|
|
rootCmd.Flags().BoolP("paginate", "p", false, "pipe output into a pager")
|
|
rootCmd.Flags().Bool("version", false, "display version information")
|
|
rootCmd.Flags().String("work-tree", "", "path to working tree")
|
|
|
|
rootCmd.Flag("list-cmds").NoOptDefVal = " "
|
|
|
|
carapace.Gen(rootCmd).FlagCompletion(carapace.ActionMap{
|
|
"C": carapace.ActionDirectories(),
|
|
"c": carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action {
|
|
switch len(c.Parts) {
|
|
case 0:
|
|
return git.ActionConfigs().NoSpace()
|
|
default:
|
|
return carapace.ActionValues()
|
|
}
|
|
}),
|
|
"exec-path": carapace.ActionDirectories(),
|
|
"git-dir": carapace.ActionDirectories(),
|
|
"list-cmds": carapace.ActionValues("main", "others", "alias", "nohelpers"),
|
|
"work-tree": carapace.ActionDirectories(),
|
|
})
|
|
|
|
carapace.Gen(rootCmd).PreInvoke(func(cmd *cobra.Command, flag *pflag.Flag, action carapace.Action) carapace.Action {
|
|
return action.Chdir(rootCmd.Flag("C").Value.String())
|
|
})
|
|
|
|
carapace.Gen(rootCmd).PreRun(func(cmd *cobra.Command, args []string) {
|
|
if _, _, err := cmd.Find(args); len(args) > 1 && err == nil {
|
|
return // core command - skip aliases and other commands
|
|
}
|
|
addAliasCompletion(args)
|
|
addOtherCommands()
|
|
})
|
|
}
|
|
|
|
func addAliasCompletion(args []string) {
|
|
cmd := &cobra.Command{}
|
|
cmd.FParseErrWhitelist.UnknownFlags = true
|
|
cmd.Flags().StringS("C", "C", "", "run as if git was started in given path")
|
|
cmd.Flags().String("git-dir", "", "path to repository")
|
|
|
|
cmd.ParseFlags(args[:len(args)-1])
|
|
if aliases, err := git.Aliases(cmd.Flag("C").Value.String(), cmd.Flag("git-dir").Value.String()); err == nil {
|
|
for key, value := range aliases {
|
|
if _, _, err := rootCmd.Find([]string{key}); err == nil {
|
|
continue // don't clobber existing commands
|
|
}
|
|
|
|
aliasCmd := &cobra.Command{
|
|
Use: key,
|
|
Short: fmt.Sprintf("alias for '%s'", value),
|
|
GroupID: groups[group_alias].ID,
|
|
DisableFlagParsing: true,
|
|
}
|
|
|
|
rootCmd.AddCommand(aliasCmd)
|
|
|
|
if strings.HasPrefix(value, "!") {
|
|
continue // aliases beginning with ! are arbitrary shell commands so don't add completion
|
|
}
|
|
|
|
tokens, err := shlex.Split(value) // TODO trim value?
|
|
if err == nil {
|
|
carapace.Gen(aliasCmd).PositionalAnyCompletion(
|
|
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
|
|
c.Args = append(tokens.Strings(), c.Args...)
|
|
return bridge.ActionCarapaceBin("git").Invoke(c).ToA()
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func addOtherCommands() {
|
|
if output, err := (carapace.Context{}).Command("git", "--list-cmds=others").Output(); err == nil {
|
|
lines := strings.Split(string(output), "\n")
|
|
|
|
for _, name := range lines[:len(lines)-1] {
|
|
pluginCmd := &cobra.Command{
|
|
Use: name,
|
|
Short: othersDescription(name),
|
|
Run: func(cmd *cobra.Command, args []string) {},
|
|
GroupID: groups[group_external].ID,
|
|
DisableFlagParsing: true,
|
|
}
|
|
|
|
carapace.Gen(pluginCmd).PositionalAnyCompletion(
|
|
bridge.ActionCarapaceBin("git-" + name),
|
|
)
|
|
|
|
rootCmd.AddCommand(pluginCmd)
|
|
}
|
|
}
|
|
}
|
|
|
|
func othersDescription(name string) string {
|
|
return map[string]string{
|
|
"abort": "Abort current git operation",
|
|
"alias": "Define, search and show aliases",
|
|
"archive-file": "Export the current HEAD of the git repository to an archive",
|
|
"authors": "Generate authors report",
|
|
"browse": "View the web page for the current repository",
|
|
"browse-ci": "Opens the current git repository CI page in your default web browser",
|
|
"brv": "List branches sorted by their last commit date",
|
|
"bulk": "Run git commands on multiple repositories",
|
|
"changelog": "Generate a changelog report",
|
|
"clang-format": "run clang-format on lines that differ",
|
|
"clear": "Rigorously clean up a repository",
|
|
"clear-soft": "Soft clean up a repository",
|
|
"coauthor": "Add a co-author to the last commit",
|
|
"commits-since": "Show commit logs since some date",
|
|
"contrib": "Show user's contributions",
|
|
"count": "Show commit count",
|
|
"cp": "Copy a file keeping its history",
|
|
"create-branch": "Create branches",
|
|
"delete-branch": "Delete branches",
|
|
"delete-merged-branches": "Delete merged branches",
|
|
"delete-squashed-branches": "Delete branches that were squashed",
|
|
"delete-submodule": "Delete submodules",
|
|
"delete-tag": "Delete tags",
|
|
"delta": "Lists changed files",
|
|
"effort": "Show effort statistics on file(s)",
|
|
"extras": "Awesome GIT utilities",
|
|
"feature": "Create/Merge feature branch",
|
|
"force-clone": "overwrite local repositories with clone",
|
|
"fork": "Fork a repo on github",
|
|
"fresh-branch": "Create fresh branches",
|
|
"gh-pages": "Create the GitHub Pages branch",
|
|
"graft": "Merge and destroy a given branch",
|
|
"guilt": "calculate change between two revisions",
|
|
"ignore": "Add .gitignore patterns",
|
|
"ignore-io": "Get sample gitignore file",
|
|
"info": "Returns information on current repository",
|
|
"local-commits": "List local commits",
|
|
"lock": "Lock a file excluded from version control",
|
|
"locked": "ls files that have been locked",
|
|
"magic": "Automate add/commit/push routines",
|
|
"merge-into": "Merge one branch into another",
|
|
"merge-repo": "Merge two repo histories",
|
|
"missing": "Show commits missing from another branch",
|
|
"mr": "Checks out a merge request locally",
|
|
"obliterate": "rewrite past commits to remove some files",
|
|
"paste": "Send patches to pastebin for chat conversations",
|
|
"pr": "Checks out a pull request locally",
|
|
"psykorebase": "Rebase a branch with a merge commit",
|
|
"pull-request": "Create pull request for GitHub project",
|
|
"reauthor": "Rewrite history to change author's identity",
|
|
"rebase-patch": "Rebases a patch",
|
|
"release": "Commit, tag and push changes to the repository",
|
|
"rename-branch": "rename local branch and push to remote",
|
|
"rename-remote": "Rename a remote",
|
|
"rename-tag": "Rename a tag",
|
|
"repl": "git read-eval-print-loop",
|
|
"reset-file": "Reset one file",
|
|
"root": "show path of root",
|
|
"rscp": "Copies specific files from the working directory of a remote repository to the current working directory.",
|
|
"scp": "Copy files to SSH compatible git-remote",
|
|
"sed": "replace patterns in git-controlled files",
|
|
"setup": "Set up a git repository",
|
|
"show-merged-branches": "Show merged branches",
|
|
"show-tree": "show branch tree of commit history",
|
|
"show-unmerged-branches": "Show unmerged branches",
|
|
"squash": "squash N last changes up to a ref'ed commit",
|
|
"stamp": "Stamp the last commit message",
|
|
"standup": "Recall the commit history",
|
|
"summary": "Show repository summary",
|
|
"sync": "Sync local branch with remote branch",
|
|
"touch": "Touch and add file to the index",
|
|
"undo": "Remove latest commits",
|
|
"unlock": "Unlock a file excluded from version control",
|
|
"utimes": "Change files modification time to their last commit date",
|
|
}[name]
|
|
}
|