summaryrefslogtreecommitdiffstats
path: root/pkg/config
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/config')
-rw-r--r--pkg/config/app_config.go222
-rw-r--r--pkg/config/config_default_platform.go10
-rw-r--r--pkg/config/config_linux.go10
-rw-r--r--pkg/config/config_windows.go10
-rw-r--r--pkg/config/dummies.go10
-rw-r--r--pkg/config/os_config.go10
-rw-r--r--pkg/config/user_config.go215
7 files changed, 365 insertions, 122 deletions
diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go
index 6558f9d3b..db0d56558 100644
--- a/pkg/config/app_config.go
+++ b/pkg/config/app_config.go
@@ -1,28 +1,27 @@
package config
import (
- "bytes"
"io/ioutil"
"os"
"path/filepath"
- "github.com/shibukawa/configdir"
- "github.com/spf13/viper"
- yaml "gopkg.in/yaml.v2"
+ "github.com/OpenPeeDeeP/xdg"
+ yaml "github.com/jesseduffield/yaml"
)
// AppConfig contains the base configuration fields required for lazygit.
type AppConfig struct {
- Debug bool `long:"debug" env:"DEBUG" default:"false"`
- Version string `long:"version" env:"VERSION" default:"unversioned"`
- Commit string `long:"commit" env:"COMMIT"`
- BuildDate string `long:"build-date" env:"BUILD_DATE"`
- Name string `long:"name" env:"NAME" default:"lazygit"`
- BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
- UserConfig *viper.Viper
- UserConfigDir string
- AppState *AppState
- IsNewRepo bool
+ Debug bool `long:"debug" env:"DEBUG" default:"false"`
+ Version string `long:"version" env:"VERSION" default:"unversioned"`
+ Commit string `long:"commit" env:"COMMIT"`
+ BuildDate string `long:"build-date" env:"BUILD_DATE"`
+ Name string `long:"name" env:"NAME" default:"lazygit"`
+ BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
+ UserConfig *UserConfig
+ UserConfigDir string
+ UserConfigPath string
+ AppState *AppState
+ IsNewRepo bool
}
// AppConfigurer interface allows individual app config structs to inherit Fields
@@ -34,10 +33,11 @@ type AppConfigurer interface {
GetBuildDate() string
GetName() string
GetBuildSource() string
- GetUserConfig() *viper.Viper
+ GetUserConfig() *UserConfig
GetUserConfigDir() string
+ GetUserConfigPath() string
GetAppState() *AppState
- WriteToUserConfig(string, interface{}) error
+ WriteToUserConfig(func(*UserConfig) error) error
SaveAppState() error
LoadAppState() error
SetIsNewRepo(bool)
@@ -46,7 +46,12 @@ type AppConfigurer interface {
// NewAppConfig makes a new app config
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool) (*AppConfig, error) {
- userConfig, userConfigPath, err := LoadConfig("config", true)
+ configDir, err := findOrCreateConfigDir(name)
+ if err != nil {
+ return nil, err
+ }
+
+ userConfig, err := loadUserConfigWithDefaults(configDir)
if err != nil {
return nil, err
}
@@ -56,16 +61,17 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
}
appConfig := &AppConfig{
- Name: "lazygit",
- Version: version,
- Commit: commit,
- BuildDate: date,
- Debug: debuggingFlag,
- BuildSource: buildSource,
- UserConfig: userConfig,
- UserConfigDir: filepath.Dir(userConfigPath),
- AppState: &AppState{},
- IsNewRepo: false,
+ Name: "lazygit",
+ Version: version,
+ Commit: commit,
+ BuildDate: date,
+ Debug: debuggingFlag,
+ BuildSource: buildSource,
+ UserConfig: userConfig,
+ UserConfigDir: configDir,
+ UserConfigPath: filepath.Join(configDir, "config.yml"),
+ AppState: &AppState{},
+ IsNewRepo: false,
}
if err := appConfig.LoadAppState(); err != nil {
@@ -75,6 +81,51 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg
return appConfig, nil
}
+func findOrCreateConfigDir(projectName string) (string, error) {
+ // chucking my name there is not for vanity purposes, the xdg spec (and that
+ // function) requires a vendor name. May as well line up with github
+ configDirs := xdg.New("jesseduffield", projectName)
+ folder := configDirs.ConfigHome()
+
+ err := os.MkdirAll(folder, 0755)
+ if err != nil {
+ return "", err
+ }
+
+ return folder, nil
+}
+
+func loadUserConfigWithDefaults(configDir string) (*UserConfig, error) {
+ return loadUserConfig(configDir, GetDefaultConfig())
+}
+
+func loadUserConfig(configDir string, base *UserConfig) (*UserConfig, error) {
+ fileName := filepath.Join(configDir, "config.yml")
+
+ if _, err := os.Stat(fileName); err != nil {
+ if os.IsNotExist(err) {
+ file, err := os.Create(fileName)
+ if err != nil {
+ return nil, err
+ }
+ file.Close()
+ } else {
+ return nil, err
+ }
+ }
+
+ content, err := ioutil.ReadFile(fileName)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := yaml.Unmarshal(content, base); err != nil {
+ return nil, err
+ }
+
+ return base, nil
+}
+
// GetIsNewRepo returns known repo boolean
func (c *AppConfig) GetIsNewRepo() bool {
return c.IsNewRepo
@@ -117,10 +168,15 @@ func (c *AppConfig) GetBuildSource() string {
}
// GetUserConfig returns the user config
-func (c *AppConfig) GetUserConfig() *viper.Viper {
+func (c *AppConfig) GetUserConfig() *UserConfig {
return c.UserConfig
}
+// GetUserConfig returns the user config
+func (c *AppConfig) GetUserConfigPath() string {
+ return c.UserConfigPath
+}
+
// GetAppState returns the app state
func (c *AppConfig) GetAppState() *AppState {
return c.AppState
@@ -130,78 +186,40 @@ func (c *AppConfig) GetUserConfigDir() string {
return c.UserConfigDir
}
-func newViper(filename string) (*viper.Viper, error) {
- v := viper.New()
- v.SetConfigType("yaml")
- v.SetConfigName(filename)
- return v, nil
-}
-
-// LoadConfig gets the user's config
-func LoadConfig(filename string, withDefaults bool) (*viper.Viper, string, error) {
- v, err := newViper(filename)
- if err != nil {
- return nil, "", err
- }
- if withDefaults {
- if err = LoadDefaults(v, GetDefaultConfig()); err != nil {
- return nil, "", err
- }
- if err = LoadDefaults(v, GetPlatformDefaultConfig()); err != nil {
- return nil, "", err
- }
- }
- configPath, err := LoadAndMergeFile(v, filename+".yml")
+func configFilePath(filename string) (string, error) {
+ folder, err := findOrCreateConfigDir("lazygit")
if err != nil {
- return nil, "", err
+ return "", err
}
- return v, configPath, nil
-}
-
-// LoadDefaults loads in the defaults defined in this file
-func LoadDefaults(v *viper.Viper, defaults []byte) error {
- return v.MergeConfig(bytes.NewBuffer(defaults))
-}
-func prepareConfigFile(filename string) (string, error) {
- // chucking my name there is not for vanity purposes, the xdg spec (and that
- // function) requires a vendor name. May as well line up with github
- configDirs := configdir.New("jesseduffield", "lazygit")
- folder := configDirs.QueryFolderContainsFile(filename)
- if folder == nil {
- // create the file as empty
- folders := configDirs.QueryFolders(configdir.Global)
- if err := folders[0].WriteFile(filename, []byte{}); err != nil {
- return "", err
- }
- folder = configDirs.QueryFolderContainsFile(filename)
- }
- return filepath.Join(folder.Path, filename), nil
+ return filepath.Join(folder, filename), nil
}
-// LoadAndMergeFile Loads the config/state file, creating
-// the file has an empty one if it does not exist
-func LoadAndMergeFile(v *viper.Viper, filename string) (string, error) {
- configPath, err := prepareConfigFile(filename)
+// WriteToUserConfig allows you to set a value on the user config to be saved
+// note that if you set a zero-value, it may be ignored e.g. a false or 0 or
+// empty string this is because we are using the omitempty yaml directive so
+// that we don't write a heap of zero values to the user's config.yml
+func (c *AppConfig) WriteToUserConfig(updateConfig func(*UserConfig) error) error {
+ userConfig, err := loadUserConfig(c.UserConfigDir, &UserConfig{})
if err != nil {
- return "", err
+ return err
}
- v.AddConfigPath(filepath.Dir(configPath))
- return configPath, v.MergeInConfig()
-}
+ if err := updateConfig(userConfig); err != nil {
+ return err
+ }
-// WriteToUserConfig adds a key/value pair to the user's config and saves it
-func (c *AppConfig) WriteToUserConfig(key string, value interface{}) error {
- // reloading the user config directly (without defaults) so that we're not
- // writing any defaults back to the user's config
- v, _, err := LoadConfig("config", false)
+ file, err := os.OpenFile(c.ConfigFilename(), os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return err
}
- v.Set(key, value)
- return v.WriteConfig()
+ return yaml.NewEncoder(file).Encode(userConfig)
+}
+
+// ConfigFilename returns the filename of the current config file
+func (c *AppConfig) ConfigFilename() string {
+ return filepath.Join(c.UserConfigDir, "config.yml")
}
// SaveAppState marshalls the AppState struct and writes it to the disk
@@ -211,7 +229,7 @@ func (c *AppConfig) SaveAppState() error {
return err
}
- filepath, err := prepareConfigFile("state.yml")
+ filepath, err := configFilePath("state.yml")
if err != nil {
return err
}
@@ -221,7 +239,7 @@ func (c *AppConfig) SaveAppState() error {
// LoadAppState loads recorded AppState from file
func (c *AppConfig) LoadAppState() error {
- filepath, err := prepareConfigFile("state.yml")
+ filepath, err := configFilePath("state.yml")
if err != nil {
return err
}
@@ -235,8 +253,20 @@ func (c *AppConfig) LoadAppState() error {
return yaml.Unmarshal(appStateBytes, c.AppState)
}
-// GetDefaultConfig returns the application default configuration
-func GetDefaultConfig() []byte {
+func GetDefaultConfig() *UserConfig {
+ userConfig := &UserConfig{}
+
+ if err := yaml.Unmarshal(GetDefaultConfigBytes(), userConfig); err != nil {
+ panic(err)
+ }
+
+ userConfig.OS = GetPlatformDefaultConfig()
+
+ return userConfig
+}
+
+// GetDefaultConfigBytes returns the application default configuration
+func GetDefaultConfigBytes() []byte {
return []byte(
`gui:
## stuff relating to the UI
@@ -414,12 +444,6 @@ func getDefaultAppState() []byte {
`)
}
-func globalConfigDir() string {
- configDirs := configdir.New("jesseduffield", "lazygit")
- configDir := configDirs.QueryFolders(configdir.Global)[0]
- return configDir.Path
-}
-
-func LogPath() string {
- return filepath.Join(globalConfigDir(), "development.log")
+func LogPath() (string, error) {
+ return configFilePath("development.log")
}
diff --git a/pkg/config/config_default_platform.go b/pkg/config/config_default_platform.go
index df205c0d7..e9e2f63ba 100644
--- a/pkg/config/config_default_platform.go
+++ b/pkg/config/config_default_platform.go
@@ -3,9 +3,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
-func GetPlatformDefaultConfig() []byte {
- return []byte(
- `os:
- openCommand: 'open {{filename}}'
- openLinkCommand: 'open {{link}}'`)
+func GetPlatformDefaultConfig() OSConfig {
+ return OSConfig{
+ OpenCommand: "open {{filename}}",
+ OpenLinkCommand: "open {{link}}",
+ }
}
diff --git a/pkg/config/config_linux.go b/pkg/config/config_linux.go
index 2dfbdb1c6..b3d7f42b8 100644
--- a/pkg/config/config_linux.go
+++ b/pkg/config/config_linux.go
@@ -1,9 +1,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
-func GetPlatformDefaultConfig() []byte {
- return []byte(
- `os:
- openCommand: 'sh -c "xdg-open {{filename}} >/dev/null"'
- openLinkCommand: 'sh -c "xdg-open {{link}} >/dev/null"'`)
+func GetPlatformDefaultConfig() OSConfig {
+ return OSConfig{
+ OpenCommand: `sh -c "xdg-open {{filename}} >/dev/null"`,
+ OpenLinkCommand: `sh -c "xdg-open {{link}} >/dev/null"`,
+ }
}
diff --git a/pkg/config/config_windows.go b/pkg/config/config_windows.go
index 6f6560316..cea722424 100644
--- a/pkg/config/config_windows.go
+++ b/pkg/config/config_windows.go
@@ -1,9 +1,9 @@
package config
// GetPlatformDefaultConfig gets the defaults for the platform
-func GetPlatformDefaultConfig() []byte {
- return []byte(
- `os:
- openCommand: 'cmd /c "start "" {{filename}}"'
- openLinkCommand: 'cmd /c "start "" {{link}}"'`)
+func GetPlatformDefaultConfig() OSConfig {
+ return OSConfig{
+ OpenCommand: `cmd /c "start "" {{filename}}"`,
+ OpenLinkCommand: `cmd /c "start "" {{link}}"`,
+ }
}
diff --git a/pkg/config/dummies.go b/pkg/config/dummies.go
index 034d9b88b..40548d732 100644
--- a/pkg/config/dummies.go
+++ b/pkg/config/dummies.go
@@ -1,17 +1,11 @@
package config
import (
- "github.com/spf13/viper"
- yaml "gopkg.in/yaml.v2"
+ yaml "github.com/jesseduffield/yaml"
)
// NewDummyAppConfig creates a new dummy AppConfig for testing
func NewDummyAppConfig() *AppConfig {
- userConfig := viper.New()
- userConfig.SetConfigType("yaml")
- if err := LoadDefaults(userConfig, GetDefaultConfig()); err != nil {
- panic(err)
- }
appConfig := &AppConfig{
Name: "lazygit",
Version: "unversioned",
@@ -19,7 +13,7 @@ func NewDummyAppConfig() *AppConfig {
BuildDate: "",
Debug: false,
BuildSource: "",
- UserConfig: userConfig,
+ UserConfig: GetDefaultConfig(),
}
_ = yaml.Unmarshal([]byte{}, appConfig.AppState)
return appConfig
diff --git a/pkg/config/os_config.go b/pkg/config/os_config.go
new file mode 100644
index 000000000..b24e0ced3
--- /dev/null
+++ b/pkg/config/os_config.go
@@ -0,0 +1,10 @@
+package config
+
+// OSConfig contains config on the level of the os
+type OSConfig struct {
+ // OpenCommand is the command for opening a file
+ OpenCommand string `yaml:"openCommand,omitempty"`
+
+ // OpenCommand is the command for opening a link
+ OpenLinkCommand string `yaml:"openLinkCommand,omitempty"`
+}
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
new file mode 100644
index 000000000..e058d5c5a
--- /dev/null
+++ b/pkg/config/user_config.go
@@ -0,0 +1,215 @@
+package config
+
+type CommitPrefixConfig struct {
+ Pattern string `yaml:"pattern"`
+ Replace string `yaml:"replace"`
+}
+
+type ThemeConfig struct {
+ LightTheme bool `yaml:"lightTheme"`
+ ActiveBorderColor []string `yaml:"activeBorderColor"`
+ InactiveBorderColor []string `yaml:"inactiveBorderColor"`
+ OptionsTextColor []string `yaml:"optionsTextColor"`
+ SelectedLineBgColor []string `yaml:"selectedLineBgColor"`
+ SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
+}
+
+type CustomCommandMenuOption struct {
+ Name string `yaml:"name"`
+ Description string `yaml:"description"`
+ Value string `yaml:"value"`
+}
+
+type CustomCommandPrompt struct {
+ Type string `yaml:"type"` // one of 'input' and 'menu'
+ Title string `yaml:"title"`
+
+ // this only apply to prompts
+ InitialValue string `yaml:"initialValue"`
+
+ // this only applies to menus
+ Options []CustomCommandMenuOption
+}
+
+type CustomCommand struct {
+ Key string `yaml:"key"`
+ Context string `yaml:"context"`
+ Command string `yaml:"command"`
+ Subprocess bool `yaml:"subprocess"`
+ Prompts []CustomCommandPrompt `yaml:"prompts"`
+ LoadingText string `yaml:"loadingText"`
+ Description string `yaml:"description"`
+}
+
+type UserConfig struct {
+ Gui struct {
+ ScrollHeight int `yaml:"scrollHeight"`
+ ScrollPastBottom bool `yaml:"scrollPastBottom"`
+ MouseEvents bool `yaml:"mouseEvents"`
+ SkipUnstageLineWarning bool `yaml:"skipUnstageLineWarning"`
+ SkipStashWarning bool `yaml:"skipStashWarning"`
+ SidePanelWidth float64 `yaml:"sidePanelWidth"`
+ ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
+ MainPanelSplitMode string `yaml:"mainPanelSplitMode"`
+ Theme ThemeConfig `yaml:"theme"`
+ CommitLength struct {
+ Show bool `yaml:"show"`
+ } `yaml:"commitLength"`
+ } `yaml:"gui"`
+ Git struct {
+ Paging struct {
+ ColorArg string `yaml:"colorArg"`
+ Pager string `yaml:"pager"`
+ UseConfig bool `yaml:"useConfig"`
+ } `yaml:"paging"`
+ Merging struct {
+ ManualCommit bool `yaml:"manualCommit"`
+ Args string `yaml:"args"`
+ } `yaml:"merging"`
+ Pull struct {
+ Mode string `yaml:"mode"`
+ } `yaml:"pull"`
+ SkipHookPrefix string `yaml:"skipHookPrefix"`
+ AutoFetch bool `yaml:"autoFetch"`
+ BranchLogCmd string `yaml:"branchLogCmd"`
+ OverrideGpg bool `yaml:"overrideGpg"`
+ DisableForcePushing bool `yaml:"disableForcePushing"`
+ CommitPrefixes map[string]CommitPrefixConfig `yaml:"commitPrefixes"`
+ } `yaml:"git"`
+ Update struct {
+ Method string `yaml:"method"`
+ Days int64 `yaml:"days"`
+ } `yaml:"update"`
+ Reporting string `yaml:"reporting"`
+ SplashUpdatesIndex int `yaml:"splashUpdatesIndex"`
+ ConfirmOnQuit bool `yaml:"confirmOnQuit"`
+ QuitOnTopLevelReturn bool `yaml:"quitOnTopLevelReturn"`
+ Keybinding struct {
+ Universal struct {
+ Quit string `yaml:"quit"`
+ QuitAlt1 string `yaml:"quit-alt1"`
+ Return string `yaml:"return"`
+ QuitWithoutChangingDirectory string `yaml:"quitWithoutChangingDirectory"`
+ TogglePanel string `yaml:"togglePanel"`
+ PrevItem string `yaml:"prevItem"`
+ NextItem string `yaml:"nextItem"`
+ PrevItemAlt string `yaml:"prevItem-alt"`
+ NextItemAlt string `yaml:"nextItem-alt"`
+ PrevPage string `yaml:"prevPage"`
+ NextPage string `yaml:"nextPage"`
+ GotoTop string `yaml:"gotoTop"`
+ GotoBottom string `yaml:"gotoBottom"`
+ PrevBlock string `yaml:"prevBlock"`
+ NextBlock string `yaml:"nextBlock"`
+ PrevBlockAlt string `yaml:"prevBlock-alt"`
+ NextBlockAlt string `yaml:"nextBlock-alt"`
+ NextMatch string `yaml:"nextMatch"`
+ PrevMatch string `yaml:"prevMatch"`
+ StartSearch string `yaml:"startSearch"`
+ OptionMenu string `yaml:"optionMenu"`
+ OptionMenuAlt1 string `yaml:"optionMenu-alt1"`
+ Select string `yaml:"select"`
+ GoInto string `yaml:"goInto"`
+ Confirm string `yaml:"confirm"`
+ ConfirmAlt1 string `yaml:"confirm-alt1"`
+ Remove string `yaml:"remove"`
+ New string `yaml:"new"`
+ Edit string `yaml:"edit"`
+ OpenFile string `yaml:"openFile"`
+ ScrollUpMain string `yaml:"scrollUpMain"`
+ ScrollDownMain string `yaml:"scrollDownMain"`
+ ScrollUpMainAlt1 string `yaml:"scrollUpMain-alt1"`
+ ScrollDownMainAlt1 string `yaml:"scrollDownMain-alt1"`
+ ScrollUpMainAlt2 string `yaml:"scrollUpMain-alt2"`
+ ScrollDownMainAlt2 string `yaml:"scrollDownMain-alt2"`
+ ExecuteCustomCommand string `yaml:"executeCustomCommand"`
+ CreateRebaseOptionsMenu string `yaml:"createRebaseOptionsMenu"`
+ PushFiles string `yaml:"pushFiles"`
+ PullFiles string `yaml:"pullFiles"`
+ Refresh string `yaml:"refresh"`
+ CreatePatchOptionsMenu string `yaml:"createPatchOptionsMenu"`
+ NextTab string `yaml:"nextTab"`
+ PrevTab string `yaml:"prevTab"`
+ NextScreenMode string `yaml:"nextScreenMode"`
+ PrevScreenMode string `yaml:"prevScreenMode"`
+ Undo string `yaml:"undo"`
+ Redo string `yaml:"redo"`
+ FilteringMenu string `yaml:"filteringMenu"`
+ DiffingMenu string `yaml:"diffingMenu"`
+ DiffingMenuAlt string `yaml:"diffingMenu-alt"`
+ CopyToClipboard string `yaml:"copyToClipboard"`
+ } `yaml:"universal"`
+ Status struct {
+ CheckForUpdate string `yaml:"checkForUpdate"`
+ RecentRepos string `yaml:"recentRepos"`
+ } `yaml:"status"`
+ Files struct {
+ CommitChanges string `yaml:"commitChanges"`
+ CommitChangesWithoutHook string `yaml:"commitChangesWithoutHook"`
+ AmendLastCommit string `yaml:"amendLastCommit"`
+ CommitChangesWithEditor string `yaml:"commitChangesWithEditor"`
+ IgnoreFile string `yaml:"ignoreFile"`
+ RefreshFiles string `yaml:"refreshFiles"`
+ StashAllChanges string `yaml:"stashAllChanges"`
+ ViewStashOptions string `yaml:"viewStashOptions"`
+ ToggleStagedAll string `yaml:"toggleStagedAll"`
+ ViewResetOptions string `yaml:"viewResetOptions"`
+ Fetch string `yaml:"fetch"`
+ } `yaml:"files"`
+ Branches struct {
+ CreatePullRequest string `yaml:"createPullRequest"`
+ CheckoutBranchByName string `yaml:"checkoutBranchByName"`
+ ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
+ RebaseBranch string `yaml:"rebaseBranch"`
+ RenameBranch string `yaml:"renameBranch"`
+ MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
+ ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
+ FastForward string `yaml:"fastForward"`
+ PushTag string `yaml:"pushTag"`
+ SetUpstream string `yaml:"setUpstream"`
+ FetchRemote string `yaml:"fetchRemote"`
+ } `yaml:"branches"`
+ Commits struct {
+ SquashDown string `yaml:"squashDown"`
+ RenameCommit string `yaml:"renameCommit"`
+ RenameCommitWithEditor string `yaml:"renameCommitWithEditor"`
+ ViewResetOptions string `yaml:"viewResetOptions"`
+ MarkCommitAsFixup string `yaml:"markCommitAsFixup"`
+ CreateFixupCommit string `yaml:"createFixupCommit"`
+ SquashAboveCommits string `yaml:"squashAboveCommits"`
+ MoveDownCommit string `yaml:"moveDownCommit"`
+ MoveUpCommit string `yaml:"moveUpCommit"`
+ AmendToCommit string `yaml:"amendToCommit"`
+ PickCommit string `yaml:"pickCommit"`
+ RevertCommit string `yaml:"revertCommit"`
+ CherryPickCopy string `yaml:"cherryPickCopy"`
+ CherryPickCopyRange string `yaml:"cherryPickCopyRange"`
+ PasteCommits string `yaml:"pasteCommits"`
+ TagCommit string `yaml:"tagCommit"`
+ CheckoutCommit string `yaml:"checkoutCommit"`
+ ResetCherryPick string `yaml:"resetCherryPick"`
+ } `yaml:"commits"`
+ Stash struct {
+ PopStash string `yaml:"popStash"`
+ } `yaml:"stash"`
+ CommitFiles struct {
+ CheckoutCommitFile string `yaml:"checkoutCommitFile"`
+ } `yaml:"commitFiles"`
+ Main struct {
+ ToggleDragSelect string `yaml:"toggleDragSelect"`
+ ToggleDragSelectAlt string `yaml:"toggleDragSelect-alt"`
+ ToggleSelectHunk string `yaml:"toggleSelectHunk"`
+ PickBothHunks string `yaml:"pickBothHunks"`
+ } `yaml:"main"`
+ Submodules struct {
+ Init string `yaml:"init"`
+ Update string `yaml:"update"`
+ BulkMenu string `yaml:"bulkMenu"`
+ } `yaml:"submodules"`
+ } `yaml:"keybinding"`
+ // OS determines what defaults are set for opening files and links
+ OS OSConfig `yaml:"os,omitempty"`
+ StartupPopupVersion int `yaml:"startupPopupVersion"`
+ CustomCommands []CustomCommand `yaml:"customCommands"`
+ Services map[string]string `yaml:"services"`
+}