1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-11-30 09:16:47 +02:00
lazygit/pkg/gui/view_helpers.go

270 lines
6.2 KiB
Go
Raw Normal View History

2018-08-14 11:05:26 +02:00
package gui
2018-05-26 05:23:39 +02:00
import (
"fmt"
"sort"
"strings"
"time"
2018-05-26 05:23:39 +02:00
"github.com/jesseduffield/gocui"
2018-05-26 05:23:39 +02:00
)
2018-06-06 04:17:49 +02:00
var cyclableViews = []string{"files", "branches", "commits", "stash"}
2018-08-14 11:05:26 +02:00
func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
gui.refreshBranches(g)
gui.refreshFiles(g)
gui.refreshCommits(g)
return nil
2018-06-06 04:17:49 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error {
var focusedViewName string
if v == nil || v.Name() == cyclableViews[len(cyclableViews)-1] {
focusedViewName = cyclableViews[0]
} else {
for i := range cyclableViews {
if v.Name() == cyclableViews[i] {
focusedViewName = cyclableViews[i+1]
break
}
if i == len(cyclableViews)-1 {
2018-08-15 11:49:43 +02:00
message := gui.Tr.TemplateLocalize(
"IssntListOfViews",
Teml{
2018-08-15 11:49:43 +02:00
"name": v.Name(),
},
)
gui.Log.Info(message)
return nil
}
}
}
focusedView, err := g.View(focusedViewName)
if err != nil {
panic(err)
}
2018-08-14 11:05:26 +02:00
return gui.switchFocus(g, v, focusedView)
2018-06-06 04:17:49 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error {
var focusedViewName string
2018-07-22 04:58:39 +02:00
if v == nil || v.Name() == cyclableViews[0] {
focusedViewName = cyclableViews[len(cyclableViews)-1]
} else {
for i := range cyclableViews {
if v.Name() == cyclableViews[i] {
focusedViewName = cyclableViews[i-1] // TODO: make this work properly
break
}
if i == len(cyclableViews)-1 {
2018-08-15 11:49:43 +02:00
message := gui.Tr.TemplateLocalize(
"IssntListOfViews",
Teml{
2018-08-15 11:49:43 +02:00
"name": v.Name(),
},
)
gui.Log.Info(message)
return nil
}
}
}
focusedView, err := g.View(focusedViewName)
if err != nil {
panic(err)
}
2018-08-14 11:05:26 +02:00
return gui.switchFocus(g, v, focusedView)
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error {
mainView, _ := g.View("main")
mainView.SetOrigin(0, 0)
switch v.Name() {
case "files":
2018-08-14 11:05:26 +02:00
return gui.handleFileSelect(g, v)
case "branches":
2018-08-14 11:05:26 +02:00
return gui.handleBranchSelect(g, v)
case "confirmation":
return nil
2018-08-11 07:09:37 +02:00
case "commitMessage":
2018-08-14 11:05:26 +02:00
return gui.handleCommitFocused(g, v)
case "main":
// TODO: pull this out into a 'view focused' function
2018-08-14 11:05:26 +02:00
gui.refreshMergePanel(g)
v.Highlight = false
return nil
case "commits":
2018-08-14 11:05:26 +02:00
return gui.handleCommitSelect(g, v)
case "stash":
2018-08-14 11:05:26 +02:00
return gui.handleStashEntrySelect(g, v)
default:
panic(gui.Tr.SLocalize("NoViewMachingNewLineFocusedSwitchStatement"))
}
2018-06-06 04:17:49 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error {
previousView, err := g.View(gui.State.PreviousView)
if err != nil {
panic(err)
}
2018-08-14 11:05:26 +02:00
return gui.switchFocus(g, v, previousView)
2018-05-26 05:23:39 +02:00
}
2018-06-09 11:06:33 +02:00
// pass in oldView = nil if you don't want to be able to return to your old view
2018-08-14 11:05:26 +02:00
func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error {
// we assume we'll never want to return focus to a confirmation panel i.e.
// we should never stack confirmation panels
if oldView != nil && oldView.Name() != "confirmation" {
oldView.Highlight = false
2018-08-15 11:49:43 +02:00
message := gui.Tr.TemplateLocalize(
"settingPreviewsViewTo",
Teml{
2018-08-15 11:49:43 +02:00
"oldViewName": oldView.Name(),
},
)
gui.Log.Info(message)
2018-08-14 11:05:26 +02:00
gui.State.PreviousView = oldView.Name()
}
newView.Highlight = true
2018-08-15 11:49:43 +02:00
message := gui.Tr.TemplateLocalize(
"newFocusedViewIs",
Teml{
2018-08-15 11:49:43 +02:00
"newFocusedView": newView.Name(),
},
)
gui.Log.Info(message)
if _, err := g.SetCurrentView(newView.Name()); err != nil {
return err
}
g.Cursor = newView.Editable
2018-08-14 11:05:26 +02:00
return gui.newLineFocused(g, newView)
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) getItemPosition(v *gocui.View) int {
gui.correctCursor(v)
_, cy := v.Cursor()
_, oy := v.Origin()
return oy + cy
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) cursorUp(g *gocui.Gui, v *gocui.View) error {
// swallowing cursor movements in main
// TODO: pull this out
if v == nil || v.Name() == "main" {
return nil
}
ox, oy := v.Origin()
cx, cy := v.Cursor()
if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
if err := v.SetOrigin(ox, oy-1); err != nil {
return err
}
}
2018-08-14 11:05:26 +02:00
gui.newLineFocused(g, v)
return nil
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) cursorDown(g *gocui.Gui, v *gocui.View) error {
// swallowing cursor movements in main
// TODO: pull this out
if v == nil || v.Name() == "main" {
return nil
}
cx, cy := v.Cursor()
ox, oy := v.Origin()
if cy+oy >= len(v.BufferLines())-2 {
return nil
}
if err := v.SetCursor(cx, cy+1); err != nil {
if err := v.SetOrigin(ox, oy+1); err != nil {
return err
}
}
2018-08-14 11:05:26 +02:00
gui.newLineFocused(g, v)
return nil
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) resetOrigin(v *gocui.View) error {
if err := v.SetCursor(0, 0); err != nil {
return err
}
return v.SetOrigin(0, 0)
2018-06-09 11:06:33 +02:00
}
2018-08-14 11:05:26 +02:00
// if the cursor down past the last item, move it to the last line
func (gui *Gui) correctCursor(v *gocui.View) error {
cx, cy := v.Cursor()
_, oy := v.Origin()
lineCount := len(v.BufferLines()) - 2
if cy >= lineCount-oy {
return v.SetCursor(cx, lineCount-oy)
}
return nil
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
g.Update(func(*gocui.Gui) error {
v, err := g.View(viewName)
// just in case the view disappeared as this function was called, we'll
// silently return if it's not found
if err != nil {
return nil
}
v.Clear()
fmt.Fprint(v, s)
v.Wrap = true
return nil
})
return nil
2018-05-26 05:23:39 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
optionsArray := make([]string, 0)
for key, description := range optionsMap {
optionsArray = append(optionsArray, key+": "+description)
}
sort.Strings(optionsArray)
return strings.Join(optionsArray, ", ")
2018-06-09 11:06:33 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) renderOptionsMap(g *gocui.Gui, optionsMap map[string]string) error {
return gui.renderString(g, "options", gui.optionsMapToString(optionsMap))
2018-06-09 11:06:33 +02:00
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) loader() string {
characters := "|/-\\"
now := time.Now()
nanos := now.UnixNano()
index := nanos / 50000000 % int64(len(characters))
return characters[index : index+1]
}
2018-08-11 07:09:37 +02:00
// TODO: refactor properly
2018-08-14 11:05:26 +02:00
func (gui *Gui) getFilesView(g *gocui.Gui) *gocui.View {
2018-08-11 07:09:37 +02:00
v, _ := g.View("files")
return v
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) getCommitsView(g *gocui.Gui) *gocui.View {
2018-08-11 07:09:37 +02:00
v, _ := g.View("commits")
return v
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) getCommitMessageView(g *gocui.Gui) *gocui.View {
2018-08-11 07:09:37 +02:00
v, _ := g.View("commitMessage")
return v
}
2018-08-14 11:05:26 +02:00
func (gui *Gui) trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer())
}
func (gui *Gui) currentViewName(g *gocui.Gui) string {
currentView := g.CurrentView()
return currentView.Name()
}