diff options
Diffstat (limited to 'gui/extensions.go')
| -rw-r--r-- | gui/extensions.go | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/gui/extensions.go b/gui/extensions.go new file mode 100644 index 0000000..b25848c --- /dev/null +++ b/gui/extensions.go @@ -0,0 +1,198 @@ +package gui + +import ( + "github.com/jroimartin/gocui" + log "github.com/sirupsen/logrus" +) + +// focus to next view +func (gui *Gui) nextViewOfGroup(g *gocui.Gui, v *gocui.View, group []viewFeature) error { + var focusedViewName string + if v == nil || v.Name() == group[len(group)-1].Name { + focusedViewName = group[0].Name + } else { + for i := range group { + if v.Name() == group[i].Name { + focusedViewName = group[i+1].Name + break + } + if i == len(group)-1 { + return nil + } + } + } + if _, err := g.SetCurrentView(focusedViewName); err != nil { + log.WithFields(log.Fields{ + "view": focusedViewName, + }).Warn("View cannot be focused.") + return nil + } + + return gui.updateKeyBindingsView(g, focusedViewName) +} + +// focus to previous view +func (gui *Gui) previousViewOfGroup(g *gocui.Gui, v *gocui.View, group []viewFeature) error { + var focusedViewName string + if v == nil || v.Name() == group[0].Name { + focusedViewName = group[len(group)-1].Name + } else { + for i := range group { + if v.Name() == group[i].Name { + focusedViewName = group[i-1].Name + break + } + if i == len(group)-1 { + return nil + } + } + } + if _, err := g.SetCurrentView(focusedViewName); err != nil { + log.WithFields(log.Fields{ + "view": focusedViewName, + }).Warn("View cannot be focused.") + return nil + } + + return gui.updateKeyBindingsView(g, focusedViewName) +} + +// siwtch the app's mode to fetch +func (gui *Gui) switchToFetchMode(g *gocui.Gui, v *gocui.View) error { + gui.State.Mode = fetchMode + return gui.updateKeyBindingsView(g, mainViewFeature.Name) +} + +// siwtch the app's mode to pull +func (gui *Gui) switchToPullMode(g *gocui.Gui, v *gocui.View) error { + gui.State.Mode = pullMode + return gui.updateKeyBindingsView(g, mainViewFeature.Name) +} + +// siwtch the app's mode to merge +func (gui *Gui) switchToMergeMode(g *gocui.Gui, v *gocui.View) error { + gui.State.Mode = mergeMode + return gui.updateKeyBindingsView(g, mainViewFeature.Name) +} + +// bring the view on the top by its name +func (gui *Gui) setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { + if _, err := g.SetCurrentView(name); err != nil { + return nil, err + } + return g.SetViewOnTop(name) +} + +// 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() + ox, oy := v.Origin() + width, height := v.Size() + maxY := height - 1 + ly := width - 1 + if oy+cy <= ly { + return nil + } + newCy := min(ly, maxY) + if err := v.SetCursor(cx, newCy); err != nil { + return err + } + err := v.SetOrigin(ox, ly-newCy) + return err +} + +// min finds the minimum value of two int +func min(x, y int) int { + if x < y { + return x + } + return y +} + +// this function handles the iteration of a side view and set its origin point +// so that the selected line can be in the middle of the view +func (gui *Gui) smartAnchorRelativeToLine(v *gocui.View, currentindex, totallines int) error { + _, y := v.Size() + if currentindex >= int(0.5*float32(y)) && totallines-currentindex+int(0.5*float32(y)) >= y { + if err := v.SetOrigin(0, currentindex-int(0.5*float32(y))); err != nil { + return err + } + } else if totallines-currentindex < y && totallines > y { + if err := v.SetOrigin(0, totallines-y); err != nil { + return err + } + } else if totallines-currentindex <= int(0.5*float32(y)) && totallines > y-1 && currentindex > y { + if err := v.SetOrigin(0, currentindex-int(0.5*float32(y))); err != nil { + return err + } + } else { + if err := v.SetOrigin(0, 0); err != nil { + return err + } + } + return nil +} + +// this function writes the given text to rgiht hand side of the view +// cx and cy values are important to get the cursor to its old position +func writeRightHandSide(v *gocui.View, text string, cx, cy int) error { + runes := []rune(text) + tl := len(runes) + lx, _ := v.Size() + v.MoveCursor(lx-tl, cy-1, true) + for i := tl - 1; i >= 0; i-- { + v.EditDelete(true) + v.EditWrite(runes[i]) + } + v.SetCursor(cx, cy) + return nil +} + +// cursor down acts like half-page down for faster scrolling +func (gui *Gui) fastCursorDown(g *gocui.Gui, v *gocui.View) error { + if v != nil { + ox, oy := v.Origin() + _, vy := v.Size() + if len(v.BufferLines())+len(v.ViewBufferLines()) <= vy+oy || len(v.ViewBufferLines()) < vy { + return nil + } + // TODO: do something when it hits bottom + if err := v.SetOrigin(ox, oy+vy/2); err != nil { + return err + } + } + return nil +} + +// cursor up acts like half-page up for faster scrolling +func (gui *Gui) fastCursorUp(g *gocui.Gui, v *gocui.View) error { + if v != nil { + ox, oy := v.Origin() + _, vy := v.Size() + + if oy-vy/2 > 0 { + if err := v.SetOrigin(ox, oy-vy/2); err != nil { + return err + } + } else if oy-vy/2 <= 0 { + if err := v.SetOrigin(0, 0); err != nil { + return err + } + } + } + return nil +} + +// closeViewCleanup both updates the keybidings view and focuses to returning view +func (gui *Gui) closeViewCleanup(returningViewName string) (err error) { + if _, err = gui.g.SetCurrentView(returningViewName); err != nil { + return err + } + err = gui.updateKeyBindingsView(gui.g, returningViewName) + return err +} + +// focus to view same as closeViewCleanup but its just a wrapper for easy reading +func (gui *Gui) focusToView(viewName string) (err error) { + return gui.closeViewCleanup(viewName) +} |
