From 07462303abbd88af9f29c5ab0d650eb059ae7675 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 8 Sep 2019 11:46:09 +1000 Subject: bump gocui --- go.mod | 2 +- go.sum | 7 +- vendor/github.com/jesseduffield/gocui/gui.go | 139 +++++++++++++++++---- .../github.com/jesseduffield/gocui/gui_notwin.go | 61 +++++++++ vendor/github.com/jesseduffield/gocui/gui_win.go | 10 ++ vendor/github.com/jesseduffield/gocui/view.go | 41 +++++- vendor/modules.txt | 2 +- 7 files changed, 230 insertions(+), 32 deletions(-) create mode 100644 vendor/github.com/jesseduffield/gocui/gui_notwin.go create mode 100644 vendor/github.com/jesseduffield/gocui/gui_win.go diff --git a/go.mod b/go.mod index 4ab3ae48a..eabf54077 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63 - github.com/jesseduffield/gocui v0.0.0-20190526022629-625842035f05 + github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54 github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406 github.com/jesseduffield/rollrus v0.0.0-20190701125922-dd028cb0bfd7 github.com/jesseduffield/termbox-go v0.0.0-20180919093808-1e272ff78dcb // indirect diff --git a/go.sum b/go.sum index 3b667ee61..ca84aaaa9 100644 --- a/go.sum +++ b/go.sum @@ -38,7 +38,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186 h1:URgjUo+bs1KwatoNbwG0uCO4dHN4r1jsp4a5AGgHRjo= github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001 h1:qC+3MHkvfCXb1cA9YDpWZ7np8tPOXZceLrW+xyqOgmk= +github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001 h1:MFPzqpPED05pFyGjNPJEC2sXM6EHTzFyvX+0s0JoZ48= github.com/hashicorp/go-getter v0.0.0-20180809191950-4bda8fa99001/go.mod h1:6rdJFnhkXnzGOJbvkrdv4t9nLwKcVA+tmbQeUlkIzrU= github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc h1:wAa9fGALVHfjYxZuXRnmuJG2CnwRpJYOTvY6YdErAh0= github.com/hashicorp/go-safetemp v0.0.0-20180326211150-b1a1dbde6fdc/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= @@ -50,10 +50,12 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63 h1:tbm85YuPi3d1LFAUr6yZyzZ4vR96ygV98rezZZ+ywbg= +github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63 h1:Nrr/yUxNjXWYK0B3IqcFlYh1ICnesJDB4ogcfOVc5Ns= github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63/go.mod h1:fNqjRf+4XnTo2PrGN1JRb79b/BeoHwP4lU00f39SQY0= github.com/jesseduffield/gocui v0.0.0-20190526022629-625842035f05 h1:SMWr70VU5rthPPUtWgYdHvqLLabhvWgvJ3JpkytLV1c= github.com/jesseduffield/gocui v0.0.0-20190526022629-625842035f05/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw= +github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54 h1:zK8KCB55hNdBadw5iJll46xQL6WXEwEXbt9B+QyYswo= +github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw= github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406 h1:iYMH6h6SuWuBkIzRtymosE8NpSgTK0oRMfyTdVWgxzc= github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406/go.mod h1:7jlS40+UhOqkZJDIG1B/H21xnuET/+fvbbnHCa8wSIo= github.com/jesseduffield/roll v0.0.0-20190629104057-695be2e62b00 h1:+JaOkfBNYQYlGD7dgru8mCwYNEc5tRRI8mThlVANhSM= @@ -154,7 +156,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 37e46cc0f..e917b3cf0 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -6,6 +6,7 @@ package gocui import ( standardErrors "errors" + "strings" "time" "github.com/go-errors/errors" @@ -38,18 +39,26 @@ const ( Output216 = OutputMode(termbox.Output216) ) +type tabClickHandler func(int) error + +type tabClickBinding struct { + viewName string + handler tabClickHandler +} + // Gui represents the whole User Interface, including the views, layouts // and keybindings. type Gui struct { - tbEvents chan termbox.Event - userEvents chan userEvent - views []*View - currentView *View - managers []Manager - keybindings []*keybinding - maxX, maxY int - outputMode OutputMode - stop chan struct{} + tbEvents chan termbox.Event + userEvents chan userEvent + views []*View + currentView *View + managers []Manager + keybindings []*keybinding + tabClickBindings []*tabClickBinding + maxX, maxY int + outputMode OutputMode + stop chan struct{} // BgColor and FgColor allow to configure the background and foreground // colors of the GUI. @@ -84,11 +93,16 @@ type Gui struct { // NewGui returns a new Gui object with a given output mode. func NewGui(mode OutputMode, supportOverlaps bool) (*Gui, error) { - if err := termbox.Init(); err != nil { + g := &Gui{} + + var err error + if g.maxX, g.maxY, err = g.getTermWindowSize(); err != nil { return nil, err } - g := &Gui{} + if err := termbox.Init(); err != nil { + return nil, err + } g.outputMode = mode termbox.SetOutputMode(termbox.OutputMode(mode)) @@ -98,8 +112,6 @@ func NewGui(mode OutputMode, supportOverlaps bool) (*Gui, error) { g.tbEvents = make(chan termbox.Event, 20) g.userEvents = make(chan userEvent, 20) - g.maxX, g.maxY = termbox.Size() - g.BgColor, g.FgColor = ColorDefault, ColorDefault g.SelBgColor, g.SelFgColor = ColorDefault, ColorDefault @@ -129,7 +141,8 @@ func (g *Gui) Size() (x, y int) { // the given colors. func (g *Gui) SetRune(x, y int, ch rune, fgColor, bgColor Attribute) error { if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY { - return errors.New("invalid point") + // swallowing error because it's not that big of a deal + return nil } termbox.SetCell(x, y, ch, termbox.Attribute(fgColor), termbox.Attribute(bgColor)) return nil @@ -232,7 +245,11 @@ func (g *Gui) ViewByPosition(x, y int) (*View, error) { // traverse views in reverse order checking top views first for i := len(g.views); i > 0; i-- { v := g.views[i-1] - if x > v.x0 && x < v.x1 && y > v.y0 && y < v.y1 { + frameOffset := 0 + if v.Frame { + frameOffset = 1 + } + if x > v.x0-frameOffset && x < v.x1+frameOffset && y > v.y0-frameOffset && y < v.y1+frameOffset { return v, nil } } @@ -320,6 +337,16 @@ func (g *Gui) DeleteKeybindings(viewname string) { g.keybindings = s } +// SetTabClickBinding sets a binding for a tab click event +func (g *Gui) SetTabClickBinding(viewName string, handler tabClickHandler) error { + g.tabClickBindings = append(g.tabClickBindings, &tabClickBinding{ + viewName: viewName, + handler: handler, + }) + + return nil +} + // getKey takes an empty interface with a key and returns the corresponding // typed Key or rune. func getKey(key interface{}) (Key, rune, error) { @@ -371,6 +398,7 @@ func (g *Gui) SetManager(managers ...Manager) { g.currentView = nil g.views = nil g.keybindings = nil + g.tabClickBindings = nil go func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }() } @@ -486,14 +514,7 @@ func (g *Gui) flush() error { continue } if v.Frame { - var fgColor, bgColor Attribute - if g.Highlight && v == g.currentView { - fgColor = g.SelFgColor - bgColor = g.SelBgColor - } else { - fgColor = g.FgColor - bgColor = g.BgColor - } + fgColor, bgColor := g.viewColors(v) if err := g.drawFrameEdges(v, fgColor, bgColor); err != nil { return err @@ -501,7 +522,7 @@ func (g *Gui) flush() error { if err := g.drawFrameCorners(v, fgColor, bgColor); err != nil { return err } - if v.Title != "" { + if v.Title != "" || len(v.Tabs) > 0 { if err := g.drawTitle(v, fgColor, bgColor); err != nil { return err } @@ -520,6 +541,13 @@ func (g *Gui) flush() error { return nil } +func (g *Gui) viewColors(v *View) (Attribute, Attribute) { + if g.Highlight && v == g.currentView { + return g.SelFgColor, g.SelBgColor + } + return g.FgColor, g.BgColor +} + // drawFrameEdges draws the horizontal and vertical edges of a view. func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error { runeH, runeV := '─', '│' @@ -615,17 +643,57 @@ func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error { return nil } - for i, ch := range v.Title { + tabs := v.Tabs + separator := " - " + charIndex := 0 + currentTabStart := -1 + currentTabEnd := -1 + if len(tabs) == 0 { + tabs = []string{v.Title} + } else { + for i, tab := range tabs { + if i == v.TabIndex { + currentTabStart = charIndex + currentTabEnd = charIndex + len(tab) + break + } + charIndex += len(tab) + if i < len(tabs)-1 { + charIndex += len(separator) + } + } + } + + str := strings.Join(tabs, separator) + + for i, ch := range str { x := v.x0 + i + 2 if x < 0 { continue } else if x > v.x1-2 || x >= g.maxX { break } - if err := g.SetRune(x, v.y0, ch, fgColor, bgColor); err != nil { + + currentFgColor := fgColor + currentBgColor := bgColor + // if you are the current view and you have multiple tabs, de-highlight the non-selected tabs + if v == g.currentView && len(v.Tabs) > 0 { + currentFgColor = v.FgColor + currentBgColor = v.BgColor + } + + if i >= currentTabStart && i <= currentTabEnd { + currentFgColor = v.SelFgColor + if v != g.currentView { + currentFgColor -= AttrBold + } + currentBgColor = v.SelBgColor + } + if err := g.SetRune(x, v.y0, ch, currentFgColor, currentBgColor); err != nil { return err } } + return nil } @@ -708,6 +776,17 @@ func (g *Gui) onKey(ev *termbox.Event) error { if err != nil { break } + if v.Frame && my == v.y0 { + if len(v.Tabs) > 0 { + tabIndex := v.GetClickedTabIndex(mx - v.x0) + + for _, binding := range g.tabClickBindings { + if binding.viewName == v.Name() { + return binding.handler(tabIndex) + } + } + } + } if err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil { return err } @@ -723,6 +802,8 @@ func (g *Gui) onKey(ev *termbox.Event) error { // and event. The value of matched is true if there is a match and no errors. func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) { var globalKb *keybinding + var matchingParentViewKb *keybinding + for _, kb := range g.keybindings { if kb.handler == nil { continue @@ -733,10 +814,16 @@ func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err err if kb.matchView(v) { return g.execKeybinding(v, kb) } + if kb.matchView(v.ParentView) { + matchingParentViewKb = kb + } if kb.viewName == "" && ((v != nil && !v.Editable) || (kb.ch == 0 && kb.key != KeyCtrlU && kb.key != KeyCtrlA && kb.key != KeyCtrlE)) { globalKb = kb } } + if matchingParentViewKb != nil { + return g.execKeybinding(v.ParentView, matchingParentViewKb) + } if globalKb != nil { return g.execKeybinding(v, globalKb) } diff --git a/vendor/github.com/jesseduffield/gocui/gui_notwin.go b/vendor/github.com/jesseduffield/gocui/gui_notwin.go new file mode 100644 index 000000000..dc445b938 --- /dev/null +++ b/vendor/github.com/jesseduffield/gocui/gui_notwin.go @@ -0,0 +1,61 @@ +// +build !windows + +package gocui + +import ( + "os" + "os/signal" + "syscall" + "unsafe" + + "github.com/go-errors/errors" +) + +type windowSize struct { + rows uint16 + cols uint16 + xpixels uint16 + ypixels uint16 +} + +// getTermWindowSize is get terminal window size on linux or unix. +// When gocui run inside the docker contaienr need to check and get the window size. +func (g *Gui) getTermWindowSize() (int, int, error) { + out, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) + if err != nil { + return 0, 0, err + } + defer out.Close() + + signalCh := make(chan os.Signal, 1) + signal.Notify(signalCh, syscall.SIGWINCH, syscall.SIGINT) + defer signal.Stop(signalCh) + + var sz windowSize + + for { + _, _, err = syscall.Syscall( + syscall.SYS_IOCTL, + out.Fd(), + uintptr(syscall.TIOCGWINSZ), + uintptr(unsafe.Pointer(&sz)), + ) + + // check terminal window size + if sz.cols > 0 && sz.rows > 0 { + return int(sz.cols), int(sz.rows), nil + } + + select { + case signal := <-signalCh: + switch signal { + // when the terminal window size is changed + case syscall.SIGWINCH: + continue + // ctrl + c to cancel + case syscall.SIGINT: + return 0, 0, errors.New("There was not enough window space to start the application") + } + } + } +} diff --git a/vendor/github.com/jesseduffield/gocui/gui_win.go b/vendor/github.com/jesseduffield/gocui/gui_win.go new file mode 100644 index 000000000..2a19775e7 --- /dev/null +++ b/vendor/github.com/jesseduffield/gocui/gui_win.go @@ -0,0 +1,10 @@ +// +build windows + +package gocui + +import "github.com/jesseduffield/termbox-go" + +func (g *Gui) getTermWindowSize() (int, int, error) { + x, y := termbox.Size() + return x, y, nil +} diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index 9d6553cbc..35ffa71ba 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -80,6 +80,9 @@ type View struct { // If Frame is true, Title allows to configure a title for the view. Title string + Tabs []string + TabIndex int + // If Frame is true, Subtitle allows to configure a subtitle for the view. Subtitle string @@ -94,6 +97,12 @@ type View struct { HasLoader bool writeMutex sync.Mutex + + // IgnoreCarriageReturns tells us whether to ignore '\r' characters + IgnoreCarriageReturns bool + + // ParentView is the view which catches events bubbled up from the given view if there's no matching handler + ParentView *View } type viewLine struct { @@ -190,7 +199,7 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error { func (v *View) SetCursor(x, y int) error { maxX, maxY := v.Size() if x < 0 || x >= maxX || y < 0 || y >= maxY { - return errors.New("invalid point") + return nil } v.cx = x v.cy = y @@ -235,6 +244,9 @@ func (v *View) Write(p []byte) (n int, err error) { case '\n': v.lines = append(v.lines, nil) case '\r': + if v.IgnoreCarriageReturns { + continue + } nl := len(v.lines) if nl > 0 { v.lines[nl-1] = nil @@ -421,7 +433,11 @@ func (v *View) realPosition(vx, vy int) (x, y int, err error) { // Clear empties the view's internal buffer. func (v *View) Clear() { + v.writeMutex.Lock() + defer v.writeMutex.Unlock() + v.tainted = true + v.ei.reset() v.lines = nil v.viewLines = nil @@ -470,10 +486,16 @@ func (v *View) ViewBufferLines() []string { return lines } +// LinesHeight is the count of view lines (i.e. lines excluding wrapping) func (v *View) LinesHeight() int { return len(v.lines) } +// ViewLinesHeight is the count of view lines (i.e. lines including wrapping) +func (v *View) ViewLinesHeight() int { + return len(v.viewLines) +} + // ViewBuffer returns a string with the contents of the view's buffer that is // shown to the user. func (v *View) ViewBuffer() string { @@ -614,3 +636,20 @@ func Loader() cell { func (v *View) IsTainted() bool { return v.tainted } + +// GetClickedTabIndex tells us which tab was clicked +func (v *View) GetClickedTabIndex(x int) int { + if len(v.Tabs) <= 1 { + return 0 + } + + charIndex := 0 + for i, tab := range v.Tabs { + charIndex += len(tab + " - ") + if x < charIndex { + return i + } + } + + return 0 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b32bf9709..9a8f42fe9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -76,7 +76,7 @@ github.com/hashicorp/hcl/json/token github.com/jbenet/go-context/io # github.com/jesseduffield/go-getter v0.0.0-20180822080847-906e15686e63 github.com/jesseduffield/go-getter -# github.com/jesseduffield/gocui v0.0.0-20190526022629-625842035f05 +# github.com/jesseduffield/gocui v0.3.1-0.20190908012510-092b2290ee54 github.com/jesseduffield/gocui # github.com/jesseduffield/pty v0.0.0-20181218102224-02db52c7e406 github.com/jesseduffield/pty -- cgit v1.2.3