diff --git a/completers/git_completer/cmd/reset.go b/completers/git_completer/cmd/reset.go index 2cc554c335..3f59c892fd 100644 --- a/completers/git_completer/cmd/reset.go +++ b/completers/git_completer/cmd/reset.go @@ -1,6 +1,8 @@ package cmd import ( + "strings" + "github.com/rsteube/carapace" "github.com/rsteube/carapace-bin/pkg/actions/tools/git" "github.com/spf13/cobra" @@ -31,20 +33,54 @@ func init() { resetCmd.Flag("recurse-submodules").NoOptDefVal = " " + modeFlags := []string{"soft", "mixed", "hard", "merge", "keep"} + resetCmd.MarkFlagsMutuallyExclusive( + append(modeFlags, "patch")..., // TODO verify - either one of the "modes" above or patch allowed + ) + carapace.Gen(resetCmd).FlagCompletion(carapace.ActionMap{ "pathspec-from-file": carapace.ActionFiles(), }) carapace.Gen(resetCmd).PositionalCompletion( - git.ActionRefs(git.RefOption{}.Default()), + carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if strings.HasPrefix(c.Value, ".") { + for _, name := range modeFlags { + if f := resetCmd.Flag(name); f != nil && f.Changed { + return carapace.ActionValues() // complete only commits for these flags + } + } + return git.ActionRefDiffs() + } + return git.ActionRefs(git.RefOption{}.Default()) + }), ) carapace.Gen(resetCmd).PositionalAnyCompletion( carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if resetCmd.Flags().ArgsLenAtDash() != -1 { - return carapace.ActionFiles() + toFilter := make([]string, 0) + for _, arg := range c.Args { + // TODO directories? globs possible? should work for most cases though + switch { + case !strings.HasPrefix(c.Value, "."): + toFilter = append(toFilter, strings.TrimPrefix(arg, "./")) + case !strings.HasPrefix(arg, "."): + toFilter = append(toFilter, "./"+arg) + default: + toFilter = append(toFilter, arg) + } + } + + switch { + case strings.HasPrefix(c.Args[0], "."): + return git.ActionRefDiffs().Filter(toFilter...) + default: + return git.ActionRefDiffs(c.Args[0]).Filter(toFilter[1:]...) } - return carapace.ActionValues() }), ) + + carapace.Gen(resetCmd).DashAnyCompletion( + carapace.ActionPositional(resetCmd), + ) } diff --git a/pkg/actions/tools/git/change.go b/pkg/actions/tools/git/change.go index 389756b3a9..61bf02e3fd 100644 --- a/pkg/actions/tools/git/change.go +++ b/pkg/actions/tools/git/change.go @@ -58,7 +58,7 @@ func ActionChanges(opts ChangeOpts) carapace.Action { }) } -// ActionRefChanges completes changes compared to given ref +// ActionRefChanges completes changes made in given ref // // go.mod // cmd/carapace/main.go diff --git a/pkg/actions/tools/git/diff.go b/pkg/actions/tools/git/diff.go index b7072ce2ae..ecb6d97e56 100644 --- a/pkg/actions/tools/git/diff.go +++ b/pkg/actions/tools/git/diff.go @@ -1,6 +1,12 @@ package git -import "github.com/rsteube/carapace" +import ( + "path/filepath" + "strings" + + "github.com/rsteube/carapace" + "github.com/rsteube/carapace/pkg/style" +) // ActionDiffAlgorithms completes diff algorithms // @@ -102,3 +108,57 @@ func ActionDiffTools() carapace.Action { "xxdiff", ) } + +// ActionRefDiffs completes changes beetween refs +// Accepts up to two refs +// 0: compare current workspace to HEAD +// 1: compare current workspace to given ref +// 2: compare first ref to second ref +func ActionRefDiffs(refs ...string) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + args := []string{"diff", "--name-status"} + switch len(refs) { + case 0: + args = append(args, "HEAD") + case 1: + args = append(args, refs[0]) + case 2: + args = append(args, refs[0], refs[1]) + default: + return carapace.ActionMessage("only up to two refs allowed [ActionRefDiffs]") + } + + return carapace.ActionExecCommand("git", args...)(func(output []byte) carapace.Action { + lines := strings.Split(string(output), "\n") + + root, err := rootDir(c) + if err != nil { + return carapace.ActionMessage(err.Error()) + } + + vals := make([]string, 0) + for _, line := range lines { + splitted := strings.Split(line, "\t") + if len(splitted) < 2 { + continue + } + + relativePath, err := filepath.Rel(c.Dir, root+"/"+splitted[1]) + if err != nil { + return carapace.ActionMessage(err.Error()) + } + + switch { + case strings.HasPrefix(relativePath, "../"): + vals = append(vals, relativePath, splitted[0]) + case strings.HasPrefix(c.Value, "."): + vals = append(vals, "./"+relativePath, splitted[0]) + default: + vals = append(vals, relativePath, splitted[0]) + } + + } + return carapace.ActionValuesDescribed(vals...).StyleF(style.ForPathExt) + }) + }) +}