mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-19 21:28:28 +02:00
with gui.scrollPastBottom option true, lazygit let user scroll past the bottom - which is default if option is false, user cannot scroll further when bottom of file has appeared in mainView
258 lines
6.3 KiB
Go
258 lines
6.3 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
|
|
"github.com/shibukawa/configdir"
|
|
"github.com/spf13/viper"
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
// 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
|
|
AppState *AppState
|
|
}
|
|
|
|
// AppConfigurer interface allows individual app config structs to inherit Fields
|
|
// from AppConfig and still be used by lazygit.
|
|
type AppConfigurer interface {
|
|
GetDebug() bool
|
|
GetVersion() string
|
|
GetCommit() string
|
|
GetBuildDate() string
|
|
GetName() string
|
|
GetBuildSource() string
|
|
GetUserConfig() *viper.Viper
|
|
GetAppState() *AppState
|
|
WriteToUserConfig(string, string) error
|
|
SaveAppState() error
|
|
LoadAppState() error
|
|
}
|
|
|
|
// NewAppConfig makes a new app config
|
|
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag *bool) (*AppConfig, error) {
|
|
userConfig, err := LoadConfig("config", true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
appConfig := &AppConfig{
|
|
Name: "lazygit",
|
|
Version: version,
|
|
Commit: commit,
|
|
BuildDate: date,
|
|
Debug: *debuggingFlag,
|
|
BuildSource: buildSource,
|
|
UserConfig: userConfig,
|
|
AppState: &AppState{},
|
|
}
|
|
|
|
if err := appConfig.LoadAppState(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return appConfig, nil
|
|
}
|
|
|
|
// GetDebug returns debug flag
|
|
func (c *AppConfig) GetDebug() bool {
|
|
return c.Debug
|
|
}
|
|
|
|
// GetVersion returns debug flag
|
|
func (c *AppConfig) GetVersion() string {
|
|
return c.Version
|
|
}
|
|
|
|
// GetCommit returns debug flag
|
|
func (c *AppConfig) GetCommit() string {
|
|
return c.Commit
|
|
}
|
|
|
|
// GetBuildDate returns debug flag
|
|
func (c *AppConfig) GetBuildDate() string {
|
|
return c.BuildDate
|
|
}
|
|
|
|
// GetName returns debug flag
|
|
func (c *AppConfig) GetName() string {
|
|
return c.Name
|
|
}
|
|
|
|
// GetBuildSource returns the source of the build. For builds from goreleaser
|
|
// this will be binaryBuild
|
|
func (c *AppConfig) GetBuildSource() string {
|
|
return c.BuildSource
|
|
}
|
|
|
|
// GetUserConfig returns the user config
|
|
func (c *AppConfig) GetUserConfig() *viper.Viper {
|
|
return c.UserConfig
|
|
}
|
|
|
|
// GetAppState returns the app state
|
|
func (c *AppConfig) GetAppState() *AppState {
|
|
return c.AppState
|
|
}
|
|
|
|
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, 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
|
|
}
|
|
}
|
|
if err = LoadAndMergeFile(v, filename+".yml"); err != nil {
|
|
return nil, err
|
|
}
|
|
return v, 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
|
|
}
|
|
|
|
// LoadAndMergeFile Loads the config/state file, creating
|
|
// the file as an empty one if it does not exist
|
|
func LoadAndMergeFile(v *viper.Viper, filename string) error {
|
|
configPath, err := prepareConfigFile(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v.AddConfigPath(filepath.Dir(configPath))
|
|
return v.MergeInConfig()
|
|
}
|
|
|
|
// WriteToUserConfig adds a key/value pair to the user's config and saves it
|
|
func (c *AppConfig) WriteToUserConfig(key, value string) 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)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
v.Set(key, value)
|
|
return v.WriteConfig()
|
|
}
|
|
|
|
// SaveAppState marhsalls the AppState struct and writes it to the disk
|
|
func (c *AppConfig) SaveAppState() error {
|
|
marshalledAppState, err := yaml.Marshal(c.AppState)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
filepath, err := prepareConfigFile("state.yml")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ioutil.WriteFile(filepath, marshalledAppState, 0644)
|
|
}
|
|
|
|
// LoadAppState loads recorded AppState from file
|
|
func (c *AppConfig) LoadAppState() error {
|
|
filepath, err := prepareConfigFile("state.yml")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appStateBytes, err := ioutil.ReadFile(filepath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(appStateBytes) == 0 {
|
|
return yaml.Unmarshal(getDefaultAppState(), c.AppState)
|
|
}
|
|
return yaml.Unmarshal(appStateBytes, c.AppState)
|
|
}
|
|
|
|
// GetDefaultConfig returns the application default configuration
|
|
func GetDefaultConfig() []byte {
|
|
return []byte(
|
|
`gui:
|
|
## stuff relating to the UI
|
|
scrollHeight: 2
|
|
scrollPastBottom: true
|
|
theme:
|
|
activeBorderColor:
|
|
- white
|
|
- bold
|
|
inactiveBorderColor:
|
|
- white
|
|
optionsTextColor:
|
|
- blue
|
|
commitLength:
|
|
show: true
|
|
update:
|
|
method: prompt # can be: prompt | background | never
|
|
days: 14 # how often a update is checked for
|
|
reporting: 'undetermined' # one of: 'on' | 'off' | 'undetermined'
|
|
confirmOnQuit: false
|
|
`)
|
|
}
|
|
|
|
// AppState stores data between runs of the app like when the last update check
|
|
// was performed and which other repos have been checked out
|
|
type AppState struct {
|
|
LastUpdateCheck int64
|
|
RecentRepos []string
|
|
}
|
|
|
|
func getDefaultAppState() []byte {
|
|
return []byte(`
|
|
lastUpdateCheck: 0
|
|
recentRepos: []
|
|
`)
|
|
}
|
|
|
|
// // commenting this out until we use it again
|
|
// func homeDirectory() string {
|
|
// usr, err := user.Current()
|
|
// if err != nil {
|
|
// log.Fatal(err)
|
|
// }
|
|
// return usr.HomeDir
|
|
// }
|