1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-05 15:15:49 +02:00

add half and fullscreen modes

This commit is contained in:
Jesse Duffield 2020-02-25 08:32:46 +11:00
parent 52b5a6410c
commit fdb543fa7d
6 changed files with 172 additions and 58 deletions

View File

@ -75,6 +75,8 @@ Default path for the config file:
createPatchOptionsMenu: '<c-p>'
nextTab: ']'
prevTab: '['
nextScreenMode: '+'
prevScreenMode: '_'
status:
checkForUpdate: 'u'
recentRepos: '<enter>'

View File

@ -308,6 +308,8 @@ keybinding:
createPatchOptionsMenu: '<c-p>'
nextTab: ']'
prevTab: '['
nextScreenMode: '+'
prevScreenMode: '_'
status:
checkForUpdate: 'u'
recentRepos: '<enter>'

View File

@ -33,6 +33,12 @@ import (
"github.com/sirupsen/logrus"
)
const (
SCREEN_NORMAL int = iota
SCREEN_HALF
SCREEN_FULL
)
const StartupPopupVersion = 1
// OverlappingEdges determines if panel edges overlap
@ -202,6 +208,8 @@ type guiState struct {
IsRefreshingFiles bool
RefreshingFilesMutex sync.Mutex
Searching searchingState
ScreenMode int
SideView *gocui.View
}
// for now the split view will always be on
@ -236,6 +244,8 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
},
Status: &statusPanelState{},
},
ScreenMode: SCREEN_NORMAL,
SideView: nil,
}
gui := &Gui{
@ -257,6 +267,18 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *comma
return gui, nil
}
func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error {
gui.State.ScreenMode = utils.NextIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
return nil
}
func (gui *Gui) prevScreenMode(g *gocui.Gui, v *gocui.View) error {
gui.State.ScreenMode = utils.PrevIntInCycle([]int{SCREEN_NORMAL, SCREEN_HALF, SCREEN_FULL}, gui.State.ScreenMode)
return nil
}
func (gui *Gui) scrollUpView(viewName string) error {
mainView, _ := gui.g.View(viewName)
ox, oy := mainView.Origin()
@ -379,6 +401,75 @@ func (gui *Gui) onFocus(v *gocui.View) error {
return nil
}
func (gui *Gui) getViewHeights() map[string]int {
currView := gui.g.CurrentView()
currentCyclebleView := gui.State.PreviousView
if currView != nil {
viewName := currView.Name()
usePreviousView := true
for _, view := range cyclableViews {
if view == viewName {
currentCyclebleView = viewName
usePreviousView = false
break
}
}
if usePreviousView {
currentCyclebleView = gui.State.PreviousView
}
}
// unfortunate result of the fact that these are separate views, have to map explicitly
if currentCyclebleView == "commitFiles" {
currentCyclebleView = "commits"
}
_, height := gui.g.Size()
if gui.State.ScreenMode == SCREEN_FULL || gui.State.ScreenMode == SCREEN_HALF {
vHeights := map[string]int{
"status": 0,
"files": 0,
"branches": 0,
"commits": 0,
"stash": 0,
"options": 0,
}
vHeights[currentCyclebleView] = height - 1
return vHeights
}
usableSpace := height - 7
extraSpace := usableSpace - (usableSpace/3)*3
if height >= 28 {
return map[string]int{
"status": 3,
"files": (usableSpace / 3) + extraSpace,
"branches": usableSpace / 3,
"commits": usableSpace / 3,
"stash": 3,
"options": 1,
}
}
defaultHeight := 3
if height < 21 {
defaultHeight = 1
}
vHeights := map[string]int{
"status": defaultHeight,
"files": defaultHeight,
"branches": defaultHeight,
"commits": defaultHeight,
"stash": defaultHeight,
"options": defaultHeight,
}
vHeights[currentCyclebleView] = height - defaultHeight*4 - 1
return vHeights
}
// layout is called for every screen re-render e.g. when the screen is resized
func (gui *Gui) layout(g *gocui.Gui) error {
g.Highlight = true
@ -405,50 +496,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return nil
}
currView := gui.g.CurrentView()
currentCyclebleView := gui.State.PreviousView
if currView != nil {
viewName := currView.Name()
usePreviouseView := true
for _, view := range cyclableViews {
if view == viewName {
currentCyclebleView = viewName
usePreviouseView = false
break
}
}
if usePreviouseView {
currentCyclebleView = gui.State.PreviousView
}
}
usableSpace := height - 7
extraSpace := usableSpace - (usableSpace/3)*3
vHeights := map[string]int{
"status": 3,
"files": (usableSpace / 3) + extraSpace,
"branches": usableSpace / 3,
"commits": usableSpace / 3,
"stash": 3,
"options": 1,
}
if height < 28 {
defaultHeight := 3
if height < 21 {
defaultHeight = 1
}
vHeights = map[string]int{
"status": defaultHeight,
"files": defaultHeight,
"branches": defaultHeight,
"commits": defaultHeight,
"stash": defaultHeight,
"options": defaultHeight,
}
vHeights[currentCyclebleView] = height - defaultHeight*4 - 1
}
vHeights := gui.getViewHeights()
optionsVersionBoundary := width - max(len(utils.Decolorise(information)), 1)
@ -458,29 +506,45 @@ func (gui *Gui) layout(g *gocui.Gui) error {
appStatusOptionsBoundary = len(appStatus) + 2
}
panelSpacing := 1
if OverlappingEdges {
panelSpacing = 0
}
_, _ = g.SetViewOnBottom("limit")
g.DeleteView("limit")
textColor := theme.GocuiDefaultTextColor
leftSideWidth := width / 3
var leftSideWidth int
switch gui.State.ScreenMode {
case SCREEN_NORMAL:
leftSideWidth = width / 3
case SCREEN_HALF:
leftSideWidth = width / 2
case SCREEN_FULL:
currentView := gui.g.CurrentView()
if currentView != nil && currentView.Name() == "main" {
leftSideWidth = 0
} else {
leftSideWidth = width - 1
}
}
panelSplitX := width - 1
mainPanelLeft := leftSideWidth + 1
mainPanelRight := width - 1
secondaryPanelLeft := width - 1
secondaryPanelTop := 0
mainPanelBottom := height - 2
if gui.State.SplitMainPanel {
if width < 220 {
if gui.State.ScreenMode == SCREEN_FULL {
mainPanelLeft = 0
panelSplitX = width/2 - 4
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
} else if width < 220 {
mainPanelBottom = height/2 - 1
secondaryPanelTop = mainPanelBottom + 1
secondaryPanelLeft = leftSideWidth + 1
} else {
units := 5
leftSideWidth = width / units
mainPanelLeft = leftSideWidth + 1
panelSplitX = (1 + ((units - 1) / 2)) * width / units
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
@ -510,7 +574,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
v, err := g.SetView(main, leftSideWidth+panelSpacing, 0, mainPanelRight, mainPanelBottom, gocui.LEFT)
v, err := g.SetView(main, mainPanelLeft, 0, mainPanelRight, mainPanelBottom, gocui.LEFT)
if err != nil {
if err.Error() != "unknown view" {
return err
@ -519,16 +583,15 @@ func (gui *Gui) layout(g *gocui.Gui) error {
v.Wrap = true
v.FgColor = textColor
v.IgnoreCarriageReturns = true
v.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
return nil
}))
}
hiddenViewOffset := 0
hiddenViewOffset := 9999
hiddenSecondaryPanelOffset := 0
if !gui.State.SplitMainPanel {
hiddenViewOffset = 9999
hiddenSecondaryPanelOffset = hiddenViewOffset
}
secondaryView, err := g.SetView(secondary, secondaryPanelLeft+hiddenViewOffset, hiddenViewOffset+secondaryPanelTop, width-1+hiddenViewOffset, height-2+hiddenViewOffset, gocui.LEFT)
secondaryView, err := g.SetView(secondary, secondaryPanelLeft+hiddenSecondaryPanelOffset, hiddenSecondaryPanelOffset+secondaryPanelTop, width-1+hiddenSecondaryPanelOffset, height-2+hiddenSecondaryPanelOffset, gocui.LEFT)
if err != nil {
if err.Error() != "unknown view" {
return err
@ -577,6 +640,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
v.Title = gui.Tr.SLocalize("CommitFiles")
v.FgColor = textColor
v.SetOnSelectItem(gui.onSelectItemWrapper(gui.onCommitFilesPanelSearchSelect))
v.ContainsList = true
}
commitsView, err := g.SetViewBeneath("commits", "branches", vHeights["commits"])

View File

@ -317,6 +317,20 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleEditConfig,
Description: gui.Tr.SLocalize("EditConfig"),
},
{
ViewName: "",
Key: gui.getKey("universal.nextScreenMode"),
Modifier: gocui.ModNone,
Handler: gui.nextScreenMode,
Description: gui.Tr.SLocalize("nextScreenMode"),
},
{
ViewName: "",
Key: gui.getKey("universal.prevScreenMode"),
Modifier: gocui.ModNone,
Handler: gui.prevScreenMode,
Description: gui.Tr.SLocalize("prevScreenMode"),
},
{
ViewName: "status",
Key: gui.getKey("universal.openFile"),

View File

@ -945,6 +945,12 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "viewResetToUpstreamOptions",
Other: "view upstream reset options",
}, &i18n.Message{
ID: "nextScreenMode",
Other: "next screen mode (normal/half/fullscreen)",
}, &i18n.Message{
ID: "prevScreenMode",
Other: "prev screen mode",
},
)
}

View File

@ -322,3 +322,29 @@ func ModuloWithWrap(n, max int) int {
return n
}
}
// NextIntInCycle returns the next int in a slice, returning to the first index if we've reached the end
func NextIntInCycle(sl []int, current int) int {
for i, val := range sl {
if val == current {
if i == len(sl)-1 {
return sl[0]
}
return sl[i+1]
}
}
return sl[0]
}
// PrevIntInCycle returns the prev int in a slice, returning to the first index if we've reached the end
func PrevIntInCycle(sl []int, current int) int {
for i, val := range sl {
if val == current {
if i > 0 {
return sl[i-1]
}
return sl[len(sl)-1]
}
}
return sl[len(sl)-1]
}