diff options
Diffstat (limited to 'termui')
-rw-r--r-- | termui/bug_table.go | 186 | ||||
-rw-r--r-- | termui/termui.go | 132 |
2 files changed, 318 insertions, 0 deletions
diff --git a/termui/bug_table.go b/termui/bug_table.go new file mode 100644 index 00000000..42b7f645 --- /dev/null +++ b/termui/bug_table.go @@ -0,0 +1,186 @@ +package termui + +import ( + "fmt" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/cache" + "github.com/jroimartin/gocui" +) + +type bugTable struct { + cache cache.RepoCacher + bugs []*bug.Snapshot + cursor int +} + +func newBugTable(cache cache.RepoCacher) *bugTable { + return &bugTable{ + cache: cache, + cursor: 0, + } +} + +func (bt *bugTable) paginate(max int) error { + allIds, err := bt.cache.AllBugIds() + if err != nil { + return err + } + + return bt.doPaginate(allIds, max) +} + +func (bt *bugTable) nextPage(max int) error { + allIds, err := bt.cache.AllBugIds() + if err != nil { + return err + } + + if bt.cursor+max > len(allIds) { + return nil + } + + bt.cursor += max + + return bt.doPaginate(allIds, max) +} + +func (bt *bugTable) previousPage(max int) error { + allIds, err := bt.cache.AllBugIds() + if err != nil { + return err + } + + bt.cursor = maxInt(0, bt.cursor-max) + + return bt.doPaginate(allIds, max) +} + +func (bt *bugTable) doPaginate(allIds []string, max int) error { + // clamp the cursor + bt.cursor = maxInt(bt.cursor, 0) + bt.cursor = minInt(bt.cursor, len(allIds)-1) + + // slice the data + nb := minInt(len(allIds)-bt.cursor, max) + + ids := allIds[bt.cursor:nb] + + bt.bugs = make([]*bug.Snapshot, len(ids)) + + for i, id := range ids { + b, err := bt.cache.ResolveBug(id) + if err != nil { + return err + } + + bt.bugs[i] = b.Snapshot() + } + + return nil +} + +func (bt *bugTable) layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + + v, err := g.SetView("header", -1, -1, maxX, 3) + + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + + v.Frame = false + } + + v.Clear() + ui.bugTable.renderHeader(v, maxX) + + v, err = g.SetView("table", -1, 1, maxX, maxY-2) + + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + + v.Frame = false + v.Highlight = true + v.SelBgColor = gocui.ColorWhite + v.SelFgColor = gocui.ColorBlack + + _, err = g.SetCurrentView("table") + + if err != nil { + return err + } + } + + _, tableHeight := v.Size() + err = bt.paginate(tableHeight) + if err != nil { + return err + } + + v.Clear() + ui.bugTable.render(v, maxX) + + v, err = g.SetView("footer", -1, maxY-3, maxX, maxY) + + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + + v.Frame = false + } + + v.Clear() + ui.bugTable.renderFooter(v, maxX) + + v, err = g.SetView("instructions", -1, maxY-2, maxX, maxY) + + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + + v.Frame = false + v.BgColor = gocui.ColorBlue + + fmt.Fprintf(v, "[q] Quit [h] Go back [j] Down [k] Up [l] Go forward [m] Load Additional [p] Play [enter] Play and Exit") + } + + return nil +} + +func (bt *bugTable) getTableLength() int { + return len(bt.bugs) +} + +func (bt *bugTable) render(v *gocui.View, maxX int) { + for _, b := range bt.bugs { + fmt.Fprintln(v, b.Title) + } +} + +func (bt *bugTable) renderHeader(v *gocui.View, maxX int) { + fmt.Fprintf(v, "header") + +} + +func (bt *bugTable) renderFooter(v *gocui.View, maxX int) { + fmt.Fprintf(v, "footer") +} + +func maxInt(a, b int) int { + if a > b { + return a + } + return b +} + +func minInt(a, b int) int { + if a > b { + return b + } + return a +} diff --git a/termui/termui.go b/termui/termui.go new file mode 100644 index 00000000..a8248442 --- /dev/null +++ b/termui/termui.go @@ -0,0 +1,132 @@ +package termui + +import ( + "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/repository" + "github.com/jroimartin/gocui" +) + +type termUI struct { + cache cache.RepoCacher + bugTable *bugTable +} + +var ui *termUI + +func Run(repo repository.Repo) error { + c := cache.NewRepoCache(repo) + + ui = &termUI{ + cache: c, + bugTable: newBugTable(c), + } + + g, err := gocui.NewGui(gocui.OutputNormal) + + if err != nil { + return err + } + + defer g.Close() + + g.SetManagerFunc(layout) + + err = keybindings(g) + + if err != nil { + return err + } + + err = g.MainLoop() + + if err != nil && err != gocui.ErrQuit { + return err + } + + return nil +} + +func layout(g *gocui.Gui) error { + //maxX, maxY := g.Size() + + ui.bugTable.layout(g) + + v, err := g.View("table") + if err != nil { + return err + } + + cursorClamp(v) + + return nil +} + +func keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil { + return err + } + if err := g.SetKeybinding("table", 'j', gocui.ModNone, cursorDown); err != nil { + return err + } + if err := g.SetKeybinding("table", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil { + return err + } + if err := g.SetKeybinding("table", 'k', gocui.ModNone, cursorUp); err != nil { + return err + } + if err := g.SetKeybinding("table", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil { + return err + } + + //err = g.SetKeybinding("table", 'h', gocui.ModNone, popTable) + //err = g.SetKeybinding("table", gocui.KeyArrowLeft, gocui.ModNone, popTable) + //err = g.SetKeybinding("table", 'l', gocui.ModNone, pushTable) + //err = g.SetKeybinding("table", gocui.KeyArrowRight, gocui.ModNone, pushTable) + //err = g.SetKeybinding("table", 'p', gocui.ModNone, playSelected) + //err = g.SetKeybinding("table", gocui.KeyEnter, gocui.ModNone, playSelectedAndExit) + //err = g.SetKeybinding("table", 'm', gocui.ModNone, loadNextRecords) + + return nil +} + +func quit(g *gocui.Gui, v *gocui.View) error { + return gocui.ErrQuit +} + +func cursorDown(g *gocui.Gui, v *gocui.View) error { + _, y := v.Cursor() + y = minInt(y+1, ui.bugTable.getTableLength()-1) + + err := v.SetCursor(0, y) + if err != nil { + return err + } + + return nil +} + +func cursorUp(g *gocui.Gui, v *gocui.View) error { + _, y := v.Cursor() + y = maxInt(y-1, 0) + + err := v.SetCursor(0, y) + if err != nil { + return err + } + + return nil +} + +func cursorClamp(v *gocui.View) error { + _, y := v.Cursor() + + y = minInt(y, ui.bugTable.getTableLength()-1) + y = maxInt(y, 0) + + err := v.SetCursor(0, y) + if err != nil { + return err + } + + return nil +} |