aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cache/cache.go76
-rw-r--r--graphql/resolvers/mutation.go12
-rw-r--r--input/input.go35
-rw-r--r--termui/bug_table.go39
-rw-r--r--termui/show_bug.go38
-rw-r--r--termui/termui.go72
6 files changed, 187 insertions, 85 deletions
diff --git a/cache/cache.go b/cache/cache.go
index cbd57802..d2595723 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -15,10 +15,6 @@ type Cacher interface {
ResolveRepo(ref string) (RepoCacher, error)
DefaultRepo() (RepoCacher, error)
-
- // Shortcut to resolve on the default repo for convenience
- DefaultResolveBug(id string) (BugCacher, error)
- DefaultResolveBugPrefix(prefix string) (BugCacher, error)
}
type RepoCacher interface {
@@ -37,13 +33,13 @@ type BugCacher interface {
ClearSnapshot()
// Mutations
- AddComment(message string) (BugCacher, error)
- ChangeLabels(added []string, removed []string) (BugCacher, error)
- Open() (BugCacher, error)
- Close() (BugCacher, error)
- SetTitle(title string) (BugCacher, error)
+ AddComment(message string) error
+ ChangeLabels(added []string, removed []string) error
+ Open() error
+ Close() error
+ SetTitle(title string) error
- Commit() (BugCacher, error)
+ Commit() error
}
// Cacher ------------------------
@@ -86,26 +82,6 @@ func (c *RootCache) ResolveRepo(ref string) (RepoCacher, error) {
return r, nil
}
-func (c *RootCache) DefaultResolveBug(id string) (BugCacher, error) {
- repo, err := c.DefaultRepo()
-
- if err != nil {
- return nil, err
- }
-
- return repo.ResolveBug(id)
-}
-
-func (c *RootCache) DefaultResolveBugPrefix(prefix string) (BugCacher, error) {
- repo, err := c.DefaultRepo()
-
- if err != nil {
- return nil, err
- }
-
- return repo.ResolveBugPrefix(prefix)
-}
-
// Repo ------------------------
type RepoCache struct {
@@ -231,10 +207,10 @@ func (c *BugCache) ClearSnapshot() {
c.snap = nil
}
-func (c *BugCache) AddComment(message string) (BugCacher, error) {
+func (c *BugCache) AddComment(message string) error {
author, err := bug.GetUser(c.repo)
if err != nil {
- return nil, err
+ return err
}
operations.Comment(c.bug, author, message)
@@ -242,30 +218,30 @@ func (c *BugCache) AddComment(message string) (BugCacher, error) {
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
- return c, nil
+ return nil
}
-func (c *BugCache) ChangeLabels(added []string, removed []string) (BugCacher, error) {
+func (c *BugCache) ChangeLabels(added []string, removed []string) error {
author, err := bug.GetUser(c.repo)
if err != nil {
- return nil, err
+ return err
}
err = operations.ChangeLabels(nil, c.bug, author, added, removed)
if err != nil {
- return nil, err
+ return err
}
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
- return c, nil
+ return nil
}
-func (c *BugCache) Open() (BugCacher, error) {
+func (c *BugCache) Open() error {
author, err := bug.GetUser(c.repo)
if err != nil {
- return nil, err
+ return err
}
operations.Open(c.bug, author)
@@ -273,13 +249,13 @@ func (c *BugCache) Open() (BugCacher, error) {
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
- return c, nil
+ return nil
}
-func (c *BugCache) Close() (BugCacher, error) {
+func (c *BugCache) Close() error {
author, err := bug.GetUser(c.repo)
if err != nil {
- return nil, err
+ return err
}
operations.Close(c.bug, author)
@@ -287,13 +263,13 @@ func (c *BugCache) Close() (BugCacher, error) {
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
- return c, nil
+ return nil
}
-func (c *BugCache) SetTitle(title string) (BugCacher, error) {
+func (c *BugCache) SetTitle(title string) error {
author, err := bug.GetUser(c.repo)
if err != nil {
- return nil, err
+ return err
}
operations.SetTitle(c.bug, author, title)
@@ -301,13 +277,9 @@ func (c *BugCache) SetTitle(title string) (BugCacher, error) {
// TODO: perf --> the snapshot could simply be updated with the new op
c.ClearSnapshot()
- return c, nil
+ return nil
}
-func (c *BugCache) Commit() (BugCacher, error) {
- err := c.bug.Commit(c.repo)
- if err != nil {
- return nil, err
- }
- return c, nil
+func (c *BugCache) Commit() error {
+ return c.bug.Commit(c.repo)
}
diff --git a/graphql/resolvers/mutation.go b/graphql/resolvers/mutation.go
index 2960368a..a85459f2 100644
--- a/graphql/resolvers/mutation.go
+++ b/graphql/resolvers/mutation.go
@@ -46,7 +46,7 @@ func (r mutationResolver) Commit(ctx context.Context, repoRef *string, prefix st
return bug.Snapshot{}, err
}
- b, err = b.Commit()
+ err = b.Commit()
if err != nil {
return bug.Snapshot{}, err
}
@@ -67,7 +67,7 @@ func (r mutationResolver) AddComment(ctx context.Context, repoRef *string, prefi
return bug.Snapshot{}, err
}
- b, err = b.AddComment(message)
+ err = b.AddComment(message)
if err != nil {
return bug.Snapshot{}, err
}
@@ -88,7 +88,7 @@ func (r mutationResolver) ChangeLabels(ctx context.Context, repoRef *string, pre
return bug.Snapshot{}, err
}
- b, err = b.ChangeLabels(added, removed)
+ err = b.ChangeLabels(added, removed)
if err != nil {
return bug.Snapshot{}, err
}
@@ -109,7 +109,7 @@ func (r mutationResolver) Open(ctx context.Context, repoRef *string, prefix stri
return bug.Snapshot{}, err
}
- b, err = b.Open()
+ err = b.Open()
if err != nil {
return bug.Snapshot{}, err
}
@@ -130,7 +130,7 @@ func (r mutationResolver) Close(ctx context.Context, repoRef *string, prefix str
return bug.Snapshot{}, err
}
- b, err = b.Close()
+ err = b.Close()
if err != nil {
return bug.Snapshot{}, err
}
@@ -151,7 +151,7 @@ func (r mutationResolver) SetTitle(ctx context.Context, repoRef *string, prefix
return bug.Snapshot{}, err
}
- b, err = b.SetTitle(title)
+ err = b.SetTitle(title)
if err != nil {
return bug.Snapshot{}, err
}
diff --git a/input/input.go b/input/input.go
index 300348af..530106e2 100644
--- a/input/input.go
+++ b/input/input.go
@@ -102,6 +102,41 @@ func BugCommentEditorInput(repo repository.Repo) (string, error) {
return message, nil
}
+const bugTitleTemplate = `
+
+# Please enter the new title. Only one line will used.
+# Lines starting with '#' will be ignored, and an empty title aborts the operation.
+`
+
+func BugTitleEditorInput(repo repository.Repo) (string, error) {
+ raw, err := LaunchEditorWithTemplate(repo, messageFilename, bugTitleTemplate)
+
+ if err != nil {
+ return "", err
+ }
+
+ lines := strings.Split(raw, "\n")
+
+ var title string
+ for _, line := range lines {
+ if strings.HasPrefix(line, "#") {
+ continue
+ }
+ trimmed := strings.TrimSpace(line)
+ if trimmed == "" {
+ continue
+ }
+ title = trimmed
+ break
+ }
+
+ if title == "" {
+ return "", ErrEmptyTitle
+ }
+
+ return title, nil
+}
+
func LaunchEditorWithTemplate(repo repository.Repo, fileName string, template string) (string, error) {
path := fmt.Sprintf("%s/.git/%s", repo.GetPath(), fileName)
diff --git a/termui/bug_table.go b/termui/bug_table.go
index ae67c289..55b451af 100644
--- a/termui/bug_table.go
+++ b/termui/bug_table.go
@@ -14,16 +14,16 @@ const bugTableFooterView = "bugTableFooterView"
const bugTableInstructionView = "bugTableInstructionView"
type bugTable struct {
- cache cache.RepoCacher
+ repo cache.RepoCacher
allIds []string
- bugs []*bug.Snapshot
+ bugs []cache.BugCacher
pageCursor int
selectCursor int
}
func newBugTable(cache cache.RepoCacher) *bugTable {
return &bugTable{
- cache: cache,
+ repo: cache,
pageCursor: 0,
selectCursor: 0,
}
@@ -165,7 +165,7 @@ func (bt *bugTable) keybindings(g *gocui.Gui) error {
// New bug
if err := g.SetKeybinding(bugTableView, 'n', gocui.ModNone,
- newBugWithEditor); err != nil {
+ bt.newBug); err != nil {
return err
}
@@ -195,7 +195,7 @@ func (bt *bugTable) disable(g *gocui.Gui) error {
}
func (bt *bugTable) paginate(max int) error {
- allIds, err := bt.cache.AllBugIds()
+ allIds, err := bt.repo.AllBugIds()
if err != nil {
return err
}
@@ -213,22 +213,22 @@ func (bt *bugTable) doPaginate(allIds []string, max int) error {
nb := minInt(len(allIds)-bt.pageCursor, max)
if nb < 0 {
- bt.bugs = []*bug.Snapshot{}
+ bt.bugs = []cache.BugCacher{}
return nil
}
// slice the data
ids := allIds[bt.pageCursor : bt.pageCursor+nb]
- bt.bugs = make([]*bug.Snapshot, len(ids))
+ bt.bugs = make([]cache.BugCacher, len(ids))
for i, id := range ids {
- b, err := bt.cache.ResolveBug(id)
+ b, err := bt.repo.ResolveBug(id)
if err != nil {
return err
}
- bt.bugs[i] = b.Snapshot()
+ bt.bugs[i] = b
}
return nil
@@ -259,16 +259,17 @@ func (bt *bugTable) render(v *gocui.View, maxX int) {
for _, b := range bt.bugs {
person := bug.Person{}
- if len(b.Comments) > 0 {
- create := b.Comments[0]
+ snap := b.Snapshot()
+ if len(snap.Comments) > 0 {
+ create := snap.Comments[0]
person = create.Author
}
- id := util.LeftPaddedString(b.HumanId(), columnWidths["id"], 2)
- status := util.LeftPaddedString(b.Status.String(), columnWidths["status"], 2)
- title := util.LeftPaddedString(b.Title, columnWidths["title"], 2)
+ id := util.LeftPaddedString(snap.HumanId(), columnWidths["id"], 2)
+ status := util.LeftPaddedString(snap.Status.String(), columnWidths["status"], 2)
+ title := util.LeftPaddedString(snap.Title, columnWidths["title"], 2)
author := util.LeftPaddedString(person.Name, columnWidths["author"], 2)
- summary := util.LeftPaddedString(b.Summary(), columnWidths["summary"], 2)
+ summary := util.LeftPaddedString(snap.Summary(), columnWidths["summary"], 2)
fmt.Fprintf(v, "%s %s %s %s %s\n", id, status, title, author, summary)
}
@@ -330,7 +331,7 @@ func (bt *bugTable) cursorClamp(v *gocui.View) error {
func (bt *bugTable) nextPage(g *gocui.Gui, v *gocui.View) error {
_, max := v.Size()
- allIds, err := bt.cache.AllBugIds()
+ allIds, err := bt.repo.AllBugIds()
if err != nil {
return err
}
@@ -348,7 +349,7 @@ func (bt *bugTable) nextPage(g *gocui.Gui, v *gocui.View) error {
func (bt *bugTable) previousPage(g *gocui.Gui, v *gocui.View) error {
_, max := v.Size()
- allIds, err := bt.cache.AllBugIds()
+ allIds, err := bt.repo.AllBugIds()
if err != nil {
return err
}
@@ -360,6 +361,10 @@ func (bt *bugTable) previousPage(g *gocui.Gui, v *gocui.View) error {
return bt.doPaginate(allIds, max)
}
+func (bt *bugTable) newBug(g *gocui.Gui, v *gocui.View) error {
+ return newBugWithEditor(bt.repo)
+}
+
func (bt *bugTable) openBug(g *gocui.Gui, v *gocui.View) error {
_, y := v.Cursor()
ui.showBug.bug = bt.bugs[bt.pageCursor+y]
diff --git a/termui/show_bug.go b/termui/show_bug.go
index 9d1f5b76..34c7a922 100644
--- a/termui/show_bug.go
+++ b/termui/show_bug.go
@@ -2,7 +2,6 @@ package termui
import (
"fmt"
- "github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/bug/operations"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/util"
@@ -17,7 +16,7 @@ const timeLayout = "Jan _2 2006"
type showBug struct {
cache cache.RepoCacher
- bug *bug.Snapshot
+ bug cache.BugCacher
}
func newShowBug(cache cache.RepoCacher) *showBug {
@@ -65,7 +64,7 @@ func (sb *showBug) layout(g *gocui.Gui) error {
v.Frame = false
v.BgColor = gocui.ColorBlue
- fmt.Fprintf(v, "[q] Return")
+ fmt.Fprintf(v, "[q] Return [c] Add comment [t] Change title")
}
_, err = g.SetCurrentView(showBugView)
@@ -78,6 +77,7 @@ func (sb *showBug) keybindings(g *gocui.Gui) error {
return err
}
+ // Scrolling
if err := g.SetKeybinding(showBugView, gocui.KeyPgup, gocui.ModNone,
sb.scrollUp); err != nil {
return err
@@ -87,6 +87,20 @@ func (sb *showBug) keybindings(g *gocui.Gui) error {
return err
}
+ // Comment
+ if err := g.SetKeybinding(showBugView, 'c', gocui.ModNone,
+ sb.comment); err != nil {
+ return err
+ }
+
+ // Title
+ if err := g.SetKeybinding(showBugView, 't', gocui.ModNone,
+ sb.title); err != nil {
+ return err
+ }
+
+ // Labels
+
return nil
}
@@ -105,15 +119,16 @@ func (sb *showBug) disable(g *gocui.Gui) error {
func (sb *showBug) renderMain(v *gocui.View) {
maxX, _ := v.Size()
+ snap := sb.bug.Snapshot()
- header1 := fmt.Sprintf("[%s] %s", sb.bug.HumanId(), sb.bug.Title)
+ header1 := fmt.Sprintf("[%s] %s", snap.HumanId(), snap.Title)
fmt.Fprintf(v, util.LeftPaddedString(header1, maxX, 2)+"\n\n")
header2 := fmt.Sprintf("[%s] %s opened this bug on %s",
- sb.bug.Status, sb.bug.Author.Name, sb.bug.CreatedAt.Format(timeLayout))
+ snap.Status, snap.Author.Name, snap.CreatedAt.Format(timeLayout))
fmt.Fprintf(v, util.LeftPaddedString(header2, maxX, 2)+"\n\n")
- for _, op := range sb.bug.Operations {
+ for _, op := range snap.Operations {
switch op.(type) {
case operations.CreateOperation:
@@ -133,11 +148,12 @@ func (sb *showBug) renderMain(v *gocui.View) {
func (sb *showBug) renderSidebar(v *gocui.View) {
maxX, _ := v.Size()
+ snap := sb.bug.Snapshot()
title := util.LeftPaddedString("LABEL", maxX, 2)
fmt.Fprintf(v, title+"\n\n")
- for _, label := range sb.bug.Labels {
+ for _, label := range snap.Labels {
fmt.Fprintf(v, util.LeftPaddedString(label.String(), maxX, 2))
fmt.Fprintln(v)
}
@@ -156,3 +172,11 @@ func (sb *showBug) scrollUp(g *gocui.Gui, v *gocui.View) error {
func (sb *showBug) scrollDown(g *gocui.Gui, v *gocui.View) error {
return nil
}
+
+func (sb *showBug) comment(g *gocui.Gui, v *gocui.View) error {
+ return addCommentWithEditor(sb.bug)
+}
+
+func (sb *showBug) title(g *gocui.Gui, v *gocui.View) error {
+ return setTitleWithEditor(sb.bug)
+}
diff --git a/termui/termui.go b/termui/termui.go
index a5da4bda..2e109c3f 100644
--- a/termui/termui.go
+++ b/termui/termui.go
@@ -136,9 +136,9 @@ func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
-func newBugWithEditor(g *gocui.Gui, v *gocui.View) error {
+func newBugWithEditor(repo cache.RepoCacher) error {
// This is somewhat hacky.
- // As there is no way to pause gocui, run the editor, restart gocui,
+ // As there is no way to pause gocui, run the editor and restart gocui,
// we have to stop it entirely and start a new one later.
//
// - an error channel is used to route the returned error of this new
@@ -158,7 +158,73 @@ func newBugWithEditor(g *gocui.Gui, v *gocui.View) error {
if err == input.ErrEmptyTitle {
ui.errorPopup.activate("Empty title, aborting.")
} else {
- _, err = ui.cache.NewBug(title, message)
+ _, err := repo.NewBug(title, message)
+ if err != nil {
+ return err
+ }
+ }
+
+ initGui()
+
+ return errTerminateMainloop
+}
+
+func addCommentWithEditor(bug cache.BugCacher) error {
+ // This is somewhat hacky.
+ // As there is no way to pause gocui, run the editor and restart gocui,
+ // we have to stop it entirely and start a new one later.
+ //
+ // - an error channel is used to route the returned error of this new
+ // instance into the original launch function
+ // - a custom error (errTerminateMainloop) is used to terminate the original
+ // instance's mainLoop. This error is then filtered.
+
+ ui.g.Close()
+ ui.g = nil
+
+ message, err := input.BugCommentEditorInput(ui.cache.Repository())
+
+ if err != nil && err != input.ErrEmptyMessage {
+ return err
+ }
+
+ if err == input.ErrEmptyMessage {
+ ui.errorPopup.activate("Empty message, aborting.")
+ } else {
+ err := bug.AddComment(message)
+ if err != nil {
+ return err
+ }
+ }
+
+ initGui()
+
+ return errTerminateMainloop
+}
+
+func setTitleWithEditor(bug cache.BugCacher) error {
+ // This is somewhat hacky.
+ // As there is no way to pause gocui, run the editor and restart gocui,
+ // we have to stop it entirely and start a new one later.
+ //
+ // - an error channel is used to route the returned error of this new
+ // instance into the original launch function
+ // - a custom error (errTerminateMainloop) is used to terminate the original
+ // instance's mainLoop. This error is then filtered.
+
+ ui.g.Close()
+ ui.g = nil
+
+ title, err := input.BugTitleEditorInput(ui.cache.Repository())
+
+ if err != nil && err != input.ErrEmptyTitle {
+ return err
+ }
+
+ if err == input.ErrEmptyTitle {
+ ui.errorPopup.activate("Empty title, aborting.")
+ } else {
+ err := bug.SetTitle(title)
if err != nil {
return err
}