2022-09-01 20:25:41 +02:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-09-03 05:57:39 +02:00
|
|
|
"strings"
|
|
|
|
"text/tabwriter"
|
2022-09-01 20:25:41 +02:00
|
|
|
|
2023-07-16 05:53:59 +02:00
|
|
|
"github.com/jesseduffield/gocui"
|
2022-09-01 20:25:41 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
2022-09-02 02:58:36 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
2022-09-01 20:25:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type WorktreesController struct {
|
|
|
|
baseController
|
|
|
|
c *ControllerCommon
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ types.IController = &WorktreesController{}
|
|
|
|
|
|
|
|
func NewWorktreesController(
|
|
|
|
common *ControllerCommon,
|
|
|
|
) *WorktreesController {
|
|
|
|
return &WorktreesController{
|
|
|
|
baseController: baseController{},
|
|
|
|
c: common,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
|
|
|
bindings := []*types.Binding{
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.Select),
|
|
|
|
Handler: self.checkSelected(self.enter),
|
2023-07-16 06:14:09 +02:00
|
|
|
Description: self.c.Tr.SwitchToWorktree,
|
2022-09-01 20:25:41 +02:00
|
|
|
},
|
2022-09-02 02:58:36 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.Remove),
|
2023-07-16 05:53:59 +02:00
|
|
|
Handler: self.checkSelected(self.remove),
|
|
|
|
Description: self.c.Tr.RemoveWorktree,
|
2022-09-02 02:58:36 +02:00
|
|
|
},
|
2022-09-03 06:38:16 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.New),
|
2023-07-16 05:53:59 +02:00
|
|
|
Handler: self.add,
|
2022-09-03 06:38:16 +02:00
|
|
|
Description: self.c.Tr.CreateWorktree,
|
|
|
|
},
|
2022-09-01 20:25:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return bindings
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) GetOnRenderToMain() func() error {
|
|
|
|
return func() error {
|
|
|
|
var task types.UpdateTask
|
|
|
|
worktree := self.context().GetSelected()
|
|
|
|
if worktree == nil {
|
2022-09-03 05:57:39 +02:00
|
|
|
task = types.NewRenderStringTask(self.c.Tr.NoWorktreesThisRepo)
|
2022-09-01 20:25:41 +02:00
|
|
|
} else {
|
2022-09-03 05:57:39 +02:00
|
|
|
main := ""
|
|
|
|
if worktree.Main() {
|
|
|
|
main = style.FgDefault.Sprintf(" %s", self.c.Tr.MainWorktree)
|
|
|
|
}
|
|
|
|
|
2022-09-02 18:35:08 +02:00
|
|
|
missing := ""
|
2022-09-11 07:36:47 +02:00
|
|
|
if self.c.Git().Worktree.IsWorktreePathMissing(worktree) {
|
2022-09-03 05:57:39 +02:00
|
|
|
missing = style.FgRed.Sprintf(" %s", self.c.Tr.MissingWorktree)
|
2022-09-02 18:35:08 +02:00
|
|
|
}
|
2022-09-03 05:57:39 +02:00
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
w := tabwriter.NewWriter(&builder, 0, 0, 2, ' ', 0)
|
|
|
|
_, _ = fmt.Fprintf(w, "%s:\t%s%s\n", self.c.Tr.Name, style.FgGreen.Sprint(worktree.Name()), main)
|
|
|
|
_, _ = fmt.Fprintf(w, "%s:\t%s\n", self.c.Tr.Branch, style.FgYellow.Sprint(worktree.Branch))
|
|
|
|
_, _ = fmt.Fprintf(w, "%s:\t%s%s\n", self.c.Tr.Path, style.FgCyan.Sprint(worktree.Path), missing)
|
|
|
|
_ = w.Flush()
|
|
|
|
|
|
|
|
task = types.NewRenderStringTask(builder.String())
|
2022-09-01 20:25:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self.c.RenderToMainViews(types.RefreshMainOpts{
|
|
|
|
Pair: self.c.MainViewPairs().Normal,
|
|
|
|
Main: &types.ViewUpdateOpts{
|
2022-09-03 05:57:39 +02:00
|
|
|
Title: self.c.Tr.WorktreeTitle,
|
2022-09-01 20:25:41 +02:00
|
|
|
Task: task,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-16 05:53:59 +02:00
|
|
|
func (self *WorktreesController) add() error {
|
2022-09-03 06:38:16 +02:00
|
|
|
return self.c.Helpers().Worktree.NewWorktree()
|
|
|
|
}
|
|
|
|
|
2023-07-16 05:53:59 +02:00
|
|
|
func (self *WorktreesController) remove(worktree *models.Worktree) error {
|
2022-09-02 18:35:08 +02:00
|
|
|
if worktree.Main() {
|
2022-09-02 02:58:36 +02:00
|
|
|
return self.c.ErrorMsg(self.c.Tr.CantDeleteMainWorktree)
|
|
|
|
}
|
|
|
|
|
2022-09-11 07:36:47 +02:00
|
|
|
if self.c.Git().Worktree.IsCurrentWorktree(worktree) {
|
2022-09-02 02:58:36 +02:00
|
|
|
return self.c.ErrorMsg(self.c.Tr.CantDeleteCurrentWorktree)
|
|
|
|
}
|
|
|
|
|
2023-07-16 05:53:59 +02:00
|
|
|
return self.removeWithForce(worktree, false)
|
2022-09-02 02:58:36 +02:00
|
|
|
}
|
|
|
|
|
2023-07-16 05:53:59 +02:00
|
|
|
func (self *WorktreesController) removeWithForce(worktree *models.Worktree, force bool) error {
|
|
|
|
title := self.c.Tr.RemoveWorktreeTitle
|
2022-09-02 02:58:36 +02:00
|
|
|
var templateStr string
|
|
|
|
if force {
|
2023-07-16 05:53:59 +02:00
|
|
|
templateStr = self.c.Tr.ForceRemoveWorktreePrompt
|
2022-09-02 02:58:36 +02:00
|
|
|
} else {
|
2023-07-16 05:53:59 +02:00
|
|
|
templateStr = self.c.Tr.RemoveWorktreePrompt
|
2022-09-02 02:58:36 +02:00
|
|
|
}
|
|
|
|
message := utils.ResolvePlaceholderString(
|
|
|
|
templateStr,
|
|
|
|
map[string]string{
|
2022-09-02 18:35:08 +02:00
|
|
|
"worktreeName": worktree.Name(),
|
2022-09-02 02:58:36 +02:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
return self.c.Confirm(types.ConfirmOpts{
|
|
|
|
Title: title,
|
|
|
|
Prompt: message,
|
|
|
|
HandleConfirm: func() error {
|
2023-07-16 05:53:59 +02:00
|
|
|
return self.c.WithWaitingStatus(self.c.Tr.RemovingWorktree, func(gocui.Task) error {
|
|
|
|
self.c.LogAction(self.c.Tr.RemovingWorktree)
|
|
|
|
if err := self.c.Git().Worktree.Delete(worktree.Path, force); err != nil {
|
|
|
|
errMessage := err.Error()
|
|
|
|
if !force {
|
|
|
|
return self.removeWithForce(worktree, true)
|
|
|
|
}
|
|
|
|
return self.c.ErrorMsg(errMessage)
|
2022-09-02 02:58:36 +02:00
|
|
|
}
|
2023-07-16 05:53:59 +02:00
|
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES}})
|
|
|
|
})
|
2022-09-02 02:58:36 +02:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-09-01 20:25:41 +02:00
|
|
|
func (self *WorktreesController) GetOnClick() func() error {
|
|
|
|
return self.checkSelected(self.enter)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) enter(worktree *models.Worktree) error {
|
2023-07-16 06:37:49 +02:00
|
|
|
return self.c.Helpers().Worktree.Switch(worktree, context.WORKTREES_CONTEXT_KEY)
|
2022-09-01 20:25:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) checkSelected(callback func(worktree *models.Worktree) error) func() error {
|
|
|
|
return func() error {
|
|
|
|
worktree := self.context().GetSelected()
|
|
|
|
if worktree == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(worktree)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) Context() types.Context {
|
|
|
|
return self.context()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *WorktreesController) context() *context.WorktreesContext {
|
|
|
|
return self.c.Contexts().Worktrees
|
|
|
|
}
|