aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2018-08-12 02:42:03 +0200
committerMichael Muré <batolettre@gmail.com>2018-08-12 02:42:03 +0200
commit53a3d5e11355ec6bed2e27bc26459a50e435b643 (patch)
tree36fc783081f21bed66398e3f93b6c0c1b6bd1275
parentf51cc4a33fcac3ebf2024e0c6cb97cb809f8db71 (diff)
downloadgit-bug-53a3d5e11355ec6bed2e27bc26459a50e435b643.tar.gz
termui: add and remove labels
-rw-r--r--termui/error_popup.go5
-rw-r--r--termui/input_popup.go96
-rw-r--r--termui/show_bug.go75
-rw-r--r--termui/termui.go16
4 files changed, 186 insertions, 6 deletions
diff --git a/termui/error_popup.go b/termui/error_popup.go
index 855bd05d..f8f53feb 100644
--- a/termui/error_popup.go
+++ b/termui/error_popup.go
@@ -2,6 +2,7 @@ package termui
import (
"fmt"
+
"github.com/MichaelMure/git-bug/util"
"github.com/jroimartin/gocui"
)
@@ -38,7 +39,7 @@ func (ep *errorPopup) layout(g *gocui.Gui) error {
width := minInt(30, maxX)
wrapped, nblines := util.WordWrap(ep.message, width-2)
- height := minInt(nblines+2, maxY)
+ height := minInt(nblines+1, maxY)
x0 := (maxX - width) / 2
y0 := (maxY - height) / 2
@@ -66,6 +67,6 @@ func (ep *errorPopup) close(g *gocui.Gui, v *gocui.View) error {
return g.DeleteView(errorPopupView)
}
-func (ep *errorPopup) activate(message string) {
+func (ep *errorPopup) Activate(message string) {
ep.message = message
}
diff --git a/termui/input_popup.go b/termui/input_popup.go
new file mode 100644
index 00000000..00e602e5
--- /dev/null
+++ b/termui/input_popup.go
@@ -0,0 +1,96 @@
+package termui
+
+import (
+ "io/ioutil"
+
+ "github.com/jroimartin/gocui"
+)
+
+const inputPopupView = "inputPopupView"
+
+type inputPopup struct {
+ active bool
+ title string
+ c chan string
+}
+
+func newInputPopup() *inputPopup {
+ return &inputPopup{}
+}
+
+func (ip *inputPopup) keybindings(g *gocui.Gui) error {
+ // Close
+ if err := g.SetKeybinding(inputPopupView, gocui.KeyEsc, gocui.ModNone, ip.close); err != nil {
+ return err
+ }
+
+ // Validate
+ if err := g.SetKeybinding(inputPopupView, gocui.KeyEnter, gocui.ModNone, ip.validate); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (ip *inputPopup) layout(g *gocui.Gui) error {
+ if !ip.active {
+ return nil
+ }
+
+ maxX, maxY := g.Size()
+
+ width := minInt(30, maxX)
+ height := 2
+ x0 := (maxX - width) / 2
+ y0 := (maxY - height) / 2
+
+ v, err := g.SetView(inputPopupView, x0, y0, x0+width, y0+height)
+ if err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+
+ v.Frame = true
+ v.Title = ip.title
+ v.Editable = true
+ }
+
+ if _, err := g.SetCurrentView(inputPopupView); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (ip *inputPopup) close(g *gocui.Gui, v *gocui.View) error {
+ ip.title = ""
+ ip.active = false
+ return g.DeleteView(inputPopupView)
+}
+
+func (ip *inputPopup) validate(g *gocui.Gui, v *gocui.View) error {
+ ip.title = ""
+
+ content, err := ioutil.ReadAll(v)
+ if err != nil {
+ return err
+ }
+
+ ip.title = ""
+ ip.active = false
+ err = g.DeleteView(inputPopupView)
+ if err != nil {
+ return err
+ }
+
+ ip.c <- string(content)
+
+ return nil
+}
+
+func (ip *inputPopup) Activate(title string) <-chan string {
+ ip.title = title
+ ip.active = true
+ ip.c = make(chan string)
+ return ip.c
+}
diff --git a/termui/show_bug.go b/termui/show_bug.go
index 040a7b5f..ab0fd472 100644
--- a/termui/show_bug.go
+++ b/termui/show_bug.go
@@ -90,8 +90,15 @@ func (sb *showBug) layout(g *gocui.Gui) error {
sb.childViews = append(sb.childViews, showBugInstructionView)
v.Frame = false
v.BgColor = gocui.ColorBlue
+ }
+
+ v.Clear()
+ fmt.Fprintf(v, "[q] Save and return [←,h] Left [↓,j] Down [↑,k] Up [→,l] Right ")
- fmt.Fprintf(v, "[q] Save and return [c] Comment [t] Change title [↓,j] Down [↑,k] Up")
+ if sb.isOnSide {
+ fmt.Fprint(v, "[a] Add label [r] Remove label")
+ } else {
+ fmt.Fprint(v, "[c] Comment [t] Change title")
}
_, err = g.SetViewOnTop(showBugInstructionView)
@@ -170,6 +177,14 @@ func (sb *showBug) keybindings(g *gocui.Gui) error {
}
// Labels
+ if err := g.SetKeybinding(showBugView, 'a', gocui.ModNone,
+ sb.addLabel); err != nil {
+ return err
+ }
+ if err := g.SetKeybinding(showBugView, 'r', gocui.ModNone,
+ sb.removeLabel); err != nil {
+ return err
+ }
return nil
}
@@ -563,3 +578,61 @@ func (sb *showBug) comment(g *gocui.Gui, v *gocui.View) error {
func (sb *showBug) setTitle(g *gocui.Gui, v *gocui.View) error {
return setTitleWithEditor(sb.bug)
}
+
+func (sb *showBug) addLabel(g *gocui.Gui, v *gocui.View) error {
+ c := ui.inputPopup.Activate("Add labels")
+
+ go func() {
+ input := <-c
+
+ labels := strings.FieldsFunc(input, func(r rune) bool {
+ return r == ' ' || r == ','
+ })
+
+ err := sb.bug.ChangeLabels(trimLabels(labels), nil)
+ if err != nil {
+ ui.errorPopup.Activate(err.Error())
+ }
+
+ g.Update(func(gui *gocui.Gui) error {
+ return nil
+ })
+ }()
+
+ return nil
+}
+
+func (sb *showBug) removeLabel(g *gocui.Gui, v *gocui.View) error {
+ c := ui.inputPopup.Activate("Remove labels")
+
+ go func() {
+ input := <-c
+
+ labels := strings.FieldsFunc(input, func(r rune) bool {
+ return r == ' ' || r == ','
+ })
+
+ err := sb.bug.ChangeLabels(nil, trimLabels(labels))
+ if err != nil {
+ ui.errorPopup.Activate(err.Error())
+ }
+
+ g.Update(func(gui *gocui.Gui) error {
+ return nil
+ })
+ }()
+
+ return nil
+}
+
+func trimLabels(labels []string) []string {
+ var result []string
+
+ for _, label := range labels {
+ trimmed := strings.TrimSpace(label)
+ if len(trimmed) > 0 {
+ result = append(result, trimmed)
+ }
+ }
+ return result
+}
diff --git a/termui/termui.go b/termui/termui.go
index d2585c4b..535842e4 100644
--- a/termui/termui.go
+++ b/termui/termui.go
@@ -20,6 +20,7 @@ type termUI struct {
bugTable *bugTable
showBug *showBug
errorPopup *errorPopup
+ inputPopup *inputPopup
}
func (tui *termUI) activateWindow(window window) error {
@@ -49,6 +50,7 @@ func Run(repo repository.Repo) error {
bugTable: newBugTable(c),
showBug: newShowBug(c),
errorPopup: newErrorPopup(),
+ inputPopup: newInputPopup(),
}
ui.activeWindow = ui.bugTable
@@ -108,6 +110,10 @@ func layout(g *gocui.Gui) error {
return err
}
+ if err := ui.inputPopup.layout(g); err != nil {
+ return err
+ }
+
return nil
}
@@ -129,6 +135,10 @@ func keybindings(g *gocui.Gui) error {
return err
}
+ if err := ui.inputPopup.keybindings(g); err != nil {
+ return err
+ }
+
return nil
}
@@ -156,7 +166,7 @@ func newBugWithEditor(repo cache.RepoCacher) error {
}
if err == input.ErrEmptyTitle {
- ui.errorPopup.activate("Empty title, aborting.")
+ ui.errorPopup.Activate("Empty title, aborting.")
} else {
_, err := repo.NewBug(title, message)
if err != nil {
@@ -189,7 +199,7 @@ func addCommentWithEditor(bug cache.BugCacher) error {
}
if err == input.ErrEmptyMessage {
- ui.errorPopup.activate("Empty message, aborting.")
+ ui.errorPopup.Activate("Empty message, aborting.")
} else {
err := bug.AddComment(message)
if err != nil {
@@ -222,7 +232,7 @@ func setTitleWithEditor(bug cache.BugCacher) error {
}
if err == input.ErrEmptyTitle {
- ui.errorPopup.activate("Empty title, aborting.")
+ ui.errorPopup.Activate("Empty title, aborting.")
} else {
err := bug.SetTitle(title)
if err != nil {