diff --git a/cmd/branch.go b/cmd/branch.go index 726d159..e801438 100644 --- a/cmd/branch.go +++ b/cmd/branch.go @@ -14,7 +14,7 @@ import ( func (h *Handler) Branch() *ffcli.Command { fs := flag.NewFlagSet("branch", flag.ContinueOnError) noFetchFlag := fs.Bool("no-fetch", false, "Skip fetching") - fs.BoolVar(noFetchFlag, "nf", *noFetchFlag, "--no-fetch") + fs.BoolVar(noFetchFlag, "n", *noFetchFlag, "--no-fetch") baseFlag := fs.String("base", "main", "Ref to base from") fs.StringVar(baseFlag, "b", *baseFlag, "--base") listFlag := fs.Bool("list", false, "List branches available") diff --git a/cmd/cd.go b/cmd/cd.go new file mode 100644 index 0000000..93e591b --- /dev/null +++ b/cmd/cd.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "context" + "flag" + "fmt" + "os" + "os/exec" + "runtime" + + "go.jolheiser.com/git-ea/config" + + "github.com/peterbourgon/ff/v3/ffcli" +) + +func (h *Handler) CD() *ffcli.Command { + fs := flag.NewFlagSet("cd", flag.ContinueOnError) + printFlag := fs.Bool("print", false, "Print workspace dir instead of spawning a shell") + fs.BoolVar(printFlag, "p", *printFlag, "--print") + return &ffcli.Command{ + Name: "cd", + FlagSet: fs, + ShortUsage: "cd [workspace=base]", + ShortHelp: "Open a shell in the specified `workspace`", + Exec: func(ctx context.Context, _ []string) error { + dir := h.Config.Workspace() + if fs.NArg() > 0 { + dir = h.Config.WorkspaceBranch(fs.Arg(0)) + } + + if *printFlag { + fmt.Println(dir) + return nil + } + + command, args := cd(h.Config) + cmd := exec.CommandContext(ctx, command, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = dir + return cmd.Run() + }, + } +} + +func cd(cfg *config.Config) (string, []string) { + if cfg.CD.Command != "" { + return cfg.CD.Command, cfg.CD.Args + } + var shell string + switch runtime.GOOS { + case "windows": + shell = "powershell.exe" + case "linux": + shell = "/bin/bash" + } + return shell, nil +} diff --git a/cmd/cmd.go b/cmd/cmd.go index 1767ce0..7415251 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -45,9 +45,10 @@ func New() (*ffcli.Command, error) { ShortUsage: "git-ea ", ShortHelp: "git-ea is the base command", Subcommands: []*ffcli.Command{ - handler.Cleanup(), handler.Backport(), handler.Branch(), + handler.Cleanup(), + handler.CD(), handler.Frontport(), handler.IDE(), handler.Init(), @@ -62,16 +63,7 @@ func New() (*ffcli.Command, error) { return nil } - dir := cfg.Base - if fs.NArg() > 0 { - if strings.EqualFold(fs.Arg(0), "help") { - fmt.Println(ffcli.DefaultUsageFunc(c)) - return nil - } - dir = cfg.WorkspaceBranch(fs.Arg(0)) - } - - fmt.Println(dir) + fmt.Println(ffcli.DefaultUsageFunc(c)) return nil } return c, nil diff --git a/cmd/ide.go b/cmd/ide.go index 991919b..0c27ece 100644 --- a/cmd/ide.go +++ b/cmd/ide.go @@ -12,6 +12,8 @@ import ( func (h *Handler) IDE() *ffcli.Command { fs := flag.NewFlagSet("ide", flag.ContinueOnError) + guiFlag := fs.Bool("gui", false, "Prefer GUI editor") + fs.BoolVar(guiFlag, "g", *guiFlag, "--gui") return &ffcli.Command{ Name: "ide", FlagSet: fs, @@ -39,7 +41,7 @@ func (h *Handler) IDE() *ffcli.Command { } path := h.Config.WorkspaceBranch(branch) - cmd := exec.Command(getIDE(), path) + cmd := exec.Command(getIDE(*guiFlag), path) cmd.Dir = path cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout @@ -49,13 +51,25 @@ func (h *Handler) IDE() *ffcli.Command { } } -func getIDE() string { - for _, ide := range []string{ +func getIDE(preferGUI bool) string { + term := []string{ "hx", "nvim", + } + gui := []string{ + "lapce", "goland", + } + def := []string{ "vi", - } { + } + + ides := append(term, gui...) + if preferGUI { + ides = append(gui, term...) + } + + for _, ide := range append(ides, def...) { if i, err := exec.LookPath(ide); err == nil { return i } diff --git a/config/config.go b/config/config.go index 76d65c4..7020f92 100644 --- a/config/config.go +++ b/config/config.go @@ -8,8 +8,14 @@ import ( "path/filepath" ) +type CD struct { + Command string `json:"command"` + Args []string `json:"args"` +} + type Config struct { Base string `json:"base"` + CD CD `json:"cd"` } func (c *Config) Workspace() string { @@ -40,9 +46,13 @@ func (c *Config) Branches() ([]string, error) { } func path() (string, error) { - userCfgDir, err := os.UserConfigDir() - if err != nil { - return "", err + userCfgDir, ok := os.LookupEnv("XDG_CONFIG_HOME") + if !ok { + var err error + userCfgDir, err = os.UserConfigDir() + if err != nil { + return "", err + } } cfgDir := filepath.Join(userCfgDir, "git-ea") return filepath.Join(cfgDir, "config.json"), os.MkdirAll(cfgDir, os.ModePerm) @@ -63,7 +73,7 @@ func Load() (*Config, error) { if err != nil { return nil, err } - if _, err := fi.WriteString("{}"); err != nil { + if _, err := fi.WriteString(`{}`); err != nil { return nil, err } if _, err := fi.Seek(0, 0); err != nil { diff --git a/contrib/git-ea.nu b/contrib/git-ea.nu new file mode 100644 index 0000000..b67caef --- /dev/null +++ b/contrib/git-ea.nu @@ -0,0 +1,70 @@ +def "nu-complete git-ea branches" [] { + ^git-ea branch -l | lines | each { |line| $line | str trim } +} + +# Backport +export extern "git ea backport" [ + --from(-f) # From branch + --list(-l) # Open a web browser to view needed backports + --push(-p) # Push immediately + --to(-t) # To branch +] + +# Branch +export extern "git ea branch" [ + name: string # Branch name + --base(-b) # Branch base + --ide(-i) # Open an IDE for the new branch + --list(-l) # List branches + --no-fetch(-n) # Skip fetching +] + +# CD +export extern "git ea cd" [ + workspace?: string@"nu-complete git-ea branches" # Workspace + --print(-p) # Print instead of spawning shell +] + +# Cleanup +export extern "git ea cleanup" [ + ...branches: string # Branch names + --force(-f) # Force cleanup + --prune(-p) # Prune worktrees +] + +# Frontport +export extern "git ea frontport" [ + --from(-f) # From branch + --push(-p) # Push immediately + --to(-t) # To branch +] + +# IDE +export extern "git ea ide" [ + workspace?: string@"nu-complete git-ea branches" # Workspace + --gui(-g) # Prefer GUI +] + +# Init +export extern "git ea init" [] + +# Post +export extern "git ea post" [ + --author(-a) # Author + --changelog(-c) # Changelog (no header) + --milestone(-m) # Milestone + --output(-o) # Output file (default: `content/post/release-of-${milestone}.md`) +] + +# PR +export extern "git ea pr" [ + index: int # PR index + --ide(-i) # Open IDE for this PR +] + +# Tag +export extern "git ea tag" [ + branch?: string # The branch to tag + --push(-p) # Push immediately +] +