mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-12 11:15:00 +02:00
49da7b482d
When we use the one panel for the entire commit message, its tricky to have a keybinding both for adding a newline and submitting. By having two panels: one for the summary line and one for the description, we allow for 'enter' to submit the message when done from the summary panel, and 'enter' to add a newline when done from the description panel. Alt-enter, for those who can use that key combo, also works for submitting the message from the description panel. For those who can't use that key combo, and don't want to remap the keybinding, they can hit tab to go back to the summary panel and then 'enter' to submit the message. We have some awkwardness in that both contexts (i.e. panels) need to appear and disappear in tandem and we don't have a great way of handling that concept, so we just push both contexts one after the other, and likewise remove both contexts when we escape.
221 lines
5.9 KiB
Go
221 lines
5.9 KiB
Go
package components
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/jesseduffield/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
)
|
|
|
|
type Views struct {
|
|
t *TestDriver
|
|
}
|
|
|
|
func (self *Views) Main() *ViewDriver {
|
|
return &ViewDriver{
|
|
context: "main view",
|
|
getView: func() *gocui.View { return self.t.gui.MainView() },
|
|
t: self.t,
|
|
}
|
|
}
|
|
|
|
func (self *Views) Secondary() *ViewDriver {
|
|
return &ViewDriver{
|
|
context: "secondary view",
|
|
getView: func() *gocui.View { return self.t.gui.SecondaryView() },
|
|
t: self.t,
|
|
}
|
|
}
|
|
|
|
func (self *Views) regularView(viewName string) *ViewDriver {
|
|
return self.newStaticViewDriver(viewName, nil, nil, nil)
|
|
}
|
|
|
|
func (self *Views) patchExplorerViewByName(viewName string) *ViewDriver {
|
|
return self.newStaticViewDriver(
|
|
viewName,
|
|
func() ([]string, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.PatchExplorerContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return nil, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
selectedContent := state.PlainRenderSelected()
|
|
// the above method returns a string with a trailing newline so we need to remove that before splitting
|
|
selectedLines := strings.Split(strings.TrimSuffix(selectedContent, "\n"), "\n")
|
|
return selectedLines, nil
|
|
},
|
|
func() (int, int, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.PatchExplorerContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return 0, 0, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
startIdx, endIdx := state.SelectedRange()
|
|
return startIdx, endIdx, nil
|
|
},
|
|
func() (int, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.PatchExplorerContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return 0, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
return state.GetSelectedLineIdx(), nil
|
|
},
|
|
)
|
|
}
|
|
|
|
// 'static' because it'll always refer to the same view, as opposed to the 'main' view which could actually be
|
|
// one of several views, or the 'current' view which depends on focus.
|
|
func (self *Views) newStaticViewDriver(
|
|
viewName string,
|
|
getSelectedLinesFn func() ([]string, error),
|
|
getSelectedLineRangeFn func() (int, int, error),
|
|
getSelectedLineIdxFn func() (int, error),
|
|
) *ViewDriver {
|
|
return &ViewDriver{
|
|
context: fmt.Sprintf("%s view", viewName),
|
|
getView: func() *gocui.View { return self.t.gui.View(viewName) },
|
|
getSelectedLinesFn: getSelectedLinesFn,
|
|
getSelectedRangeFn: getSelectedLineRangeFn,
|
|
getSelectedLineIdxFn: getSelectedLineIdxFn,
|
|
t: self.t,
|
|
}
|
|
}
|
|
|
|
func (self *Views) MergeConflicts() *ViewDriver {
|
|
viewName := "mergeConflicts"
|
|
return self.newStaticViewDriver(
|
|
viewName,
|
|
func() ([]string, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.MergeConflictsContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return nil, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
selectedContent := strings.Split(state.PlainRenderSelected(), "\n")
|
|
|
|
return selectedContent, nil
|
|
},
|
|
func() (int, int, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.MergeConflictsContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return 0, 0, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
startIdx, endIdx := state.GetSelectedRange()
|
|
return startIdx, endIdx, nil
|
|
},
|
|
// there is no concept of a cursor in the merge conflicts panel so we just return the start of the selection
|
|
func() (int, error) {
|
|
ctx := self.t.gui.ContextForView(viewName).(*context.MergeConflictsContext)
|
|
state := ctx.GetState()
|
|
if state == nil {
|
|
return 0, errors.New("Expected patch explorer to be activated")
|
|
}
|
|
startIdx, _ := state.GetSelectedRange()
|
|
return startIdx, nil
|
|
},
|
|
)
|
|
}
|
|
|
|
func (self *Views) Commits() *ViewDriver {
|
|
return self.regularView("commits")
|
|
}
|
|
|
|
func (self *Views) Files() *ViewDriver {
|
|
return self.regularView("files")
|
|
}
|
|
|
|
func (self *Views) Status() *ViewDriver {
|
|
return self.regularView("status")
|
|
}
|
|
|
|
func (self *Views) Submodules() *ViewDriver {
|
|
return self.regularView("submodules")
|
|
}
|
|
|
|
func (self *Views) Information() *ViewDriver {
|
|
return self.regularView("information")
|
|
}
|
|
|
|
func (self *Views) AppStatus() *ViewDriver {
|
|
return self.regularView("appStatus")
|
|
}
|
|
|
|
func (self *Views) Branches() *ViewDriver {
|
|
return self.regularView("localBranches")
|
|
}
|
|
|
|
func (self *Views) Remotes() *ViewDriver {
|
|
return self.regularView("remotes")
|
|
}
|
|
|
|
func (self *Views) RemoteBranches() *ViewDriver {
|
|
return self.regularView("remoteBranches")
|
|
}
|
|
|
|
func (self *Views) Tags() *ViewDriver {
|
|
return self.regularView("tags")
|
|
}
|
|
|
|
func (self *Views) ReflogCommits() *ViewDriver {
|
|
return self.regularView("reflogCommits")
|
|
}
|
|
|
|
func (self *Views) SubCommits() *ViewDriver {
|
|
return self.regularView("subCommits")
|
|
}
|
|
|
|
func (self *Views) CommitFiles() *ViewDriver {
|
|
return self.regularView("commitFiles")
|
|
}
|
|
|
|
func (self *Views) Stash() *ViewDriver {
|
|
return self.regularView("stash")
|
|
}
|
|
|
|
func (self *Views) Staging() *ViewDriver {
|
|
return self.patchExplorerViewByName("staging")
|
|
}
|
|
|
|
func (self *Views) StagingSecondary() *ViewDriver {
|
|
return self.patchExplorerViewByName("stagingSecondary")
|
|
}
|
|
|
|
func (self *Views) PatchBuilding() *ViewDriver {
|
|
return self.patchExplorerViewByName("patchBuilding")
|
|
}
|
|
|
|
func (self *Views) PatchBuildingSecondary() *ViewDriver {
|
|
// this is not a patch explorer view because you can't actually focus it: it
|
|
// just renders content
|
|
return self.regularView("patchBuildingSecondary")
|
|
}
|
|
|
|
func (self *Views) Menu() *ViewDriver {
|
|
return self.regularView("menu")
|
|
}
|
|
|
|
func (self *Views) Confirmation() *ViewDriver {
|
|
return self.regularView("confirmation")
|
|
}
|
|
|
|
func (self *Views) CommitMessage() *ViewDriver {
|
|
return self.regularView("commitMessage")
|
|
}
|
|
|
|
func (self *Views) CommitDescription() *ViewDriver {
|
|
return self.regularView("commitDescription")
|
|
}
|
|
|
|
func (self *Views) Suggestions() *ViewDriver {
|
|
return self.regularView("suggestions")
|
|
}
|
|
|
|
func (self *Views) Search() *ViewDriver {
|
|
return self.regularView("search")
|
|
}
|