mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-08-08 22:36:49 +02:00
refactor custom commands panel
This commit is contained in:
@@ -256,6 +256,13 @@ func (gui *Gui) handleToggleCommitFileDirCollapsed() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics
|
||||||
|
func (gui *Gui) handleToggleCommitFileTreeView() error {
|
||||||
|
gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleShowTree()
|
||||||
|
|
||||||
|
return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles)
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error {
|
func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error {
|
||||||
// sometimes the commitFiles view is already shown in another window, so we need to ensure that window
|
// sometimes the commitFiles view is already shown in another window, so we need to ensure that window
|
||||||
// no longer considers the commitFiles view as its main view.
|
// no longer considers the commitFiles view as its main view.
|
||||||
@@ -273,10 +280,3 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC
|
|||||||
|
|
||||||
return gui.c.PushContext(gui.State.Contexts.CommitFiles)
|
return gui.c.PushContext(gui.State.Contexts.CommitFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics
|
|
||||||
func (gui *Gui) handleToggleCommitFileTreeView() error {
|
|
||||||
gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleShowTree()
|
|
||||||
|
|
||||||
return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles)
|
|
||||||
}
|
|
||||||
|
@@ -40,7 +40,7 @@ type commandMenuEntry struct {
|
|||||||
value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (string, error) {
|
func (gui *Gui) getResolveTemplateFn(promptResponses []string) func(string) (string, error) {
|
||||||
objects := CustomCommandObjects{
|
objects := CustomCommandObjects{
|
||||||
SelectedFile: gui.getSelectedFile(),
|
SelectedFile: gui.getSelectedFile(),
|
||||||
SelectedPath: gui.getSelectedPath(),
|
SelectedPath: gui.getSelectedPath(),
|
||||||
@@ -58,71 +58,101 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
|
|||||||
PromptResponses: promptResponses,
|
PromptResponses: promptResponses,
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.ResolveTemplate(templateStr, objects)
|
return func(templateStr string) (string, error) { return utils.ResolveTemplate(templateStr, objects) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
func resolveCustomCommandPrompt(prompt *config.CustomCommandPrompt, resolveTemplate func(string) (string, error)) (*config.CustomCommandPrompt, error) {
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
var err error
|
||||||
|
result := &config.CustomCommandPrompt{}
|
||||||
|
|
||||||
|
result.Title, err = resolveTemplate(prompt.Title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.c.Error(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses)
|
result.InitialValue, err = resolveTemplate(prompt.InitialValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.c.Error(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.Command, err = resolveTemplate(prompt.Command)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Filter, err = resolveTemplate(prompt.Filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(prompt.Options) > 0 {
|
||||||
|
newOptions := make([]config.CustomCommandMenuOption, len(prompt.Options))
|
||||||
|
for _, option := range prompt.Options {
|
||||||
|
option := option
|
||||||
|
newOption, err := resolveMenuOption(&option, resolveTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newOptions = append(newOptions, *newOption)
|
||||||
|
}
|
||||||
|
prompt.Options = newOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveMenuOption(option *config.CustomCommandMenuOption, resolveTemplate func(string) (string, error)) (*config.CustomCommandMenuOption, error) {
|
||||||
|
nameTemplate := option.Name
|
||||||
|
if nameTemplate == "" {
|
||||||
|
// this allows you to only pass values rather than bother with names/descriptions
|
||||||
|
nameTemplate = option.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err := resolveTemplate(nameTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
description, err := resolveTemplate(option.Description)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := resolveTemplate(option.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config.CustomCommandMenuOption{
|
||||||
|
Name: name,
|
||||||
|
Description: description,
|
||||||
|
Value: value,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) inputPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
|
||||||
return gui.c.Prompt(types.PromptOpts{
|
return gui.c.Prompt(types.PromptOpts{
|
||||||
Title: title,
|
Title: prompt.Title,
|
||||||
InitialContent: initialValue,
|
InitialContent: prompt.InitialValue,
|
||||||
HandleConfirm: func(str string) error {
|
HandleConfirm: func(str string) error {
|
||||||
promptResponses[responseIdx] = str
|
return wrappedF(str)
|
||||||
return wrappedF()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
func (gui *Gui) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
|
||||||
// need to make a menu here some how
|
|
||||||
menuItems := make([]*types.MenuItem, len(prompt.Options))
|
menuItems := make([]*types.MenuItem, len(prompt.Options))
|
||||||
for i, option := range prompt.Options {
|
for i, option := range prompt.Options {
|
||||||
option := option
|
option := option
|
||||||
|
|
||||||
nameTemplate := option.Name
|
|
||||||
if nameTemplate == "" {
|
|
||||||
// this allows you to only pass values rather than bother with names/descriptions
|
|
||||||
nameTemplate = option.Value
|
|
||||||
}
|
|
||||||
name, err := gui.resolveTemplate(nameTemplate, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
description, err := gui.resolveTemplate(option.Description, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := gui.resolveTemplate(option.Value, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItems[i] = &types.MenuItem{
|
menuItems[i] = &types.MenuItem{
|
||||||
DisplayStrings: []string{name, style.FgYellow.Sprint(description)},
|
DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
promptResponses[responseIdx] = value
|
return wrappedF(option.Value)
|
||||||
return wrappedF()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems})
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) {
|
func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) {
|
||||||
@@ -191,27 +221,15 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label
|
|||||||
return candidates, err
|
return candidates, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
func (gui *Gui) menuPromptFromCommand(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
|
||||||
// Collect cmd to run from config
|
|
||||||
cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect Filter regexp
|
|
||||||
filter, err := gui.resolveTemplate(prompt.Filter, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run and save output
|
// Run and save output
|
||||||
message, err := gui.git.Custom.RunWithOutput(cmdStr)
|
message, err := gui.git.Custom.RunWithOutput(prompt.Command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.c.Error(err)
|
return gui.c.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to make a menu out of what the cmd has displayed
|
// Need to make a menu out of what the cmd has displayed
|
||||||
candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.ValueFormat, prompt.LabelFormat)
|
candidates, err := gui.GenerateMenuCandidates(message, prompt.Filter, prompt.ValueFormat, prompt.LabelFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.c.Error(err)
|
return gui.c.Error(err)
|
||||||
}
|
}
|
||||||
@@ -222,18 +240,12 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR
|
|||||||
menuItems[i] = &types.MenuItem{
|
menuItems[i] = &types.MenuItem{
|
||||||
DisplayStrings: []string{candidates[i].label},
|
DisplayStrings: []string{candidates[i].label},
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
promptResponses[responseIdx] = candidates[i].value
|
return wrappedF(candidates[i].value)
|
||||||
return wrappedF()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems})
|
||||||
if err != nil {
|
|
||||||
return gui.c.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error {
|
func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error {
|
||||||
@@ -241,7 +253,8 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
|
|||||||
promptResponses := make([]string, len(customCommand.Prompts))
|
promptResponses := make([]string, len(customCommand.Prompts))
|
||||||
|
|
||||||
f := func() error {
|
f := func() error {
|
||||||
cmdStr, err := gui.resolveTemplate(customCommand.Command, promptResponses)
|
resolveTemplate := gui.getResolveTemplateFn(promptResponses)
|
||||||
|
cmdStr, err := resolveTemplate(customCommand.Command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gui.c.Error(err)
|
return gui.c.Error(err)
|
||||||
}
|
}
|
||||||
@@ -254,6 +267,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
|
|||||||
if loadingText == "" {
|
if loadingText == "" {
|
||||||
loadingText = gui.c.Tr.LcRunningCustomCommandStatus
|
loadingText = gui.c.Tr.LcRunningCustomCommandStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.c.WithWaitingStatus(loadingText, func() error {
|
return gui.c.WithWaitingStatus(loadingText, func() error {
|
||||||
gui.c.LogAction(gui.c.Tr.Actions.CustomCommand)
|
gui.c.LogAction(gui.c.Tr.Actions.CustomCommand)
|
||||||
cmdObj := gui.os.Cmd.NewShell(cmdStr)
|
cmdObj := gui.os.Cmd.NewShell(cmdStr)
|
||||||
@@ -276,26 +290,33 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
|
|||||||
// going backwards so the outermost prompt is the first one
|
// going backwards so the outermost prompt is the first one
|
||||||
prompt := customCommand.Prompts[idx]
|
prompt := customCommand.Prompts[idx]
|
||||||
|
|
||||||
// need to do this because f's value will change with each iteration
|
wrappedF := func(response string) error {
|
||||||
wrappedF := f
|
promptResponses[idx] = response
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveTemplate := gui.getResolveTemplateFn(promptResponses)
|
||||||
|
resolvedPrompt, err := resolveCustomCommandPrompt(&prompt, resolveTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return gui.c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
switch prompt.Type {
|
switch prompt.Type {
|
||||||
case "input":
|
case "input":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
return gui.inputPrompt(prompt, promptResponses, idx, wrappedF)
|
return gui.inputPrompt(resolvedPrompt, wrappedF)
|
||||||
}
|
}
|
||||||
case "menu":
|
case "menu":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
return gui.menuPrompt(prompt, promptResponses, idx, wrappedF)
|
return gui.menuPrompt(resolvedPrompt, wrappedF)
|
||||||
}
|
}
|
||||||
case "menuFromCommand":
|
case "menuFromCommand":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF)
|
return gui.menuPromptFromCommand(resolvedPrompt, wrappedF)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return gui.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'")
|
return gui.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return f()
|
return f()
|
||||||
|
Reference in New Issue
Block a user