show_bug.go

  1package termui
  2
  3import (
  4	"fmt"
  5	"github.com/MichaelMure/git-bug/bug/operations"
  6	"github.com/MichaelMure/git-bug/cache"
  7	"github.com/MichaelMure/git-bug/util"
  8	"github.com/jroimartin/gocui"
  9)
 10
 11const showBugView = "showBugView"
 12const showBugSidebarView = "showBugSidebarView"
 13const showBugInstructionView = "showBugInstructionView"
 14
 15const timeLayout = "Jan _2 2006"
 16
 17type showBug struct {
 18	cache      cache.RepoCacher
 19	bug        cache.BugCacher
 20	childViews []string
 21}
 22
 23func newShowBug(cache cache.RepoCacher) *showBug {
 24	return &showBug{
 25		cache: cache,
 26	}
 27}
 28
 29func (sb *showBug) layout(g *gocui.Gui) error {
 30	maxX, maxY := g.Size()
 31
 32	v, err := g.SetView(showBugView, 2, 0, maxX*2/3, maxY-2)
 33
 34	if err != nil {
 35		if err != gocui.ErrUnknownView {
 36			return err
 37		}
 38
 39		sb.childViews = append(sb.childViews, showBugView)
 40		v.Frame = false
 41	}
 42
 43	v.Clear()
 44	err = sb.renderMain(g, v)
 45	if err != nil {
 46		return err
 47	}
 48
 49	v, err = g.SetView(showBugSidebarView, maxX*2/3+1, 0, maxX-1, maxY-2)
 50
 51	if err != nil {
 52		if err != gocui.ErrUnknownView {
 53			return err
 54		}
 55
 56		sb.childViews = append(sb.childViews, showBugSidebarView)
 57		v.Frame = true
 58	}
 59
 60	v.Clear()
 61	sb.renderSidebar(v)
 62
 63	v, err = g.SetView(showBugInstructionView, -1, maxY-2, maxX, maxY)
 64
 65	if err != nil {
 66		if err != gocui.ErrUnknownView {
 67			return err
 68		}
 69
 70		sb.childViews = append(sb.childViews, showBugInstructionView)
 71		v.Frame = false
 72		v.BgColor = gocui.ColorBlue
 73
 74		fmt.Fprintf(v, "[q] Return [c] Comment [t] Change title")
 75	}
 76
 77	_, err = g.SetCurrentView(showBugView)
 78	return err
 79}
 80
 81func (sb *showBug) keybindings(g *gocui.Gui) error {
 82	// Return
 83	if err := g.SetKeybinding(showBugView, 'q', gocui.ModNone, sb.back); err != nil {
 84		return err
 85	}
 86
 87	// Scrolling
 88	if err := g.SetKeybinding(showBugView, gocui.KeyPgup, gocui.ModNone,
 89		sb.scrollUp); err != nil {
 90		return err
 91	}
 92	if err := g.SetKeybinding(showBugView, gocui.KeyPgdn, gocui.ModNone,
 93		sb.scrollDown); err != nil {
 94		return err
 95	}
 96
 97	// Comment
 98	if err := g.SetKeybinding(showBugView, 'c', gocui.ModNone,
 99		sb.comment); err != nil {
100		return err
101	}
102
103	// Title
104	if err := g.SetKeybinding(showBugView, 't', gocui.ModNone,
105		sb.title); err != nil {
106		return err
107	}
108
109	// Labels
110
111	return nil
112}
113
114func (sb *showBug) disable(g *gocui.Gui) error {
115	for _, view := range sb.childViews {
116		if err := g.DeleteView(view); err != nil {
117			return err
118		}
119	}
120	return nil
121}
122
123func (sb *showBug) renderMain(g *gocui.Gui, mainView *gocui.View) error {
124	maxX, _ := mainView.Size()
125	x0, y0, _, _, _ := g.ViewPosition(mainView.Name())
126	snap := sb.bug.Snapshot()
127
128	v, err := g.SetView("showBugHeader", x0, y0, maxX+1, y0+4)
129
130	if err != nil {
131		if err != gocui.ErrUnknownView {
132			return err
133		}
134
135		sb.childViews = append(sb.childViews, "showBugHeader")
136		v.Frame = false
137	}
138	y0 += 4
139
140	v.Clear()
141	header1 := fmt.Sprintf("[%s] %s", snap.HumanId(), snap.Title)
142	fmt.Fprintf(v, util.LeftPaddedString(header1, maxX, 0)+"\n\n")
143
144	header2 := fmt.Sprintf("[%s] %s opened this bug on %s",
145		snap.Status, snap.Author.Name, snap.CreatedAt.Format(timeLayout))
146	fmt.Fprintf(v, util.LeftPaddedString(header2, maxX, 0))
147
148	for i, op := range snap.Operations {
149		viewName := fmt.Sprintf("op%d", i)
150
151		switch op.(type) {
152
153		case operations.CreateOperation:
154			create := op.(operations.CreateOperation)
155			content, lines := util.TextWrap(create.Message, maxX)
156
157			v, err := sb.createOpView(g, viewName, x0, y0, maxX, lines)
158			if err != nil {
159				return err
160			}
161			fmt.Fprint(v, content)
162			y0 += lines + 2
163
164		case operations.AddCommentOperation:
165			comment := op.(operations.AddCommentOperation)
166
167			header := fmt.Sprintf("%s commented on %s",
168				comment.Author.Name, comment.Time().Format(timeLayout))
169			header = util.LeftPaddedString(header, maxX, 6)
170			message, lines := util.TextWrap(comment.Message, maxX)
171
172			v, err := sb.createOpView(g, viewName, x0, y0, maxX, lines+2)
173			if err != nil {
174				return err
175			}
176			fmt.Fprint(v, header, "\n\n", message)
177			y0 += lines + 3
178		}
179	}
180
181	return nil
182
183}
184
185func (sb *showBug) createOpView(g *gocui.Gui, name string, x0 int, y0 int, maxX int, height int) (*gocui.View, error) {
186	v, err := g.SetView(name, x0, y0, maxX+3, y0+height+1)
187
188	if err != nil {
189		if err != gocui.ErrUnknownView {
190			return nil, err
191		}
192
193		sb.childViews = append(sb.childViews, name)
194		v.Frame = false
195	}
196
197	v.Clear()
198
199	return v, nil
200}
201
202func (sb *showBug) renderSidebar(v *gocui.View) {
203	maxX, _ := v.Size()
204	snap := sb.bug.Snapshot()
205
206	title := util.LeftPaddedString("LABEL", maxX, 2)
207	fmt.Fprintf(v, title+"\n\n")
208
209	for _, label := range snap.Labels {
210		fmt.Fprintf(v, util.LeftPaddedString(label.String(), maxX, 2))
211		fmt.Fprintln(v)
212	}
213}
214
215func (sb *showBug) back(g *gocui.Gui, v *gocui.View) error {
216	ui.activateWindow(ui.bugTable)
217	return nil
218}
219
220func (sb *showBug) scrollUp(g *gocui.Gui, v *gocui.View) error {
221	return nil
222}
223
224func (sb *showBug) scrollDown(g *gocui.Gui, v *gocui.View) error {
225	return nil
226}
227
228func (sb *showBug) comment(g *gocui.Gui, v *gocui.View) error {
229	return addCommentWithEditor(sb.bug)
230}
231
232func (sb *showBug) title(g *gocui.Gui, v *gocui.View) error {
233	return setTitleWithEditor(sb.bug)
234}