diff options
author | Michael Muré <batolettre@gmail.com> | 2018-07-31 22:19:11 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2018-07-31 22:19:11 +0200 |
commit | 6b012b1e485d369d82cb410a1652f53a752bf21c (patch) | |
tree | b8f882bda85bf8b072fce3b6830f91cbf0a01e1c /termui | |
parent | 20bd25f332a5ca04ee80a8a4965f56ef3e7cdbf2 (diff) | |
download | git-bug-6b012b1e485d369d82cb410a1652f53a752bf21c.tar.gz |
termui: add a reusable error popup, use it for badly formated bug creation
Diffstat (limited to 'termui')
-rw-r--r-- | termui/bug_table.go | 40 | ||||
-rw-r--r-- | termui/error_popup.go | 93 | ||||
-rw-r--r-- | termui/termui.go | 42 |
3 files changed, 142 insertions, 33 deletions
diff --git a/termui/bug_table.go b/termui/bug_table.go index 264dff2d..7f96df02 100644 --- a/termui/bug_table.go +++ b/termui/bug_table.go @@ -27,6 +27,11 @@ func newBugTable(cache cache.RepoCacher) *bugTable { func (bt *bugTable) layout(g *gocui.Gui) error { maxX, maxY := g.Size() + if maxY < 4 { + // window too small ! + return nil + } + v, err := g.SetView("header", -1, -1, maxX, 3) if err != nil { @@ -51,12 +56,6 @@ func (bt *bugTable) layout(g *gocui.Gui) error { v.Highlight = true v.SelBgColor = gocui.ColorWhite v.SelFgColor = gocui.ColorBlack - - _, err = g.SetCurrentView(bugTableView) - - if err != nil { - return err - } } _, viewHeight := v.Size() @@ -99,6 +98,12 @@ func (bt *bugTable) layout(g *gocui.Gui) error { fmt.Fprintf(v, "[q] Quit [←,h] Previous page [↓,j] Down [↑,k] Up [→,l] Next page [enter] Open bug [n] New bug") } + _, err = g.SetCurrentView(bugTableView) + + if err != nil { + return err + } + return nil } @@ -181,6 +186,11 @@ func (bt *bugTable) doPaginate(allIds []string, max int) error { nb := minInt(len(allIds)-bt.cursor, max) + if nb < 0 { + bt.bugs = []*bug.Snapshot{} + return nil + } + // slice the data ids := allIds[bt.cursor : bt.cursor+nb] @@ -260,10 +270,8 @@ func (bt *bugTable) cursorDown(g *gocui.Gui, v *gocui.View) error { _, y := v.Cursor() y = minInt(y+1, bt.getTableLength()-1) - err := v.SetCursor(0, y) - if err != nil { - return err - } + // window is too small to set the cursor properly, ignoring the error + _ = v.SetCursor(0, y) return nil } @@ -272,10 +280,8 @@ func (bt *bugTable) 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 - } + // window is too small to set the cursor properly, ignoring the error + _ = v.SetCursor(0, y) return nil } @@ -286,10 +292,8 @@ func (bt *bugTable) cursorClamp(v *gocui.View) error { y = minInt(y, bt.getTableLength()-1) y = maxInt(y, 0) - err := v.SetCursor(0, y) - if err != nil { - return err - } + // window is too small to set the cursor properly, ignoring the error + _ = v.SetCursor(0, y) return nil } diff --git a/termui/error_popup.go b/termui/error_popup.go new file mode 100644 index 00000000..f0af5a93 --- /dev/null +++ b/termui/error_popup.go @@ -0,0 +1,93 @@ +package termui + +import ( + "fmt" + "github.com/jroimartin/gocui" + "strings" +) + +const errorPopupView = "errorPopupView" + +type errorPopup struct { + err string +} + +func newErrorPopup() *errorPopup { + return &errorPopup{ + err: "", + } +} + +func (ep *errorPopup) keybindings(g *gocui.Gui) error { + if err := g.SetKeybinding(errorPopupView, gocui.KeySpace, gocui.ModNone, ep.close); err != nil { + return err + } + if err := g.SetKeybinding(errorPopupView, gocui.KeyEnter, gocui.ModNone, ep.close); err != nil { + return err + } + + return nil +} + +func (ep *errorPopup) layout(g *gocui.Gui) error { + if ep.err == "" { + return nil + } + + maxX, maxY := g.Size() + + width := minInt(30, maxX) + wrapped, nblines := word_wrap(ep.err, width-2) + height := minInt(nblines+2, maxY) + x0 := (maxX - width) / 2 + y0 := (maxY - height) / 2 + + v, err := g.SetView(errorPopupView, x0, y0, x0+width, y0+height) + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + + v.Frame = true + + fmt.Fprintf(v, wrapped) + } + + if _, err := g.SetCurrentView(errorPopupView); err != nil { + return err + } + + return nil +} + +func (ep *errorPopup) close(g *gocui.Gui, v *gocui.View) error { + ep.err = "" + g.DeleteView(errorPopupView) + return nil +} + +func (ep *errorPopup) isActive() bool { + return ep.err != "" +} + +func word_wrap(text string, lineWidth int) (string, int) { + words := strings.Fields(strings.TrimSpace(text)) + if len(words) == 0 { + return text, 1 + } + lines := 1 + wrapped := words[0] + spaceLeft := lineWidth - len(wrapped) + for _, word := range words[1:] { + if len(word)+1 > spaceLeft { + wrapped += "\n" + word + spaceLeft = lineWidth - len(word) + lines++ + } else { + wrapped += " " + word + spaceLeft -= 1 + len(word) + } + } + + return wrapped, lines +} diff --git a/termui/termui.go b/termui/termui.go index 9ac82fd3..f4a4fb26 100644 --- a/termui/termui.go +++ b/termui/termui.go @@ -16,7 +16,8 @@ type termUI struct { cache cache.RepoCacher activeWindow window - bugTable *bugTable + bugTable *bugTable + errorPopup *errorPopup } var ui *termUI @@ -30,9 +31,10 @@ func Run(repo repository.Repo) error { c := cache.NewRepoCache(repo) ui = &termUI{ - gError: make(chan error, 1), - cache: c, - bugTable: newBugTable(c), + gError: make(chan error, 1), + cache: c, + bugTable: newBugTable(c), + errorPopup: newErrorPopup(), } ui.activeWindow = ui.bugTable @@ -64,6 +66,7 @@ func initGui() { if err != nil { ui.g.Close() + ui.g = nil ui.gError <- err return } @@ -71,7 +74,9 @@ func initGui() { err = g.MainLoop() if err != nil && err != errTerminateMainloop { - ui.g.Close() + if ui.g != nil { + ui.g.Close() + } ui.gError <- err } @@ -79,14 +84,16 @@ func initGui() { } func layout(g *gocui.Gui) error { - //maxX, maxY := g.Size() - g.Cursor = false if err := ui.activeWindow.layout(g); err != nil { return err } + if err := ui.errorPopup.layout(g); err != nil { + return err + } + return nil } @@ -100,6 +107,10 @@ func keybindings(g *gocui.Gui) error { return err } + if err := ui.errorPopup.keybindings(g); err != nil { + return err + } + return nil } @@ -118,20 +129,21 @@ func newBugWithEditor(g *gocui.Gui, v *gocui.View) error { // instance's mainLoop. This error is then filtered. ui.g.Close() + ui.g = nil title, message, err := input.BugCreateEditorInput(ui.cache.Repository(), "", "") - if err == input.ErrEmptyTitle { - // TODO: display proper error - return err - } - if err != nil { + if err != nil && err != input.ErrEmptyTitle { return err } - _, err = ui.cache.NewBug(title, message) - if err != nil { - return err + if err == input.ErrEmptyTitle { + ui.errorPopup.err = err.Error() + } else { + _, err = ui.cache.NewBug(title, message) + if err != nil { + return err + } } initGui() |