From 698f823dd926183a3a800787a8962e058366e19a Mon Sep 17 00:00:00 2001 From: Jordan Barrett <90195985+barrettj12@users.noreply.github.com.> Date: Sat, 5 Jul 2025 23:00:02 -0500 Subject: [PATCH] implement config for default editor --- cmd/clone.go | 29 +++++++++++++++++++----- cmd/new.go | 34 +++++++++++++++++++++++----- common/config/bindings.go | 27 ++++++++++++++++++++++ common/config/config.go | 47 +++++++++++++++++++++++++++++++++++++++ common/worktree.go | 9 ++++++-- go.mod | 1 + go.sum | 1 + test/tests/edit.sh | 4 ++++ 8 files changed, 139 insertions(+), 13 deletions(-) create mode 100644 common/config/bindings.go create mode 100644 common/config/config.go diff --git a/cmd/clone.go b/cmd/clone.go index fd5780f..4d09926 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/barrettj12/jit/common" + "github.com/barrettj12/jit/common/config" "github.com/barrettj12/jit/common/git" "github.com/barrettj12/jit/common/path" "github.com/barrettj12/jit/common/types" @@ -157,12 +158,30 @@ Create new branches using fmt.Printf("created initial worktree %s\n", currentBranch) // Open new branch for editing (maybe) - noEdit, err := cmd.Flags().GetBool("no-edit") - if err != nil { - fmt.Printf("WARNING could not get value of --no-edit flag, opening for editing anyway\n") - noEdit = false + var getShouldEditFromConfig = func() bool { + shouldEdit, err := config.EditNewBranches() + if err != nil { + // Default to false as not to be annoying + return false + } + return shouldEdit } - if !noEdit { + + var shouldEdit bool + if cmd.Flags().Changed("no-edit") { + noEdit, err := cmd.Flags().GetBool("no-edit") + if err == nil { + shouldEdit = !noEdit + } else { + // Fall back to config default + shouldEdit = getShouldEditFromConfig() + } + } else { + // Fall back to config default + shouldEdit = getShouldEditFromConfig() + } + + if shouldEdit { err = edit() if err != nil { fmt.Printf("WARNING could not open branch %q for editing: %v\n", currentBranch, err) diff --git a/cmd/new.go b/cmd/new.go index 925871c..de12ca0 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -2,13 +2,15 @@ package cmd import ( "fmt" + "strings" + "github.com/barrettj12/jit/common" + "github.com/barrettj12/jit/common/config" "github.com/barrettj12/jit/common/git" "github.com/barrettj12/jit/common/path" "github.com/barrettj12/jit/common/types" "github.com/barrettj12/jit/common/url" "github.com/spf13/cobra" - "strings" ) var newDocs = ` @@ -66,12 +68,31 @@ func New(cmd *cobra.Command, args []string) error { return fmt.Errorf("failed to create new branch: %w", err) } - noEdit, err := cmd.Flags().GetBool("no-edit") - if err != nil { - fmt.Printf("WARNING could not get value of --no-edit flag, will open new branch for editing anyway\n") - noEdit = false + // Open new branch for editing (maybe) + var getShouldEditFromConfig = func() bool { + shouldEdit, err := config.EditNewBranches() + if err != nil { + // Default to false as not to be annoying + return false + } + return shouldEdit } - if !noEdit { + + var shouldEdit bool + if cmd.Flags().Changed("no-edit") { + noEdit, err := cmd.Flags().GetBool("no-edit") + if err == nil { + shouldEdit = !noEdit + } else { + // Fall back to config default + shouldEdit = getShouldEditFromConfig() + } + } else { + // Fall back to config default + shouldEdit = getShouldEditFromConfig() + } + + if shouldEdit { err = edit() if err != nil { fmt.Printf("WARNING could not open branch %q for editing: %v\n", branchName, err) @@ -79,6 +100,7 @@ func New(cmd *cobra.Command, args []string) error { } return nil + } func newWorktreeBasedOnExistingBranch(branch types.LocalBranch) (types.LocalBranch, common.EditFunc, error) { diff --git a/common/config/bindings.go b/common/config/bindings.go new file mode 100644 index 0000000..52cc2fe --- /dev/null +++ b/common/config/bindings.go @@ -0,0 +1,27 @@ +package config + +import ( + "errors" +) + +// Editor returns the default editor. +func Editor() (string, error) { + // editor, err := readRepoConfig[string]("editor") + // if err != nil { + editor, err := readGlobalConfig[string]("editor") + if err != nil { + return "", errors.New("default editor not set") + } + // } + return editor, nil +} + +// EditNewBranches returns whether new branches should be automatically opened +// for editing. +func EditNewBranches() (bool, error) { + editNew, err := readGlobalConfig[bool]("edit-new") + if err != nil { + return false, errors.New("edit-new not set") + } + return editNew, nil +} diff --git a/common/config/config.go b/common/config/config.go new file mode 100644 index 0000000..9998ff4 --- /dev/null +++ b/common/config/config.go @@ -0,0 +1,47 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + + "gopkg.in/yaml.v3" +) + +// Read a config value from the global Jit config file at +// +// $HOME/.jit/config.yaml +// +// The provided type parameter defines the type that the value will be +// unmarshalled to. +func readGlobalConfig[T any](key string) (t T, err error) { + userHomeDir, err := getUserHomeDir() + if err != nil { + return t, fmt.Errorf("getting user home dir: %w", err) + } + globalConfigFilePath := filepath.Join(userHomeDir, ".jit/config.yaml") + return readConfigFile[T](globalConfigFilePath, key) +} + +// Read a key from a Jit config file. The format of the config file is a +// uni-level mapping of keys to values. The provided type parameter defines the +// type that the value will be unmarshalled to. +func readConfigFile[T any](filePath, key string) (t T, err error) { + file, err := os.Open(filePath) + if err != nil { + return t, fmt.Errorf("reading repo config: %w", err) + } + + var config map[string]T + // We will get an error for values that don't match type T, but we should + // ignore this, because we only care about the value corresponding to the + // given key. + _ = yaml.NewDecoder(file).Decode(&config) + if _, ok := config[key]; !ok { + return t, fmt.Errorf("key %q not defined in config file at %s", key, filePath) + } + return config[key], nil +} + +// These methods can be replaced for testing. +var getUserHomeDir = os.UserHomeDir diff --git a/common/worktree.go b/common/worktree.go index 73037db..a703670 100644 --- a/common/worktree.go +++ b/common/worktree.go @@ -2,10 +2,12 @@ package common import ( "fmt" + "strings" + + "github.com/barrettj12/jit/common/config" "github.com/barrettj12/jit/common/git" "github.com/barrettj12/jit/common/path" "github.com/barrettj12/jit/common/types" - "strings" ) // AddWorktree adds a worktree for the given branch. It assumes the branch @@ -97,8 +99,11 @@ func LookupWorktreeForBranch(branch types.LocalBranch) (path.Worktree, error) { type EditFunc func() error func EditWorktree(path path.Worktree) EditFunc { - editor := defaultEditor() + editor, err := config.Editor() return func() error { + if err != nil { + return err + } res := Exec(ExecArgs{ Cmd: editor, Args: []string{path.Path()}, diff --git a/go.mod b/go.mod index d248f2b..3008d32 100644 --- a/go.mod +++ b/go.mod @@ -7,4 +7,5 @@ require github.com/spf13/cobra v1.8.1 require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 912390a..76db3b1 100644 --- a/go.sum +++ b/go.sum @@ -7,4 +7,5 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/tests/edit.sh b/test/tests/edit.sh index 760569e..1b765a3 100644 --- a/test/tests/edit.sh +++ b/test/tests/edit.sh @@ -1,6 +1,10 @@ # Test `jit edit` command set -ex +# Set up config file with default editor +mkdir -p "$HOME/.jit" +echo 'editor: goland' > "$HOME/.jit/config.yaml" + # Set up test repo setup_test_repo edit/repo1 jit clone edit/repo1 --fork=false