aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-07-31 22:19:11 +0200
committerMichael Muré <batolettre@gmail.com>2018-07-31 22:19:11 +0200
commit6b012b1e485d369d82cb410a1652f53a752bf21c (patch)
treeb8f882bda85bf8b072fce3b6830f91cbf0a01e1c
parent20bd25f332a5ca04ee80a8a4965f56ef3e7cdbf2 (diff)
downloadgit-bug-6b012b1e485d369d82cb410a1652f53a752bf21c.tar.gz
termui: add a reusable error popup, use it for badly formated bug creation
-rw-r--r--termui/bug_table.go40
-rw-r--r--termui/error_popup.go93
-rw-r--r--termui/termui.go42
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()