diff --git a/iview.go b/iview.go index 9862364..22bba3f 100644 --- a/iview.go +++ b/iview.go @@ -3,6 +3,7 @@ package main import ( "errors" "strings" + "time" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" @@ -22,18 +23,25 @@ type _range struct { End int } -type InteractiveView struct { - visual bool - vrange *_range - baseSel int - View *tview.Table +type interactiveView struct { + visual bool + vrange *_range + baseSel int + Pages *tview.Pages + view *tview.Table + ctxContentHandler func() []string + ctxSelectHandler func(s string) } -func NewInteractiveView() *InteractiveView { +func NewInteractiveView() *interactiveView { view := tview.NewTable() view.SetSelectable(true, false) - i := &InteractiveView{ - View: view, + pages := tview.NewPages() + pages.AddPage("IView", view, true, true) + + i := &interactiveView{ + view: view, + Pages: pages, vrange: &_range{}, visual: false, } @@ -42,22 +50,22 @@ func NewInteractiveView() *InteractiveView { return i } -func (i *InteractiveView) exitVisualMode() { +func (i *interactiveView) exitVisualMode() { if i.vrange.Start < i.baseSel { - i.View.Select(i.vrange.Start, -1) + i.view.Select(i.vrange.Start, -1) } else if i.vrange.End > i.baseSel { - i.View.Select(i.vrange.End, -1) + i.view.Select(i.vrange.End, -1) } i.baseSel = -1 } -func (i *InteractiveView) enterVisualMode() { - row, _ := i.View.GetSelection() +func (i *interactiveView) enterVisualMode() { + row, _ := i.view.GetSelection() i.baseSel = row i.vrange.Start, i.vrange.End = row, row } -func (i *InteractiveView) toggleVisualMode() { +func (i *interactiveView) toggleVisualMode() { if i.visual { i.exitVisualMode() } else if !i.visual { @@ -66,7 +74,7 @@ func (i *InteractiveView) toggleVisualMode() { i.visual = !i.visual } -func (i *InteractiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.EventKey { +func (i *interactiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.EventKey { vr := i.vrange check := func() { if vr.Start <= -1 { @@ -75,11 +83,11 @@ func (i *InteractiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.Ev if vr.End <= -1 { vr.End = 0 } - if vr.End >= i.View.GetRowCount() { - vr.End = i.View.GetRowCount() - 1 + if vr.End >= i.view.GetRowCount() { + vr.End = i.view.GetRowCount() - 1 } - if vr.Start >= i.View.GetRowCount() { - vr.Start = i.View.GetRowCount() - 1 + if vr.Start >= i.view.GetRowCount() { + vr.Start = i.view.GetRowCount() - 1 } } funcMap := map[string]func(e *tcell.EventKey) *tcell.EventKey{ @@ -125,7 +133,7 @@ func (i *InteractiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.Ev if i.visual { i.vrange.Start = 0 i.vrange.End = i.baseSel - i.View.ScrollToBeginning() + i.view.ScrollToBeginning() return nil } return e @@ -133,12 +141,16 @@ func (i *InteractiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.Ev "bottom": func(e *tcell.EventKey) *tcell.EventKey { if i.visual { i.vrange.Start = i.baseSel - i.vrange.End = i.View.GetRowCount() - 1 - i.View.ScrollToEnd() + i.vrange.End = i.view.GetRowCount() - 1 + i.view.ScrollToEnd() return nil } return e }, + "openContextMenu": func(e *tcell.EventKey) *tcell.EventKey { + i.openContextMenu() + return nil + }, } if val, ok := funcMap[s]; ok { return val @@ -147,7 +159,7 @@ func (i *InteractiveView) GetHandler(s string) func(e *tcell.EventKey) *tcell.Ev } } -func (i *InteractiveView) capture(e *tcell.EventKey) *tcell.EventKey { +func (i *interactiveView) capture(e *tcell.EventKey) *tcell.EventKey { switch e.Rune() { case 'j': { @@ -170,6 +182,10 @@ func (i *InteractiveView) capture(e *tcell.EventKey) *tcell.EventKey { { return i.GetHandler("bottom")(e) } + case 'C': + { + return i.GetHandler("openContextMenu")(e) + } default: { if e.Key() == tcell.KeyEscape { @@ -186,21 +202,74 @@ func GetCell(text string, st tcell.Style) *tview.TableCell { SetStyle(st) } -func (i *InteractiveView) Update() { +func (i *interactiveView) setCtxContentHandler(f func() []string) { + i.ctxContentHandler = f +} + +func (i *interactiveView) setCtxSelectHandler(f func(s string)) { + i.ctxSelectHandler = f +} + +func (i *interactiveView) openContextMenu() { + iv := i.view + r, c := iv.GetSelection() + cslice := i.ctxContentHandler() + cwidth := 30 + cheight := len(cslice) + 2 + cpaddingx := 2 + cpaddingy := 1 + currentTime := time.Now().String() + + if i.visual { + r, c = i.baseSel, 1 + } + + ctxMenu := tview.NewTable() + ctxMenu.SetBorder(true) + ctxMenu.SetSelectable(true, false) + capture := func(e *tcell.EventKey) *tcell.EventKey { + closeCtx := func() { + i.Pages.RemovePage(currentTime) + } + if e.Key() == tcell.KeyEscape { + closeCtx() + return nil + } else if e.Key() == tcell.KeyEnter { + i.ctxSelectHandler( + ctxMenu.GetCell( + ctxMenu.GetSelection()).Text) + closeCtx() + return nil + } + return e + } + + ctxMenu.SetInputCapture(capture) + + for k := range cslice { + ctxMenu.SetCell(k, 0, + GetCell(cslice[k], defaultstyle)) + } + + i.Pages.AddPage(currentTime, ctxMenu, false, true) + ctxMenu.SetRect(c+cpaddingx, r+cpaddingy, cwidth, cheight) +} + +func (i *interactiveView) Update() { s := strings.Split("orem ipsum dolor sit amet, consectetur adipiscing elit. Nunc nec leo a tellus gravida convallis. Curabitur tempus purus nisi. Proin non enim convallis augue porta aliquet.", " ") - i.View.Clear() + i.view.Clear() for j := range s { b := "" if i.visual && (j >= i.vrange.Start && j <= i.vrange.End) { b = "[blue::]█[::]" } - i.View.SetCell(j, 0, + i.view.SetCell(j, 0, GetCell(b, defaultstyle)) - i.View.SetCell(j, 1, + i.view.SetCell(j, 1, GetCell(s[j], defaultstyle)) - i.View.SetCell(j, 2, + i.view.SetCell(j, 2, GetCell(s[j], defaultstyle.Foreground(tcell.ColorBlue))) - i.View.SetCell(j, 3, + i.view.SetCell(j, 3, GetCell(s[j], defaultstyle.Foreground(tcell.ColorYellow))) } }