1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-23 00:39:13 +02:00
Files
.devcontainer
.github
.vscode
cmd
demo
docs
pkg
app
cheatsheet
commands
common
config
constants
env
fakes
gui
context
controllers
helpers
attach.go
base_controller.go
basic_commits_controller.go
bisect_controller.go
branches_controller.go
command_log_controller.go
commit_description_controller.go
commit_message_controller.go
commits_files_controller.go
common.go
confirmation_controller.go
context_lines_controller.go
custom_patch_options_menu_action.go
diffing_menu_action.go
files_controller.go
filter_controller.go
filtering_menu_action.go
git_flow_controller.go
global_controller.go
jump_to_side_window_controller.go
list_controller.go
list_controller_trait.go
local_commits_controller.go
local_commits_controller_test.go
menu_controller.go
merge_conflicts_controller.go
options_menu_action.go
patch_building_controller.go
patch_explorer_controller.go
quit_actions.go
reflog_commits_controller.go
remote_branches_controller.go
remotes_controller.go
rename_similarity_threshold_controller.go
screen_mode_actions.go
scroll_off_margin.go
scroll_off_margin_test.go
search_controller.go
search_prompt_controller.go
shell_command_action.go
side_window_controller.go
snake_controller.go
staging_controller.go
stash_controller.go
status_controller.go
sub_commits_controller.go
submodules_controller.go
suggestions_controller.go
switch_to_diff_files_controller.go
switch_to_sub_commits_controller.go
sync_controller.go
tags_controller.go
toggle_whitespace_action.go
undo_controller.go
vertical_scroll_controller.go
workspace_reset_controller.go
worktree_options_controller.go
worktrees_controller.go
filetree
keybindings
mergeconflicts
modes
patch_exploring
popup
presentation
services
status
style
types
background.go
command_log_panel.go
context.go
context_config.go
controllers.go
dummies.go
editors.go
extras_panel.go
global_handlers.go
gui.go
gui_common.go
gui_driver.go
information_panel.go
keybindings.go
layout.go
main_panels.go
menu_panel.go
options_map.go
pty.go
pty_windows.go
recent_repos_panel.go
tasks_adapter.go
test_mode.go
view_helpers.go
views.go
i18n
integration
jsonschema
logs
snake
tasks
theme
updates
utils
schema
scripts
test
vendor
.codespellrc
.editorconfig
.gitattributes
.gitignore
.golangci.yml
.goreleaser.yml
CODE-OF-CONDUCT.md
CONTRIBUTING.md
Dockerfile
LICENSE
Makefile
README.md
VISION.md
go.mod
go.sum
main.go
lazygit/pkg/gui/controllers/submodules_controller.go
Stefan Haller d4ef8e53d5 Remove return value of Alert/Confirm/Prompt
This might seem controversial; in many cases the client code gets longer,
because it needs an extra line for an explicit `return nil`. I still prefer
this, because it makes it clearer which calls can return errors.
2024-09-06 08:45:48 +02:00

305 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)}),
DisplayOnScreen: true,
},
{
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,
DisplayOnScreen: true,
},
{
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,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Universal.New),
Handler: self.add,
Description: self.c.Tr.NewSubmodule,
DisplayOnScreen: true,
},
{
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() {
return func() {
self.c.Helpers().Diff.WithDiffModeCheck(func() {
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.FullName()),
style.FgYellow.Sprint(submodule.FullPath()),
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)
}
}
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 {
self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewSubmoduleUrl,
HandleConfirm: func(submoduleUrl string) error {
nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl)))
self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewSubmoduleName,
InitialContent: nameSuggestion,
HandleConfirm: func(submoduleName string) error {
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 {
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
})
return nil
},
})
return nil
},
})
return nil
}
func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) error {
self.c.Prompt(types.PromptOpts{
Title: fmt.Sprintf(self.c.Tr.UpdateSubmoduleUrl, submodule.FullName()),
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, newUrl)
if err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
},
})
return nil
}
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 {
return 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 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 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 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 {
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
})
}
func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) error {
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.RemoveSubmodule,
Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.FullName()),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RemoveSubmodule)
if err := self.c.Git().Submodule.Delete(submodule); err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES, types.FILES}})
},
})
return nil
}
func (self *SubmodulesController) easterEgg() error {
self.c.Context().Push(self.c.Contexts().Snake)
return nil
}
func (self *SubmodulesController) context() *context.SubmodulesContext {
return self.c.Contexts().Submodules
}