From 355130a5c91c8386f1dfee3f7d9f6cf04a5cc2f0 Mon Sep 17 00:00:00 2001 From: rsteube Date: Sat, 6 Jan 2024 01:32:45 +0100 Subject: [PATCH] git: difftool - use diff completion --- completers/git_completer/cmd/diff.go | 144 ++++++++++++----------- completers/git_completer/cmd/difftool.go | 24 +--- 2 files changed, 78 insertions(+), 90 deletions(-) diff --git a/completers/git_completer/cmd/diff.go b/completers/git_completer/cmd/diff.go index a207784f87..3fe6d58093 100644 --- a/completers/git_completer/cmd/diff.go +++ b/completers/git_completer/cmd/diff.go @@ -23,76 +23,7 @@ func init() { rootCmd.AddCommand(diffCmd) carapace.Gen(diffCmd).PositionalAnyCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if diffCmd.Flag("no-index").Changed { - switch len(c.Args) { - case 0, 1: - return carapace.ActionFiles() - default: - return carapace.ActionValues() - } - } - - batch := carapace.Batch() - - filtered := make([]string, 0) - for index, arg := range c.Args { - if index == 0 && strings.Contains(arg, "..") { // assume refrange - TODO what about '{ref}...{ref}' - filtered = append(filtered, arg) - break - } - - if err := c.Command("git", "rev-parse", "--verify", arg).Run(); err != nil { - break - } - filtered = append(filtered, arg) - } - - if len(filtered) == len(c.Args) && diffCmd.Flags().ArgsLenAtDash() < 0 { - switch len(filtered) { - case 0: - batch = append(batch, git.ActionRefRanges(git.RefOption{}.Default())) - default: - switch { - case strings.Contains(c.Args[0], ".."): // skip if we already have a refrange - case diffCmd.Flag("cached").Changed: // skip as '-cached' accepts only on ref - default: - batch = append(batch, git.ActionRefs(git.RefOption{}.Default())) - } - } - } - - expanded := filtered - if len(filtered) > 0 { - // TODO support/suppress '{ref}...{ref}'?? - expanded = append(strings.SplitN(filtered[0], "..", 2), filtered[1:]...) // split refrange if any - } - - switch len(expanded) { - case 0: - if !diffCmd.Flag("cached").Changed { - // TODO `git diff` fails on deleted files (seems still worth seeing them in completion though) - batch = append(batch, git.ActionChanges(git.ChangeOpts{Unstaged: true})) - } - default: - // TODO handle --merge-base with more than 2 refs - var action carapace.Action - if diffCmd.Flag("cached").Changed { - if len(expanded) > 0 { - action = git.ActionCachedDiffs(expanded[0]) - } - } else { - action = git.ActionRefDiffs(expanded...) - } - - if len(expanded) > 0 { // multipart for potentially large diffs - action = action.MultiParts("/").StyleF(style.ForPathExt).Tag("changed files") - } - batch = append(batch, action.Filter(c.Args[len(filtered):]...)) - } - - return batch.ToA() - }), + actionDiffArgs(diffCmd), ) carapace.Gen(diffCmd).DashAnyCompletion( @@ -204,3 +135,76 @@ func addDiffFlags(cmd *cobra.Command) { "ws-error-highlight": git.ActionWsErrorHighlightModes().UniqueList(","), }) } + +func actionDiffArgs(cmd *cobra.Command) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if cmd.Flag("no-index").Changed { + switch len(c.Args) { + case 0, 1: + return carapace.ActionFiles() + default: + return carapace.ActionValues() + } + } + + batch := carapace.Batch() + + filtered := make([]string, 0) + for index, arg := range c.Args { + if index == 0 && strings.Contains(arg, "..") { // assume refrange - TODO what about '{ref}...{ref}' + filtered = append(filtered, arg) + break + } + + if err := c.Command("git", "rev-parse", "--verify", arg).Run(); err != nil { + break + } + filtered = append(filtered, arg) + } + + if len(filtered) == len(c.Args) && cmd.Flags().ArgsLenAtDash() < 0 { + switch len(filtered) { + case 0: + batch = append(batch, git.ActionRefRanges(git.RefOption{}.Default())) + default: + switch { + case strings.Contains(c.Args[0], ".."): // skip if we already have a refrange + case cmd.Flag("cached").Changed: // skip as '-cached' accepts only on ref + default: + batch = append(batch, git.ActionRefs(git.RefOption{}.Default())) + } + } + } + + expanded := filtered + if len(filtered) > 0 { + // TODO support/suppress '{ref}...{ref}'?? + expanded = append(strings.SplitN(filtered[0], "..", 2), filtered[1:]...) // split refrange if any + } + + switch len(expanded) { + case 0: + if !cmd.Flag("cached").Changed { + // TODO `git diff` fails on deleted files (seems still worth seeing them in completion though) + batch = append(batch, git.ActionChanges(git.ChangeOpts{Unstaged: true}).Filter(cmd.Flags().Args()...)) + } + default: + // TODO handle --merge-base with more than 2 refs + var action carapace.Action + if cmd.Flag("cached").Changed { + if len(expanded) > 0 { + action = git.ActionCachedDiffs(expanded[0]) + } + } else { + action = git.ActionRefDiffs(expanded...) + } + + if len(expanded) > 0 { // multipart for potentially large diffs + action = action.MultiParts("/").StyleF(style.ForPathExt).Tag("changed files") + } + batch = append(batch, action.Filter(cmd.Flags().Args()[len(filtered):]...)) + } + + return batch.ToA() + }) +} diff --git a/completers/git_completer/cmd/difftool.go b/completers/git_completer/cmd/difftool.go index d36f6942a3..73914c43c2 100644 --- a/completers/git_completer/cmd/difftool.go +++ b/completers/git_completer/cmd/difftool.go @@ -2,8 +2,6 @@ package cmd import ( "github.com/rsteube/carapace" - "github.com/rsteube/carapace-bin/pkg/actions/tools/git" - "github.com/rsteube/carapace/pkg/util" "github.com/spf13/cobra" ) @@ -20,12 +18,13 @@ func init() { difftoolCmd.Flags().BoolP("dir-diff", "d", false, "perform a full-directory diff") difftoolCmd.Flags().StringP("extcmd", "x", "", "specify a custom command for viewing diffs") difftoolCmd.Flags().BoolP("gui", "g", false, "use `diff.guitool` instead of `diff.tool`") - difftoolCmd.Flags().Bool("no-index", false, "passed to `diff`") difftoolCmd.Flags().BoolP("no-prompt", "y", false, "do not prompt before launching a diff tool") difftoolCmd.Flags().Bool("symlinks", false, "use symlinks in dir-diff mode") difftoolCmd.Flags().StringP("tool", "t", "", "use the specified diff tool") difftoolCmd.Flags().Bool("tool-help", false, "print a list of diff tools that may be used with `--tool`") difftoolCmd.Flags().Bool("trust-exit-code", false, "exit when an invoked diff tool returns a non - zero exit code") + + addDiffFlags(difftoolCmd) rootCmd.AddCommand(difftoolCmd) carapace.Gen(difftoolCmd).FlagCompletion(carapace.ActionMap{ @@ -35,26 +34,11 @@ func init() { ).ToA(), }) - carapace.Gen(difftoolCmd).PositionalCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if util.HasPathPrefix(c.Value) { - return carapace.ActionFiles() - } - return git.ActionRefs(git.RefOption{}.Default()) - }), - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if util.HasPathPrefix(c.Value) { - return carapace.ActionFiles() - } - return git.ActionRefs(git.RefOption{}.Default()) - }), - ) - carapace.Gen(difftoolCmd).PositionalAnyCompletion( - carapace.ActionFiles(), + actionDiffArgs(difftoolCmd), ) carapace.Gen(difftoolCmd).DashAnyCompletion( - carapace.ActionFiles(), + carapace.ActionPositional(difftoolCmd), ) }