1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-21 12:16:54 +02:00
lazygit/pkg/gui/controllers/submodules_controller.go
Jesse Duffield 7bddf53223 Improve keybinding descriptions
This adds a bunch of tooltips to keybindings and updates some keybinding descriptions (i.e. labels).

It's in preparation for displaying more keybindings on-screen (in the bottom right of the screen),
and so due in part to laziness it shortens some descriptions so that we don't need to manage both
a short and long description (for on-screen vs in-menu). Nonetheless I've added a ShortDescription
field for when we do want to have both a short and long description.

You'll notice that some keybindings I deemed unworthy of the options view have longer descriptions,
because I could get away with it.
2024-01-28 08:12:01 +11:00

290 lines
9.6 KiB
Go

package controllers
import (
"fmt"
"path/filepath"
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type SubmodulesController struct {
baseController
*ListControllerTrait[*models.SubmoduleConfig]
c *ControllerCommon
}
var _ types.IController = &SubmodulesController{}
func NewSubmodulesController(
c *ControllerCommon,
) *SubmodulesController {
return &SubmodulesController{
baseController: baseController{},
ListControllerTrait: NewListControllerTrait[*models.SubmoduleConfig](
c,
c.Contexts().Submodules,
c.Contexts().Submodules.GetSelected,
c.Contexts().Submodules.GetSelectedItems,
),
c: c,
}
}
func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.GoInto),
Handler: self.withItem(self.enter),
GetDisabledReason: self.require(self.singleItemSelected()),
Description: self.c.Tr.Enter,
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.EnterSubmoduleTooltip,
map[string]string{"escape": keybindings.Label(opts.Config.Universal.Return)}),
},
{
Key: opts.GetKey(opts.Config.Universal.Select),
Handler: self.withItem(self.enter),
GetDisabledReason: self.require(self.singleItemSelected()),
},
{
Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.withItem(self.remove),
GetDisabledReason: self.require(self.singleItemSelected()),
Description: self.c.Tr.Remove,
Tooltip: self.c.Tr.RemoveSubmoduleTooltip,
},
{
Key: opts.GetKey(opts.Config.Submodules.Update),
Handler: self.withItem(self.update),
GetDisabledReason: self.require(self.singleItemSelected()),
Description: self.c.Tr.Update,
Tooltip: self.c.Tr.SubmoduleUpdateTooltip,
},
{
Key: opts.GetKey(opts.Config.Universal.New),
Handler: self.add,
Description: self.c.Tr.NewSubmodule,
},
{
Key: opts.GetKey(opts.Config.Universal.Edit),
Handler: self.withItem(self.editURL),
GetDisabledReason: self.require(self.singleItemSelected()),
Description: self.c.Tr.EditSubmoduleUrl,
},
{
Key: opts.GetKey(opts.Config.Submodules.Init),
Handler: self.withItem(self.init),
GetDisabledReason: self.require(self.singleItemSelected()),
Description: self.c.Tr.Initialize,
Tooltip: self.c.Tr.InitSubmoduleTooltip,
},
{
Key: opts.GetKey(opts.Config.Submodules.BulkMenu),
Handler: self.openBulkActionsMenu,
Description: self.c.Tr.ViewBulkSubmoduleOptions,
OpensMenu: true,
},
{
Key: nil,
Handler: self.easterEgg,
Description: self.c.Tr.EasterEgg,
},
}
}
func (self *SubmodulesController) GetOnClick() func() error {
return self.withItemGraceful(self.enter)
}
func (self *SubmodulesController) GetOnRenderToMain() func() error {
return func() error {
return self.c.Helpers().Diff.WithDiffModeCheck(func() error {
var task types.UpdateTask
submodule := self.context().GetSelected()
if submodule == nil {
task = types.NewRenderStringTask("No submodules")
} else {
prefix := fmt.Sprintf(
"Name: %s\nPath: %s\nUrl: %s\n\n",
style.FgGreen.Sprint(submodule.Name),
style.FgYellow.Sprint(submodule.Path),
style.FgCyan.Sprint(submodule.Url),
)
file := self.c.Helpers().WorkingTree.FileForSubmodule(submodule)
if file == nil {
task = types.NewRenderStringTask(prefix)
} else {
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(file, false, !file.HasUnstagedChanges && file.HasStagedChanges)
task = types.NewRunCommandTaskWithPrefix(cmdObj.GetCmd(), prefix)
}
}
return self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: "Submodule",
Task: task,
},
})
})
}
}
func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error {
return self.c.Helpers().Repos.EnterSubmodule(submodule)
}
func (self *SubmodulesController) add() error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewSubmoduleUrl,
HandleConfirm: func(submoduleUrl string) error {
nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl)))
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewSubmoduleName,
InitialContent: nameSuggestion,
HandleConfirm: func(submoduleName string) error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewSubmodulePath,
InitialContent: submoduleName,
HandleConfirm: func(submodulePath string) error {
return self.c.WithWaitingStatus(self.c.Tr.AddingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AddSubmodule)
err := self.c.Git().Submodule.Add(submoduleName, submodulePath, submoduleUrl)
if err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
})
},
})
},
})
}
func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) error {
return self.c.Prompt(types.PromptOpts{
Title: fmt.Sprintf(self.c.Tr.UpdateSubmoduleUrl, submodule.Name),
InitialContent: submodule.Url,
HandleConfirm: func(newUrl string) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleUrlStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.UpdateSubmoduleUrl)
err := self.c.Git().Submodule.UpdateUrl(submodule.Name, submodule.Path, newUrl)
if err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
})
}
func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error {
return self.c.WithWaitingStatus(self.c.Tr.InitializingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.InitialiseSubmodule)
err := self.c.Git().Submodule.Init(submodule.Path)
if err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
}
func (self *SubmodulesController) openBulkActionsMenu() error {
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.BulkSubmoduleOptions,
Items: []*types.MenuItem{
{
LabelColumns: []string{self.c.Tr.BulkInitSubmodules, style.FgGreen.Sprint(self.c.Git().Submodule.BulkInitCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkInitialiseSubmodules)
err := self.c.Git().Submodule.BulkInitCmdObj().Run()
if err != nil {
return self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
Key: 'i',
},
{
LabelColumns: []string{self.c.Tr.BulkUpdateSubmodules, style.FgYellow.Sprint(self.c.Git().Submodule.BulkUpdateCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkUpdateSubmodules)
if err := self.c.Git().Submodule.BulkUpdateCmdObj().Run(); err != nil {
return self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
Key: 'u',
},
{
LabelColumns: []string{self.c.Tr.BulkDeinitSubmodules, style.FgRed.Sprint(self.c.Git().Submodule.BulkDeinitCmdObj().ToString())},
OnPress: func() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkDeinitialiseSubmodules)
if err := self.c.Git().Submodule.BulkDeinitCmdObj().Run(); err != nil {
return self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
Key: 'd',
},
},
})
}
func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) error {
return self.c.WithWaitingStatus(self.c.Tr.UpdatingSubmoduleStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.UpdateSubmodule)
err := self.c.Git().Submodule.Update(submodule.Path)
if err != nil {
_ = self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
}
func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) error {
return self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.RemoveSubmodule,
Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.Name),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RemoveSubmodule)
if err := self.c.Git().Submodule.Delete(submodule); err != nil {
return self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES, types.FILES}})
},
})
}
func (self *SubmodulesController) easterEgg() error {
return self.c.PushContext(self.c.Contexts().Snake)
}
func (self *SubmodulesController) context() *context.SubmodulesContext {
return self.c.Contexts().Submodules
}