From 8d3cce4a497e781668aad0244e94caaeb97461cf Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 28 Mar 2023 18:44:52 +0200 Subject: [PATCH 01/10] Rename test files so that test discovery works again These files were renamed from os_windows_test.go to os_test_windows.go (etc.) in 95b2e9540a5. Since then, the tests have no longer run, since go only looks for tests in files ending with "test.go". It isn't important that the file name ends with "_windows.go", since there are already build constrains in the files themselves. --- .../oscommands/{os_test_default.go => os_default_test.go} | 0 .../oscommands/{os_test_windows.go => os_windows_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename pkg/commands/oscommands/{os_test_default.go => os_default_test.go} (100%) rename pkg/commands/oscommands/{os_test_windows.go => os_windows_test.go} (100%) diff --git a/pkg/commands/oscommands/os_test_default.go b/pkg/commands/oscommands/os_default_test.go similarity index 100% rename from pkg/commands/oscommands/os_test_default.go rename to pkg/commands/oscommands/os_default_test.go diff --git a/pkg/commands/oscommands/os_test_windows.go b/pkg/commands/oscommands/os_windows_test.go similarity index 100% rename from pkg/commands/oscommands/os_test_windows.go rename to pkg/commands/oscommands/os_windows_test.go From 24de1565928cb24a043d65dcb63801a6bf418bb9 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 29 Mar 2023 14:46:46 +0200 Subject: [PATCH 02/10] Fix windows tests Now that the tests run again, it turns out that they actually fail, so fix them. --- pkg/commands/oscommands/os_windows_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/commands/oscommands/os_windows_test.go b/pkg/commands/oscommands/os_windows_test.go index cf9c1e68a..acb971b59 100644 --- a/pkg/commands/oscommands/os_windows_test.go +++ b/pkg/commands/oscommands/os_windows_test.go @@ -6,6 +6,7 @@ package oscommands import ( "testing" + "github.com/cli/safeexec" "github.com/go-errors/errors" "github.com/stretchr/testify/assert" ) @@ -19,11 +20,13 @@ func TestOSCommandOpenFileWindows(t *testing.T) { test func(error) } + fullCmdPath, _ := safeexec.LookPath("cmd") + scenarios := []scenario{ { filename: "test", runner: NewFakeRunner(t). - ExpectArgs([]string{"cmd", "/c", "start", "", "test"}, "", errors.New("error")), + ExpectArgs([]string{fullCmdPath, "/c", "start", "", "test"}, "", errors.New("error")), test: func(err error) { assert.Error(t, err) }, @@ -31,7 +34,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { { filename: "test", runner: NewFakeRunner(t). - ExpectArgs([]string{"cmd", "/c", "start", "", "test"}, "", nil), + ExpectArgs([]string{fullCmdPath, "/c", "start", "", "test"}, "", nil), test: func(err error) { assert.NoError(t, err) }, @@ -39,7 +42,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { { filename: "filename with spaces", runner: NewFakeRunner(t). - ExpectArgs([]string{"cmd", "/c", "start", "", "filename with spaces"}, "", nil), + ExpectArgs([]string{fullCmdPath, "/c", "start", "", "filename with spaces"}, "", nil), test: func(err error) { assert.NoError(t, err) }, @@ -47,7 +50,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { { filename: "let's_test_with_single_quote", runner: NewFakeRunner(t). - ExpectArgs([]string{"cmd", "/c", "start", "", "let's_test_with_single_quote"}, "", nil), + ExpectArgs([]string{fullCmdPath, "/c", "start", "", "let's_test_with_single_quote"}, "", nil), test: func(err error) { assert.NoError(t, err) }, @@ -55,7 +58,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { { filename: "$USER.txt", runner: NewFakeRunner(t). - ExpectArgs([]string{"cmd", "/c", "start", "", "$USER.txt"}, "", nil), + ExpectArgs([]string{fullCmdPath, "/c", "start", "", "$USER.txt"}, "", nil), test: func(err error) { assert.NoError(t, err) }, From 7bbcec965bb6606c661287f3a729a1de08debd81 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 29 Mar 2023 11:50:35 +0200 Subject: [PATCH 03/10] Cleanup: fix copy/paste error in comment --- pkg/config/user_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 864a672ba..df421b03c 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -300,7 +300,7 @@ 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 is the command for opening a link OpenLinkCommand string `yaml:"openLinkCommand,omitempty"` } From 659d668e16c3aac63ca7c41bba06003b6b1f8023 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 26 Mar 2023 14:04:09 +0200 Subject: [PATCH 04/10] Implement edit presets --- pkg/commands/git_commands/file.go | 62 +++++- pkg/commands/git_commands/file_test.go | 203 +++++++++++++++++++- pkg/config/config_default_platform.go | 6 +- pkg/config/config_linux.go | 12 +- pkg/config/config_windows.go | 6 +- pkg/config/editor_presets.go | 109 +++++++++++ pkg/config/editor_presets_test.go | 126 ++++++++++++ pkg/config/user_config.go | 31 ++- pkg/gui/controllers/helpers/files_helper.go | 29 ++- pkg/gui/controllers/staging_controller.go | 2 +- 10 files changed, 557 insertions(+), 29 deletions(-) create mode 100644 pkg/config/editor_presets.go create mode 100644 pkg/config/editor_presets_test.go diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 111733bb7..3ceef2d9b 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -3,8 +3,10 @@ package git_commands import ( "os" "strconv" + "strings" "github.com/go-errors/errors" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -27,7 +29,7 @@ func (self *FileCommands) Cat(fileName string) (string, error) { return string(buf), nil } -func (self *FileCommands) GetEditCmdStr(filename string, lineNumber int) (string, error) { +func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) { editor := self.UserConfig.OS.EditCommand if editor == "" { @@ -72,3 +74,61 @@ func (self *FileCommands) GetEditCmdStr(filename string, lineNumber int) (string } return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil } + +func (self *FileCommands) GetEditCmdStr(filename string) (string, bool) { + template, editInTerminal := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + + templateValues := map[string]string{ + "filename": self.cmd.Quote(filename), + } + + cmdStr := utils.ResolvePlaceholderString(template, templateValues) + return cmdStr, editInTerminal +} + +func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) { + template, editInTerminal := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + + templateValues := map[string]string{ + "filename": self.cmd.Quote(filename), + "line": strconv.Itoa(lineNumber), + } + + cmdStr := utils.ResolvePlaceholderString(template, templateValues) + return cmdStr, editInTerminal +} + +func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string { + template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + + templateValues := map[string]string{ + "filename": self.cmd.Quote(filename), + "line": strconv.Itoa(lineNumber), + } + + cmdStr := utils.ResolvePlaceholderString(template, templateValues) + return cmdStr +} + +func (self *FileCommands) guessDefaultEditor() string { + // Try to query a few places where editors get configured + editor := self.config.GetCoreEditor() + if editor == "" { + editor = self.os.Getenv("GIT_EDITOR") + } + if editor == "" { + editor = self.os.Getenv("VISUAL") + } + if editor == "" { + editor = self.os.Getenv("EDITOR") + } + + if editor != "" { + // At this point, it might be more than just the name of the editor; + // e.g. it might be "code -w" or "vim -u myvim.rc". So assume that + // everything up to the first space is the editor name. + editor = strings.Split(editor, " ")[0] + } + + return editor +} diff --git a/pkg/commands/git_commands/file_test.go b/pkg/commands/git_commands/file_test.go index 4b9128dfe..2367e4fcb 100644 --- a/pkg/commands/git_commands/file_test.go +++ b/pkg/commands/git_commands/file_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestEditFileCmdStr(t *testing.T) { +func TestEditFileCmdStrLegacy(t *testing.T) { type scenario struct { filename string configEditCommand string @@ -172,7 +172,206 @@ func TestEditFileCmdStr(t *testing.T) { getenv: s.getenv, }) - s.test(instance.GetEditCmdStr(s.filename, 1)) + s.test(instance.GetEditCmdStrLegacy(s.filename, 1)) s.runner.CheckForMissingCalls() } } + +func TestEditFileCmd(t *testing.T) { + type scenario struct { + filename string + osConfig config.OSConfig + expectedCmdStr string + expectedEditInTerminal bool + } + + scenarios := []scenario{ + { + filename: "test", + osConfig: config.OSConfig{}, + expectedCmdStr: `vim -- "test"`, + expectedEditInTerminal: true, + }, + { + filename: "test", + osConfig: config.OSConfig{ + Edit: "nano {{filename}}", + }, + expectedCmdStr: `nano "test"`, + expectedEditInTerminal: true, + }, + { + filename: "file/with space", + osConfig: config.OSConfig{ + EditPreset: "sublime", + }, + expectedCmdStr: `subl -- "file/with space"`, + expectedEditInTerminal: false, + }, + } + + for _, s := range scenarios { + userConfig := config.GetDefaultConfig() + userConfig.OS = s.osConfig + + instance := buildFileCommands(commonDeps{ + userConfig: userConfig, + }) + + cmdStr, editInTerminal := instance.GetEditCmdStr(s.filename) + assert.Equal(t, s.expectedCmdStr, cmdStr) + assert.Equal(t, s.expectedEditInTerminal, editInTerminal) + } +} + +func TestEditFileAtLineCmd(t *testing.T) { + type scenario struct { + filename string + lineNumber int + osConfig config.OSConfig + expectedCmdStr string + expectedEditInTerminal bool + } + + scenarios := []scenario{ + { + filename: "test", + lineNumber: 42, + osConfig: config.OSConfig{}, + expectedCmdStr: `vim +42 -- "test"`, + expectedEditInTerminal: true, + }, + { + filename: "test", + lineNumber: 35, + osConfig: config.OSConfig{ + EditAtLine: "nano +{{line}} {{filename}}", + }, + expectedCmdStr: `nano +35 "test"`, + expectedEditInTerminal: true, + }, + { + filename: "file/with space", + lineNumber: 12, + osConfig: config.OSConfig{ + EditPreset: "sublime", + }, + expectedCmdStr: `subl -- "file/with space":12`, + expectedEditInTerminal: false, + }, + } + + for _, s := range scenarios { + userConfig := config.GetDefaultConfig() + userConfig.OS = s.osConfig + + instance := buildFileCommands(commonDeps{ + userConfig: userConfig, + }) + + cmdStr, editInTerminal := instance.GetEditAtLineCmdStr(s.filename, s.lineNumber) + assert.Equal(t, s.expectedCmdStr, cmdStr) + assert.Equal(t, s.expectedEditInTerminal, editInTerminal) + } +} + +func TestEditFileAtLineAndWaitCmd(t *testing.T) { + type scenario struct { + filename string + lineNumber int + osConfig config.OSConfig + expectedCmdStr string + } + + scenarios := []scenario{ + { + filename: "test", + lineNumber: 42, + osConfig: config.OSConfig{}, + expectedCmdStr: `vim +42 -- "test"`, + }, + { + filename: "file/with space", + lineNumber: 12, + osConfig: config.OSConfig{ + EditPreset: "sublime", + }, + expectedCmdStr: `subl --wait -- "file/with space":12`, + }, + } + + for _, s := range scenarios { + userConfig := config.GetDefaultConfig() + userConfig.OS = s.osConfig + + instance := buildFileCommands(commonDeps{ + userConfig: userConfig, + }) + + cmdStr := instance.GetEditAtLineAndWaitCmdStr(s.filename, s.lineNumber) + assert.Equal(t, s.expectedCmdStr, cmdStr) + } +} + +func TestGuessDefaultEditor(t *testing.T) { + type scenario struct { + gitConfigMockResponses map[string]string + getenv func(string) string + expectedResult string + } + + scenarios := []scenario{ + { + gitConfigMockResponses: nil, + getenv: func(env string) string { + return "" + }, + expectedResult: "", + }, + { + gitConfigMockResponses: map[string]string{"core.editor": "nano"}, + getenv: func(env string) string { + return "" + }, + expectedResult: "nano", + }, + { + gitConfigMockResponses: map[string]string{"core.editor": "code -w"}, + getenv: func(env string) string { + return "" + }, + expectedResult: "code", + }, + { + gitConfigMockResponses: nil, + getenv: func(env string) string { + if env == "VISUAL" { + return "emacs" + } + + return "" + }, + expectedResult: "emacs", + }, + { + gitConfigMockResponses: nil, + getenv: func(env string) string { + if env == "EDITOR" { + return "bbedit -w" + } + + return "" + }, + expectedResult: "bbedit", + }, + } + + for _, s := range scenarios { + instance := buildFileCommands(commonDeps{ + gitConfig: git_config.NewFakeGitConfig(s.gitConfigMockResponses), + getenv: s.getenv, + }) + + assert.Equal(t, s.expectedResult, instance.guessDefaultEditor()) + } +} diff --git a/pkg/config/config_default_platform.go b/pkg/config/config_default_platform.go index 6784f0ce2..1a66f9d9e 100644 --- a/pkg/config/config_default_platform.go +++ b/pkg/config/config_default_platform.go @@ -6,9 +6,7 @@ package config // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ - EditCommand: ``, - EditCommandTemplate: "", - OpenCommand: "open -- {{filename}}", - OpenLinkCommand: "open {{link}}", + OpenCommand: "open -- {{filename}}", + OpenLinkCommand: "open {{link}}", } } diff --git a/pkg/config/config_linux.go b/pkg/config/config_linux.go index 06c277061..3ed29ca6e 100644 --- a/pkg/config/config_linux.go +++ b/pkg/config/config_linux.go @@ -29,17 +29,13 @@ func isContainer() bool { func GetPlatformDefaultConfig() OSConfig { if isWSL() && !isContainer() { return OSConfig{ - EditCommand: ``, - EditCommandTemplate: "", - OpenCommand: `powershell.exe start explorer.exe {{filename}} >/dev/null`, - OpenLinkCommand: `powershell.exe start {{link}} >/dev/null`, + OpenCommand: `powershell.exe start explorer.exe {{filename}} >/dev/null`, + OpenLinkCommand: `powershell.exe start {{link}} >/dev/null`, } } return OSConfig{ - EditCommand: ``, - EditCommandTemplate: "", - OpenCommand: `xdg-open {{filename}} >/dev/null`, - OpenLinkCommand: `xdg-open {{link}} >/dev/null`, + OpenCommand: `xdg-open {{filename}} >/dev/null`, + OpenLinkCommand: `xdg-open {{link}} >/dev/null`, } } diff --git a/pkg/config/config_windows.go b/pkg/config/config_windows.go index 12ecb8dff..21663c163 100644 --- a/pkg/config/config_windows.go +++ b/pkg/config/config_windows.go @@ -3,9 +3,7 @@ package config // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ - EditCommand: ``, - EditCommandTemplate: "", - OpenCommand: `start "" {{filename}}`, - OpenLinkCommand: `start "" {{link}}`, + OpenCommand: `start "" {{filename}}`, + OpenLinkCommand: `start "" {{link}}`, } } diff --git a/pkg/config/editor_presets.go b/pkg/config/editor_presets.go new file mode 100644 index 000000000..146abe0f5 --- /dev/null +++ b/pkg/config/editor_presets.go @@ -0,0 +1,109 @@ +package config + +func GetEditTemplate(osConfig *OSConfig, guessDefaultEditor func() string) (string, bool) { + preset := getPreset(osConfig, guessDefaultEditor) + template := osConfig.Edit + if template == "" { + template = preset.editTemplate + } + + return template, getEditInTerminal(osConfig, preset) +} + +func GetEditAtLineTemplate(osConfig *OSConfig, guessDefaultEditor func() string) (string, bool) { + preset := getPreset(osConfig, guessDefaultEditor) + template := osConfig.EditAtLine + if template == "" { + template = preset.editAtLineTemplate + } + return template, getEditInTerminal(osConfig, preset) +} + +func GetEditAtLineAndWaitTemplate(osConfig *OSConfig, guessDefaultEditor func() string) string { + preset := getPreset(osConfig, guessDefaultEditor) + template := osConfig.EditAtLineAndWait + if template == "" { + template = preset.editAtLineAndWaitTemplate + } + return template +} + +type editPreset struct { + editTemplate string + editAtLineTemplate string + editAtLineAndWaitTemplate string + editInTerminal bool +} + +func getPreset(osConfig *OSConfig, guessDefaultEditor func() string) *editPreset { + presets := map[string]*editPreset{ + "vi": standardTerminalEditorPreset("vi"), + "vim": standardTerminalEditorPreset("vim"), + "nvim": standardTerminalEditorPreset("nvim"), + "emacs": standardTerminalEditorPreset("emacs"), + "nano": standardTerminalEditorPreset("nano"), + "vscode": { + editTemplate: "code --reuse-window -- {{filename}}", + editAtLineTemplate: "code --reuse-window --goto -- {{filename}}:{{line}}", + editAtLineAndWaitTemplate: "code --reuse-window --goto --wait -- {{filename}}:{{line}}", + editInTerminal: false, + }, + "sublime": { + editTemplate: "subl -- {{filename}}", + editAtLineTemplate: "subl -- {{filename}}:{{line}}", + editAtLineAndWaitTemplate: "subl --wait -- {{filename}}:{{line}}", + editInTerminal: false, + }, + "bbedit": { + editTemplate: "bbedit -- {{filename}}", + editAtLineTemplate: "bbedit +{{line}} -- {{filename}}", + editAtLineAndWaitTemplate: "bbedit +{{line}} --wait -- {{filename}}", + editInTerminal: false, + }, + "xcode": { + editTemplate: "xed -- {{filename}}", + editAtLineTemplate: "xed --line {{line}} -- {{filename}}", + editAtLineAndWaitTemplate: "xed --line {{line}} --wait -- {{filename}}", + editInTerminal: false, + }, + } + + // Some of our presets have a different name than the editor they are using. + editorToPreset := map[string]string{ + "code": "vscode", + "subl": "sublime", + "xed": "xcode", + } + + presetName := osConfig.EditPreset + if presetName == "" { + defaultEditor := guessDefaultEditor() + if presets[defaultEditor] != nil { + presetName = defaultEditor + } else if p := editorToPreset[defaultEditor]; p != "" { + presetName = p + } + } + + if presetName == "" || presets[presetName] == nil { + presetName = "vim" + } + + return presets[presetName] +} + +func standardTerminalEditorPreset(editor string) *editPreset { + return &editPreset{ + editTemplate: editor + " -- {{filename}}", + editAtLineTemplate: editor + " +{{line}} -- {{filename}}", + editAtLineAndWaitTemplate: editor + " +{{line}} -- {{filename}}", + editInTerminal: true, + } +} + +func getEditInTerminal(osConfig *OSConfig, preset *editPreset) bool { + if osConfig.EditInTerminal != nil { + return *osConfig.EditInTerminal + } + return preset.editInTerminal +} diff --git a/pkg/config/editor_presets_test.go b/pkg/config/editor_presets_test.go new file mode 100644 index 000000000..1d73df8c6 --- /dev/null +++ b/pkg/config/editor_presets_test.go @@ -0,0 +1,126 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetEditTemplate(t *testing.T) { + trueVal := true + + scenarios := []struct { + name string + osConfig *OSConfig + guessDefaultEditor func() string + expectedEditTemplate string + expectedEditAtLineTemplate string + expectedEditAtLineAndWaitTemplate string + expectedEditInTerminal bool + }{ + { + "Default template is vim", + &OSConfig{}, + func() string { return "" }, + "vim -- {{filename}}", + "vim +{{line}} -- {{filename}}", + "vim +{{line}} -- {{filename}}", + true, + }, + { + "Setting a preset", + &OSConfig{ + EditPreset: "vscode", + }, + func() string { return "" }, + "code --reuse-window -- {{filename}}", + "code --reuse-window --goto -- {{filename}}:{{line}}", + "code --reuse-window --goto --wait -- {{filename}}:{{line}}", + false, + }, + { + "Setting a preset wins over guessed editor", + &OSConfig{ + EditPreset: "vscode", + }, + func() string { return "nano" }, + "code --reuse-window -- {{filename}}", + "code --reuse-window --goto -- {{filename}}:{{line}}", + "code --reuse-window --goto --wait -- {{filename}}:{{line}}", + false, + }, + { + "Overriding a preset with explicit config (edit)", + &OSConfig{ + EditPreset: "vscode", + Edit: "myeditor {{filename}}", + EditInTerminal: &trueVal, + }, + func() string { return "" }, + "myeditor {{filename}}", + "code --reuse-window --goto -- {{filename}}:{{line}}", + "code --reuse-window --goto --wait -- {{filename}}:{{line}}", + true, + }, + { + "Overriding a preset with explicit config (edit at line)", + &OSConfig{ + EditPreset: "vscode", + EditAtLine: "myeditor --line={{line}} {{filename}}", + EditInTerminal: &trueVal, + }, + func() string { return "" }, + "code --reuse-window -- {{filename}}", + "myeditor --line={{line}} {{filename}}", + "code --reuse-window --goto --wait -- {{filename}}:{{line}}", + true, + }, + { + "Overriding a preset with explicit config (edit at line and wait)", + &OSConfig{ + EditPreset: "vscode", + EditAtLineAndWait: "myeditor --line={{line}} -w {{filename}}", + EditInTerminal: &trueVal, + }, + func() string { return "" }, + "code --reuse-window -- {{filename}}", + "code --reuse-window --goto -- {{filename}}:{{line}}", + "myeditor --line={{line}} -w {{filename}}", + true, + }, + { + "Unknown preset name", + &OSConfig{ + EditPreset: "thisPresetDoesNotExist", + }, + func() string { return "" }, + "vim -- {{filename}}", + "vim +{{line}} -- {{filename}}", + "vim +{{line}} -- {{filename}}", + true, + }, + { + "Guessing a preset from guessed editor", + &OSConfig{}, + func() string { return "emacs" }, + "emacs -- {{filename}}", + "emacs +{{line}} -- {{filename}}", + "emacs +{{line}} -- {{filename}}", + true, + }, + } + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + template, editInTerminal := GetEditTemplate(s.osConfig, s.guessDefaultEditor) + assert.Equal(t, s.expectedEditTemplate, template) + assert.Equal(t, s.expectedEditInTerminal, editInTerminal) + + template, editInTerminal = GetEditAtLineTemplate(s.osConfig, s.guessDefaultEditor) + assert.Equal(t, s.expectedEditAtLineTemplate, template) + assert.Equal(t, s.expectedEditInTerminal, editInTerminal) + + template = GetEditAtLineAndWaitTemplate(s.osConfig, s.guessDefaultEditor) + assert.Equal(t, s.expectedEditAtLineAndWaitTemplate, template) + }) + } +} diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index df421b03c..a7be98c9c 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -291,10 +291,39 @@ type KeybindingSubmodulesConfig struct { // OSConfig contains config on the level of the os type OSConfig struct { - // EditCommand is the command for editing a file + // Command for editing a file. Should contain "{{filename}}". + Edit string `yaml:"edit,omitempty"` + + // Command for editing a file at a given line number. Should contain + // "{{filename}}", and may optionally contain "{{line}}". + EditAtLine string `yaml:"editAtLine,omitempty"` + + // Same as EditAtLine, except that the command needs to wait until the + // window is closed. + EditAtLineAndWait string `yaml:"editAtLineAndWait,omitempty"` + + // Whether the given edit commands use the terminal. Used to decide whether + // lazygit needs to suspend to the background before calling the editor. + // Pointer to bool so that we can distinguish unset (nil) from false. + EditInTerminal *bool `yaml:"editInTerminal,omitempty"` + + // A built-in preset that sets all of the above settings. Supported presets + // are defined in the getPreset function in editor_presets.go. + EditPreset string `yaml:"editPreset,omitempty"` + + // -------- + + // The following configs are all deprecated and kept for backward + // compatibility. They will be removed in the future. + + // EditCommand is the command for editing a file. + // Deprecated: use Edit instead. Note that semantics are different: + // EditCommand is just the command itself, whereas Edit contains a + // "{{filename}}" variable. EditCommand string `yaml:"editCommand,omitempty"` // EditCommandTemplate is the command template for editing a file + // Deprecated: use EditAtLine instead. EditCommandTemplate string `yaml:"editCommandTemplate,omitempty"` // OpenCommand is the command for opening a file diff --git a/pkg/gui/controllers/helpers/files_helper.go b/pkg/gui/controllers/helpers/files_helper.go index 72be6e4e5..29aa19ce1 100644 --- a/pkg/gui/controllers/helpers/files_helper.go +++ b/pkg/gui/controllers/helpers/files_helper.go @@ -34,19 +34,32 @@ func NewFilesHelper( var _ IFilesHelper = &FilesHelper{} func (self *FilesHelper) EditFile(filename string) error { - return self.EditFileAtLine(filename, 1) + cmdStr, editInTerminal := self.git.File.GetEditCmdStr(filename) + return self.callEditor(cmdStr, editInTerminal) } func (self *FilesHelper) EditFileAtLine(filename string, lineNumber int) error { - cmdStr, err := self.git.File.GetEditCmdStr(filename, lineNumber) - if err != nil { - return self.c.Error(err) + cmdStr, editInTerminal := self.git.File.GetEditAtLineCmdStr(filename, lineNumber) + return self.callEditor(cmdStr, editInTerminal) +} + +func (self *FilesHelper) EditFileAtLineAndWait(filename string, lineNumber int) error { + cmdStr := self.git.File.GetEditAtLineAndWaitCmdStr(filename, lineNumber) + + // Always suspend, regardless of the value of the editInTerminal config, + // since we want to prevent interacting with the UI until the editor + // returns, even if the editor doesn't use the terminal + return self.callEditor(cmdStr, true) +} + +func (self *FilesHelper) callEditor(cmdStr string, editInTerminal bool) error { + if editInTerminal { + return self.c.RunSubprocessAndRefresh( + self.os.Cmd.NewShell(cmdStr), + ) } - self.c.LogAction(self.c.Tr.Actions.EditFile) - return self.c.RunSubprocessAndRefresh( - self.os.Cmd.NewShell(cmdStr), - ) + return self.os.Cmd.NewShell(cmdStr).Run() } func (self *FilesHelper) OpenFile(filename string) error { diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index 1d8a24b95..07e39ea1f 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -247,7 +247,7 @@ func (self *StagingController) editHunk() error { lineOffset := 3 lineIdxInHunk := state.GetSelectedLineIdx() - hunkStartIdx - if err := self.helpers.Files.EditFileAtLine(patchFilepath, lineIdxInHunk+lineOffset); err != nil { + if err := self.helpers.Files.EditFileAtLineAndWait(patchFilepath, lineIdxInHunk+lineOffset); err != nil { return err } From 2947b5613417a38a09cd8ac0ede49eff78d80ec6 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 28 Mar 2023 17:49:55 +0200 Subject: [PATCH 05/10] Add support for falling back to legacy edit config --- pkg/commands/git_commands/file.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 3ceef2d9b..94563be65 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -76,6 +76,13 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) ( } func (self *FileCommands) GetEditCmdStr(filename string) (string, bool) { + // Legacy support for old config; to be removed at some point + if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if cmdStr, err := self.GetEditCmdStrLegacy(filename, 1); err == nil { + return cmdStr, true + } + } + template, editInTerminal := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor) templateValues := map[string]string{ @@ -87,6 +94,13 @@ func (self *FileCommands) GetEditCmdStr(filename string) (string, bool) { } func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) { + // Legacy support for old config; to be removed at some point + if self.UserConfig.OS.EditAtLine == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil { + return cmdStr, true + } + } + template, editInTerminal := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor) templateValues := map[string]string{ @@ -99,6 +113,13 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) ( } func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string { + // Legacy support for old config; to be removed at some point + if self.UserConfig.OS.EditAtLineAndWait == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil { + return cmdStr + } + } + template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor) templateValues := map[string]string{ From 08d679c3a8524610e3f30e8d5ece71d522d70c68 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 28 Mar 2023 18:19:03 +0200 Subject: [PATCH 06/10] Remove line number support for "open" command The "open" command is supposed to behave in the same way as double-clicking a file in the Finder/Explorer. The concept of jumping to a specific line in the file doesn't make sense for this; use "edit" instead. --- pkg/commands/oscommands/os.go | 5 ----- pkg/gui/controllers/helpers/files_helper.go | 7 +------ pkg/gui/controllers/merge_conflicts_controller.go | 3 +-- pkg/gui/controllers/patch_building_controller.go | 3 +-- pkg/gui/controllers/staging_controller.go | 3 +-- 5 files changed, 4 insertions(+), 17 deletions(-) diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 39149ce84..11c964ca4 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -78,14 +78,9 @@ func FileType(path string) string { } func (c *OSCommand) OpenFile(filename string) error { - return c.OpenFileAtLine(filename, 1) -} - -func (c *OSCommand) OpenFileAtLine(filename string, lineNumber int) error { commandTemplate := c.UserConfig.OS.OpenCommand templateValues := map[string]string{ "filename": c.Quote(filename), - "line": fmt.Sprintf("%d", lineNumber), } command := utils.ResolvePlaceholderString(commandTemplate, templateValues) return c.Cmd.NewShell(command).Run() diff --git a/pkg/gui/controllers/helpers/files_helper.go b/pkg/gui/controllers/helpers/files_helper.go index 29aa19ce1..a0d2d4e8c 100644 --- a/pkg/gui/controllers/helpers/files_helper.go +++ b/pkg/gui/controllers/helpers/files_helper.go @@ -10,7 +10,6 @@ type IFilesHelper interface { EditFile(filename string) error EditFileAtLine(filename string, lineNumber int) error OpenFile(filename string) error - OpenFileAtLine(filename string, lineNumber int) error } type FilesHelper struct { @@ -63,12 +62,8 @@ func (self *FilesHelper) callEditor(cmdStr string, editInTerminal bool) error { } func (self *FilesHelper) OpenFile(filename string) error { - return self.OpenFileAtLine(filename, 1) -} - -func (self *FilesHelper) OpenFileAtLine(filename string, lineNumber int) error { self.c.LogAction(self.c.Tr.Actions.OpenFile) - if err := self.os.OpenFileAtLine(filename, lineNumber); err != nil { + if err := self.os.OpenFile(filename); err != nil { return self.c.Error(err) } return nil diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index 7cfcfa62d..de282d4c9 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -166,8 +166,7 @@ func (self *MergeConflictsController) HandleEditFile() error { } func (self *MergeConflictsController) HandleOpenFile() error { - lineNumber := self.context().GetState().GetSelectedLine() - return self.helpers.Files.OpenFileAtLine(self.context().GetState().GetPath(), lineNumber) + return self.helpers.Files.OpenFile(self.context().GetState().GetPath()) } func (self *MergeConflictsController) HandleScrollLeft() error { diff --git a/pkg/gui/controllers/patch_building_controller.go b/pkg/gui/controllers/patch_building_controller.go index 613aadd1d..329ae0ea1 100644 --- a/pkg/gui/controllers/patch_building_controller.go +++ b/pkg/gui/controllers/patch_building_controller.go @@ -69,8 +69,7 @@ func (self *PatchBuildingController) OpenFile() error { return nil } - lineNumber := self.context().GetState().CurrentLineNumber() - return self.helpers.Files.OpenFileAtLine(path, lineNumber) + return self.helpers.Files.OpenFile(path) } func (self *PatchBuildingController) EditFile() error { diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index 07e39ea1f..bcd6d5114 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -109,8 +109,7 @@ func (self *StagingController) OpenFile() error { return nil } - lineNumber := self.context.GetState().CurrentLineNumber() - return self.helpers.Files.OpenFileAtLine(path, lineNumber) + return self.helpers.Files.OpenFile(path) } func (self *StagingController) EditFile() error { From b7e029adc7c5cf27ae2c5db768b971a959fa2449 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 29 Mar 2023 11:42:37 +0200 Subject: [PATCH 07/10] Don't set platform defaults on OSConfig struct immediately Instead, query the platform defaults only if the config is empty. This will be necessary later to distinguish an empty config from a default config, so that we can give deprecation warnings. --- pkg/commands/oscommands/os.go | 6 ++++++ pkg/config/user_config.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 11c964ca4..f66f25b72 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -79,6 +79,9 @@ func FileType(path string) string { func (c *OSCommand) OpenFile(filename string) error { commandTemplate := c.UserConfig.OS.OpenCommand + if commandTemplate == "" { + commandTemplate = config.GetPlatformDefaultConfig().OpenCommand + } templateValues := map[string]string{ "filename": c.Quote(filename), } @@ -88,6 +91,9 @@ func (c *OSCommand) OpenFile(filename string) error { func (c *OSCommand) OpenLink(link string) error { commandTemplate := c.UserConfig.OS.OpenLinkCommand + if commandTemplate == "" { + commandTemplate = config.GetPlatformDefaultConfig().OpenLinkCommand + } templateValues := map[string]string{ "link": c.Quote(link), } diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index a7be98c9c..0c227899e 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -599,7 +599,7 @@ func GetDefaultConfig() *UserConfig { BulkMenu: "b", }, }, - OS: GetPlatformDefaultConfig(), + OS: OSConfig{}, DisableStartupPopups: false, CustomCommands: []CustomCommand(nil), Services: map[string]string(nil), From e4e16fa38ea5d89fb139c5153338e32d1eeafede Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 28 Mar 2023 18:00:40 +0200 Subject: [PATCH 08/10] Change OpenCommand to Open and OpenLinkCommand to OpenLink We do this for consistency with the edit settings. The old names are kept as a fallback for now. --- pkg/commands/oscommands/os.go | 16 ++++++++++++---- pkg/commands/oscommands/os_default_test.go | 4 ++-- pkg/config/config_default_platform.go | 4 ++-- pkg/config/config_linux.go | 8 ++++---- pkg/config/config_windows.go | 4 ++-- pkg/config/user_config.go | 9 +++++++++ 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index f66f25b72..c8f38843b 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -78,9 +78,13 @@ func FileType(path string) string { } func (c *OSCommand) OpenFile(filename string) error { - commandTemplate := c.UserConfig.OS.OpenCommand + commandTemplate := c.UserConfig.OS.Open if commandTemplate == "" { - commandTemplate = config.GetPlatformDefaultConfig().OpenCommand + // Legacy support + commandTemplate = c.UserConfig.OS.OpenCommand + } + if commandTemplate == "" { + commandTemplate = config.GetPlatformDefaultConfig().Open } templateValues := map[string]string{ "filename": c.Quote(filename), @@ -90,9 +94,13 @@ func (c *OSCommand) OpenFile(filename string) error { } func (c *OSCommand) OpenLink(link string) error { - commandTemplate := c.UserConfig.OS.OpenLinkCommand + commandTemplate := c.UserConfig.OS.OpenLink if commandTemplate == "" { - commandTemplate = config.GetPlatformDefaultConfig().OpenLinkCommand + // Legacy support + commandTemplate = c.UserConfig.OS.OpenLinkCommand + } + if commandTemplate == "" { + commandTemplate = config.GetPlatformDefaultConfig().OpenLink } templateValues := map[string]string{ "link": c.Quote(link), diff --git a/pkg/commands/oscommands/os_default_test.go b/pkg/commands/oscommands/os_default_test.go index 39a1226d2..1f534f6d3 100644 --- a/pkg/commands/oscommands/os_default_test.go +++ b/pkg/commands/oscommands/os_default_test.go @@ -75,7 +75,7 @@ func TestOSCommandOpenFileDarwin(t *testing.T) { for _, s := range scenarios { oSCmd := NewDummyOSCommandWithRunner(s.runner) oSCmd.Platform.OS = "darwin" - oSCmd.UserConfig.OS.OpenCommand = "open {{filename}}" + oSCmd.UserConfig.OS.Open = "open {{filename}}" s.test(oSCmd.OpenFile(s.filename)) } @@ -135,7 +135,7 @@ func TestOSCommandOpenFileLinux(t *testing.T) { for _, s := range scenarios { oSCmd := NewDummyOSCommandWithRunner(s.runner) oSCmd.Platform.OS = "linux" - oSCmd.UserConfig.OS.OpenCommand = `xdg-open {{filename}} > /dev/null` + oSCmd.UserConfig.OS.Open = `xdg-open {{filename}} > /dev/null` s.test(oSCmd.OpenFile(s.filename)) } diff --git a/pkg/config/config_default_platform.go b/pkg/config/config_default_platform.go index 1a66f9d9e..d05201454 100644 --- a/pkg/config/config_default_platform.go +++ b/pkg/config/config_default_platform.go @@ -6,7 +6,7 @@ package config // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ - OpenCommand: "open -- {{filename}}", - OpenLinkCommand: "open {{link}}", + Open: "open -- {{filename}}", + OpenLink: "open {{link}}", } } diff --git a/pkg/config/config_linux.go b/pkg/config/config_linux.go index 3ed29ca6e..7f6187ee3 100644 --- a/pkg/config/config_linux.go +++ b/pkg/config/config_linux.go @@ -29,13 +29,13 @@ func isContainer() bool { func GetPlatformDefaultConfig() OSConfig { if isWSL() && !isContainer() { return OSConfig{ - OpenCommand: `powershell.exe start explorer.exe {{filename}} >/dev/null`, - OpenLinkCommand: `powershell.exe start {{link}} >/dev/null`, + Open: `powershell.exe start explorer.exe {{filename}} >/dev/null`, + OpenLink: `powershell.exe start {{link}} >/dev/null`, } } return OSConfig{ - OpenCommand: `xdg-open {{filename}} >/dev/null`, - OpenLinkCommand: `xdg-open {{link}} >/dev/null`, + Open: `xdg-open {{filename}} >/dev/null`, + OpenLink: `xdg-open {{link}} >/dev/null`, } } diff --git a/pkg/config/config_windows.go b/pkg/config/config_windows.go index 21663c163..96a810b50 100644 --- a/pkg/config/config_windows.go +++ b/pkg/config/config_windows.go @@ -3,7 +3,7 @@ package config // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ - OpenCommand: `start "" {{filename}}`, - OpenLinkCommand: `start "" {{link}}`, + Open: `start "" {{filename}}`, + OpenLink: `start "" {{link}}`, } } diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 0c227899e..fb0638e43 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -311,6 +311,13 @@ type OSConfig struct { // are defined in the getPreset function in editor_presets.go. EditPreset string `yaml:"editPreset,omitempty"` + // Command for opening a file, as if the file is double-clicked. Should + // contain "{{filename}}", but doesn't support "{{line}}". + Open string `yaml:"open,omitempty"` + + // Command for opening a link. Should contain "{{link}}". + OpenLink string `yaml:"openLink,omitempty"` + // -------- // The following configs are all deprecated and kept for backward @@ -327,9 +334,11 @@ type OSConfig struct { EditCommandTemplate string `yaml:"editCommandTemplate,omitempty"` // OpenCommand is the command for opening a file + // Deprecated: use Open instead. OpenCommand string `yaml:"openCommand,omitempty"` // OpenLinkCommand is the command for opening a link + // Deprecated: use OpenLink instead. OpenLinkCommand string `yaml:"openLinkCommand,omitempty"` } From e3c5e07b20aabd375db5ff3e84e89b0473274dba Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 28 Mar 2023 17:55:00 +0200 Subject: [PATCH 09/10] Update documentation --- docs/Config.md | 61 +++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index 22f2a8e9b..df9003d23 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -96,9 +96,12 @@ git: parseEmoji: false diffContextSize: 3 # how many lines of context are shown around a change in diffs os: - editCommand: '' # see 'Configuring File Editing' section - editCommandTemplate: '' - openCommand: '' + editPreset: '' # see 'Configuring File Editing' section + edit: '' + editAtLine: '' + editAtLineAndWait: '' + open: '' + openLink: '' refresher: refreshInterval: 10 # File/submodule refresh interval in seconds. Auto-refresh can be disabled via option 'git.autoRefresh'. fetchInterval: 60 # Re-fetch interval in seconds. Auto-fetch can be disabled via option 'git.autoFetch'. @@ -268,40 +271,41 @@ os: ### Configuring File Editing -Lazygit will edit a file with the first set editor in the following: +There are two commands for opening files, `o` for "open" and `e` for "edit". `o` +acts as if the file was double-clicked in the Finder/Explorer, so it also works +for non-text files, whereas `e` opens the file in an editor. `e` can also jump +to the right line in the file if you invoke it from the staging panel, for +example. -1. config.yaml +To tell lazygit which editor to use for the `e` command, the easiest way to do +that is to provide an editPreset config, e.g. ```yaml os: - editCommand: 'vim' # as an example + editPreset: 'vscode' ``` -2. \$(git config core.editor) -3. \$GIT_EDITOR -4. \$VISUAL -5. \$EDITOR -6. \$(which vi) +Supported presets are `vim`, `emacs`, `nano`, `vscode`, `sublime`, `bbedit`, and +`xcode`. In many cases lazygit will be able to guess the right preset from your +$(git config core.editor), or an environment variable such as $VISUAL or $EDITOR. -Lazygit will log an error if none of these options are set. - -You can specify the current line number when you're in the patch explorer. +If for some reason you are not happy with the default commands from a preset, or +there simply is no preset for your editor, you can customize the commands by +setting the `edit`, `editAtLine`, and `editAtLineAndWait` options, e.g.: ```yaml os: - editCommand: 'vim' - editCommandTemplate: '{{editor}} +{{line}} -- {{filename}}' + edit: 'myeditor {{filename}}' + editAtLine: 'myeditor --line={{line}} {{filename}}' + editAtLineAndWait: 'myeditor --block --line={{line}} {{filename}}' + editInTerminal: true ``` -or +The `editInTerminal` option is used to decide whether lazygit needs to suspend +itself to the background before calling the editor. -```yaml -os: - editCommand: 'code' - editCommandTemplate: '{{editor}} --goto -- {{filename}}:{{line}}' -``` - -`{{editor}}` in `editCommandTemplate` is replaced with the value of `editCommand`. +Contributions of new editor presets are welcome; see the `getPreset` function in +[`editor_presets.go`](https://github.com/jesseduffield/lazygit/blob/master/pkg/config/editor_presets.go). ### Overriding default config file location @@ -317,15 +321,6 @@ or LG_CONFIG_FILE="$HOME/.base_lg_conf,$HOME/.light_theme_lg_conf" lazygit ``` -### Recommended Config Values - -for users of VSCode - -```yaml -os: - openCommand: 'code -rg {{filename}}' -``` - ## Color Attributes For color attributes you can choose an array of attributes (with max one color attribute) From 046b0d9daa46f2fa8da9f196dc50a5ae02239675 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 2 Apr 2023 15:01:04 +0200 Subject: [PATCH 10/10] Show warning about deprecated edit configs We print this to the terminal after lazygit quits rather than showing it in a panel at startup, so as to not annoy people too much. Hopefully it will still be prominent enough this way. --- pkg/gui/gui.go | 33 +++++++++++++++++++++++++++++++++ pkg/i18n/english.go | 17 +++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 69ff10c77..aed1d5430 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -495,6 +495,8 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { return err } + defer gui.checkForDeprecatedEditConfigs() + gui.g = g defer gui.g.Close() @@ -583,6 +585,37 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error { }) } +func (gui *Gui) checkForDeprecatedEditConfigs() { + osConfig := &gui.UserConfig.OS + deprecatedConfigs := []struct { + config string + oldName string + newName string + }{ + {osConfig.EditCommand, "EditCommand", "Edit"}, + {osConfig.EditCommandTemplate, "EditCommandTemplate", "Edit,EditAtLine"}, + {osConfig.OpenCommand, "OpenCommand", "Open"}, + {osConfig.OpenLinkCommand, "OpenLinkCommand", "OpenLink"}, + } + deprecatedConfigStrings := []string{} + + for _, dc := range deprecatedConfigs { + if dc.config != "" { + deprecatedConfigStrings = append(deprecatedConfigStrings, fmt.Sprintf(" OS.%s -> OS.%s", dc.oldName, dc.newName)) + } + } + if len(deprecatedConfigStrings) != 0 { + warningMessage := utils.ResolvePlaceholderString( + gui.c.Tr.DeprecatedEditConfigWarning, + map[string]string{ + "configs": strings.Join(deprecatedConfigStrings, "\n"), + }, + ) + + os.Stdout.Write([]byte(warningMessage)) + } +} + // returns whether command exited without error or not func (gui *Gui) runSubprocessWithSuspenseAndRefresh(subprocess oscommands.ICmdObj) error { _, err := gui.runSubprocessWithSuspense(subprocess) diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 86ba0451c..e7756d03e 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -155,6 +155,7 @@ type TranslationSet struct { MergeToolTitle string MergeToolPrompt string IntroPopupMessage string + DeprecatedEditConfigWarning string GitconfigParseErr string LcEditFile string LcOpenFile string @@ -659,6 +660,21 @@ Thanks for using lazygit! Seriously you rock. Three things to share with you: Or even just star the repo to share the love! ` +const englishDeprecatedEditConfigWarning = ` +### Deprecated config warning ### + +The following config settings are deprecated and will be removed in a future +version: +{{configs}} + +Please refer to + + https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#configuring-file-editing + +for up-to-date information how to configure your editor. + +` + // exporting this so we can use it in tests func EnglishTranslationSet() TranslationSet { return TranslationSet{ @@ -805,6 +821,7 @@ func EnglishTranslationSet() TranslationSet { MergeToolTitle: "Merge tool", MergeToolPrompt: "Are you sure you want to open `git mergetool`?", IntroPopupMessage: englishIntroPopupMessage, + DeprecatedEditConfigWarning: englishDeprecatedEditConfigWarning, GitconfigParseErr: `Gogit failed to parse your gitconfig file due to the presence of unquoted '\' characters. Removing these should fix the issue.`, LcEditFile: `edit file`, LcOpenFile: `open file`,