summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Custom_Command_Keybindings.md6
-rw-r--r--pkg/config/user_config.go23
-rw-r--r--pkg/gui/controllers/helpers/merge_and_rebase_helper.go58
-rw-r--r--pkg/gui/services/custom_commands/client.go7
-rw-r--r--pkg/gui/services/custom_commands/handler_creator.go40
-rw-r--r--pkg/integration/tests/custom_commands/check_for_conflicts.go40
-rw-r--r--pkg/integration/tests/test_list.go1
7 files changed, 128 insertions, 47 deletions
diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md
index 7cc3d035b..6b0a090ed 100644
--- a/docs/Custom_Command_Keybindings.md
+++ b/docs/Custom_Command_Keybindings.md
@@ -59,6 +59,12 @@ For a given custom command, here are the allowed fields:
| description | Label for the custom command when displayed in the keybindings menu | no |
| stream | Whether you want to stream the command's output to the Command Log panel | no |
| showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
+| after | Actions to take after the command has completed | no |
+
+Here are the options for the `after` key:
+| _field_ | _description_ | required |
+|-----------------|----------------------|-|
+| checkForConflicts | true/false. If true, check for merge conflicts | no |
## Contexts
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 8faff4326..5b7edc9e4 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -349,16 +349,21 @@ type OSConfig struct {
OpenLinkCommand string `yaml:"openLinkCommand,omitempty"`
}
+type CustomCommandAfterHook struct {
+ CheckForConflicts bool `yaml:"checkForConflicts"`
+}
+
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"`
- Stream bool `yaml:"stream"`
- ShowOutput bool `yaml:"showOutput"`
+ 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"`
+ Stream bool `yaml:"stream"`
+ ShowOutput bool `yaml:"showOutput"`
+ After CustomCommandAfterHook `yaml:"after"`
}
type CustomCommandPrompt struct {
diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
index 21ab44201..0e83ccf25 100644
--- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
+++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go
@@ -137,33 +137,47 @@ func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error {
} else if strings.Contains(result.Error(), "No rebase in progress?") {
// assume in this case that we're already done
return nil
- } else if isMergeConflictErr(result.Error()) {
- mode := self.workingTreeStateNoun()
- return self.c.Menu(types.CreateMenuOptions{
- Title: self.c.Tr.FoundConflictsTitle,
- Items: []*types.MenuItem{
- {
- Label: self.c.Tr.ViewConflictsMenuItem,
- OnPress: func() error {
- return self.c.PushContext(self.c.Contexts().Files)
- },
- Key: 'v',
- },
- {
- Label: fmt.Sprintf(self.c.Tr.AbortMenuItem, mode),
- OnPress: func() error {
- return self.genericMergeCommand(REBASE_OPTION_ABORT)
- },
- Key: 'a',
- },
- },
- HideCancel: true,
- })
+ } else {
+ return self.CheckForConflicts(result)
+ }
+}
+
+func (self *MergeAndRebaseHelper) CheckForConflicts(result error) error {
+ if result == nil {
+ return nil
+ }
+
+ if isMergeConflictErr(result.Error()) {
+ return self.PromptForConflictHandling()
} else {
return self.c.ErrorMsg(result.Error())
}
}
+func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
+ mode := self.workingTreeStateNoun()
+ return self.c.Menu(types.CreateMenuOptions{
+ Title: self.c.Tr.FoundConflictsTitle,
+ Items: []*types.MenuItem{
+ {
+ Label: self.c.Tr.ViewConflictsMenuItem,
+ OnPress: func() error {
+ return self.c.PushContext(self.c.Contexts().Files)
+ },
+ Key: 'v',
+ },
+ {
+ Label: fmt.Sprintf(self.c.Tr.AbortMenuItem, mode),
+ OnPress: func() error {
+ return self.genericMergeCommand(REBASE_OPTION_ABORT)
+ },
+ Key: 'a',
+ },
+ },
+ HideCancel: true,
+ })
+}
+
func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
// prompt user to confirm that they want to abort, then do it
mode := self.workingTreeStateNoun()
diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go
index 5e456ff6e..c746f0579 100644
--- a/pkg/gui/services/custom_commands/client.go
+++ b/pkg/gui/services/custom_commands/client.go
@@ -19,7 +19,12 @@ func NewClient(
helpers *helpers.Helpers,
) *Client {
sessionStateLoader := NewSessionStateLoader(c, helpers.Refs)
- handlerCreator := NewHandlerCreator(c, sessionStateLoader, helpers.Suggestions)
+ handlerCreator := NewHandlerCreator(
+ c,
+ sessionStateLoader,
+ helpers.Suggestions,
+ helpers.MergeAndRebase,
+ )
keybindingCreator := NewKeybindingCreator(c)
customCommands := c.UserConfig.CustomCommands
diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go
index 4d6580b03..eea596ab8 100644
--- a/pkg/gui/services/custom_commands/handler_creator.go
+++ b/pkg/gui/services/custom_commands/handler_creator.go
@@ -17,27 +17,30 @@ import (
// takes a custom command and returns a function that will be called when the corresponding user-defined keybinding is pressed
type HandlerCreator struct {
- c *helpers.HelperCommon
- sessionStateLoader *SessionStateLoader
- resolver *Resolver
- menuGenerator *MenuGenerator
- suggestionsHelper *helpers.SuggestionsHelper
+ c *helpers.HelperCommon
+ sessionStateLoader *SessionStateLoader
+ resolver *Resolver
+ menuGenerator *MenuGenerator
+ suggestionsHelper *helpers.SuggestionsHelper
+ mergeAndRebaseHelper *helpers.MergeAndRebaseHelper
}
func NewHandlerCreator(
c *helpers.HelperCommon,
sessionStateLoader *SessionStateLoader,
suggestionsHelper *helpers.SuggestionsHelper,
+ mergeAndRebaseHelper *helpers.MergeAndRebaseHelper,
) *HandlerCreator {
resolver := NewResolver(c.Common)
menuGenerator := NewMenuGenerator(c.Common)
return &HandlerCreator{
- c: c,
- sessionStateLoader: sessionStateLoader,
- resolver: resolver,
- menuGenerator: menuGenerator,
- suggestionsHelper: suggestionsHelper,
+ c: c,
+ sessionStateLoader: sessionStateLoader,
+ resolver: resolver,
+ menuGenerator: menuGenerator,
+ suggestionsHelper: suggestionsHelper,
+ mergeAndRebaseHelper: mergeAndRebaseHelper,
}
}
@@ -272,7 +275,16 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
cmdObj.StreamOutput()
}
output, err := cmdObj.RunWithOutput()
+
+ if refreshErr := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
+ self.c.Log.Error(refreshErr)
+ }
+
if err != nil {
+ if customCommand.After.CheckForConflicts {
+ return self.mergeAndRebaseHelper.CheckForConflicts(err)
+ }
+
return self.c.Error(err)
}
@@ -280,11 +292,9 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
if strings.TrimSpace(output) == "" {
output = self.c.Tr.EmptyOutput
}
- if err = self.c.Alert(cmdStr, output); err != nil {
- return self.c.Error(err)
- }
- return self.c.Refresh(types.RefreshOptions{})
+ return self.c.Alert(cmdStr, output)
}
- return self.c.Refresh(types.RefreshOptions{})
+
+ return nil
})
}
diff --git a/pkg/integration/tests/custom_commands/check_for_conflicts.go b/pkg/integration/tests/custom_commands/check_for_conflicts.go
new file mode 100644
index 000000000..cb8ac7c77
--- /dev/null
+++ b/pkg/integration/tests/custom_commands/check_for_conflicts.go
@@ -0,0 +1,40 @@
+package custom_commands
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+ "github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
+)
+
+var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Run a command and check for conflicts after",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupRepo: func(shell *Shell) {
+ shared.MergeConflictsSetup(shell)
+ },
+ SetupConfig: func(cfg *config.AppConfig) {
+ cfg.UserConfig.CustomCommands = []config.CustomCommand{
+ {
+ Key: "m",
+ Context: "localBranches",
+ Command: "git merge {{ .SelectedLocalBranch.Name | quote }}",
+ After: config.CustomCommandAfterHook{
+ CheckForConflicts: true,
+ },
+ },
+ }
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Focus().
+ TopLines(
+ Contains("first-change-branch"),
+ Contains("second-change-branch"),
+ ).
+ NavigateToLine(Contains("second-change-branch")).
+ Press("m")
+
+ t.Common().AcknowledgeConflicts()
+ },
+})
diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go
index 55085f989..af0ac1c5b 100644
--- a/pkg/integration/tests/test_list.go
+++ b/pkg/integration/tests/test_list.go
@@ -75,6 +75,7 @@ var tests = []*components.IntegrationTest{
conflicts.UndoChooseHunk,
custom_commands.BasicCmdAtRuntime,
custom_commands.BasicCmdFromConfig,
+ custom_commands.CheckForConflicts,
custom_commands.ComplexCmdAtRuntime,
custom_commands.FormPrompts,
custom_commands.MenuFromCommand,