Add table scroll left/right shortcut

pull/80/head
Miguel Mota 3 years ago
parent 394d35473d
commit 51cb442698

@ -458,8 +458,8 @@ refresh_rate = 60
"]" = "next_chart_range"
"{" = "first_chart_range"
"}" = "last_chart_range"
"<" = "previous_page"
">" = "next_page"
"<" = "scroll_left"
">" = "scroll_right"
C = "show_currency_convert_menu"
E = "show_portfolio_edit_menu"
G = "move_to_page_last_row"
@ -566,6 +566,8 @@ Action|Description
`quit_view`|Quit view
`refresh`|Do a manual refresh on the data
`save`|Save config
`scroll_left`|Scroll table to the left
`scroll_right`|Scroll table to the right
`shorten_chart`|Decrease chart height
`show_currency_convert_menu`|Show currency convert menu
`show_favorites`|Show favorites
@ -959,6 +961,10 @@ Frequently asked questions:
- A: Run cointop with the `--hide-statusbar` flag.
- Q: How do I scroll the table horizontally left or right?
- A: Use the keys <kbd><</kbd> to scroll the table to the left and <kbd><</kbd> to scroll the table to the right.
- Q: How can I delete the cache?
- A: Run `cointop clean` to delete the cache files. Cointop will generate new cache files after fetching data.

@ -72,6 +72,7 @@ type State struct {
shortcutKeys map[string]string
sortDesc bool
sortBy string
tableOffsetX int
onlyTable bool
chartHeight int
}
@ -216,7 +217,8 @@ func NewCointop(config *Config) (*Cointop, error) {
portfolio: &Portfolio{
Entries: make(map[string]*PortfolioEntry, 0),
},
chartHeight: 10,
chartHeight: 10,
tableOffsetX: 0,
},
TableColumnOrder: TableColumnOrder(),
Views: &Views{

@ -1,6 +1,7 @@
package cointop
import (
"fmt"
"strconv"
fcolor "github.com/fatih/color"
@ -229,6 +230,11 @@ func (c *Colorscheme) TableRowFavoriteSprintf() ISprintf {
return c.toSprintf("table_row_favorite")
}
// Default ...
func (c *Colorscheme) Default(a ...interface{}) string {
return fmt.Sprintf(a[0].(string), a[1:]...)
}
func (c *Colorscheme) toSprintf(name string) ISprintf {
if cached, ok := c.cache[name]; ok {
return cached

@ -2,7 +2,8 @@ package cointop
// DefaultShortcuts is a map of the default shortcuts
func DefaultShortcuts() map[string]string {
return map[string]string{"up": "move_up",
return map[string]string{
"up": "move_up",
"down": "move_down",
"left": "previous_page",
"right": "next_page",
@ -75,8 +76,8 @@ func DefaultShortcuts() map[string]string {
"[": "previous_chart_range",
"}": "last_chart_range",
"{": "first_chart_range",
">": "next_page",
"<": "previous_page",
">": "scroll_right",
"<": "scroll_left",
"\\\\": "toggle_table_fullscreen",
}
}

@ -39,7 +39,7 @@ func (ct *Cointop) UpdateHelp() {
if cnt%percol == 0 {
cnt = 0
}
item := fmt.Sprintf("%10s %-40s", k, ct.colorscheme.MenuLabel(v))
item := fmt.Sprintf("%10s %-45s", k, ct.colorscheme.MenuLabel(v))
cols[cnt] = append(cols[cnt], item)
cnt = cnt + 1
}

@ -279,6 +279,10 @@ func (ct *Cointop) Keybindings(g *gocui.Gui) error {
fn = ct.Sortfn("marketcap", true)
case "move_to_page_visible_middle_row":
fn = ct.Keyfn(ct.NavigatePageMiddleLine)
case "scroll_left":
fn = ct.Keyfn(ct.TableScrollLeft)
case "scroll_right":
fn = ct.Keyfn(ct.TableScrollRight)
case "sort_column_name":
fn = ct.Sortfn("name", false)
case "sort_column_price":
@ -375,6 +379,14 @@ func (ct *Cointop) Keybindings(g *gocui.Gui) error {
ct.SetKeybindingMod(gocui.KeyEsc, gocui.ModNone, ct.Keyfn(ct.HideConvertMenu), ct.Views.ConvertMenu.Name())
ct.SetKeybindingMod('q', gocui.ModNone, ct.Keyfn(ct.HideConvertMenu), ct.Views.ConvertMenu.Name())
// mouse events
ct.SetKeybindingMod(gocui.MouseRelease, gocui.ModNone, ct.Keyfn(ct.MouseRelease), "")
ct.SetKeybindingMod(gocui.MouseLeft, gocui.ModNone, ct.Keyfn(ct.MouseLeftClick), "")
ct.SetKeybindingMod(gocui.MouseMiddle, gocui.ModNone, ct.Keyfn(ct.MouseMiddleClick), "")
ct.SetKeybindingMod(gocui.MouseRight, gocui.ModNone, ct.Keyfn(ct.MouseRightClick), "")
ct.SetKeybindingMod(gocui.MouseWheelUp, gocui.ModNone, ct.Keyfn(ct.MouseWheelUp), "")
ct.SetKeybindingMod(gocui.MouseWheelDown, gocui.ModNone, ct.Keyfn(ct.MouseWheelDown), "")
// character key press to select option
// TODO: use scrolling table
keys := ct.SortedSupportedCurrencyConversions()

@ -90,8 +90,9 @@ func (ct *Cointop) layout() error {
}
}
tableOffsetX := ct.State.tableOffsetX
topOffset = topOffset + chartHeight
if err := ct.ui.SetView(ct.Views.TableHeader, 0, topOffset, ct.maxTableWidth, topOffset+2); err != nil {
if err := ct.ui.SetView(ct.Views.TableHeader, tableOffsetX, topOffset, ct.maxTableWidth, topOffset+2); err != nil {
ct.Views.TableHeader.SetFrame(false)
ct.Views.TableHeader.SetFgColor(ct.colorscheme.gocuiFgColor(ct.Views.TableHeader.Name()))
ct.Views.TableHeader.SetBgColor(ct.colorscheme.gocuiBgColor(ct.Views.TableHeader.Name()))
@ -99,7 +100,7 @@ func (ct *Cointop) layout() error {
}
topOffset = topOffset + headerHeight
if err := ct.ui.SetView(ct.Views.Table, 0, topOffset, ct.maxTableWidth, maxY-statusbarHeight); err != nil {
if err := ct.ui.SetView(ct.Views.Table, tableOffsetX, topOffset, ct.maxTableWidth, maxY-statusbarHeight); err != nil {
ct.Views.Table.SetFrame(false)
ct.Views.Table.SetHighlight(true)
ct.Views.Table.SetSelFgColor(ct.colorscheme.gocuiFgColor("table_row_active"))

@ -1,5 +1,9 @@
package cointop
import (
"math"
)
// CurrentPage returns the current page
func (ct *Cointop) CurrentPage() int {
ct.debuglog("currentPage()")
@ -461,3 +465,54 @@ func (ct *Cointop) CursorUpOrPreviousPage() error {
return nil
}
// TableScrollLeft scrolls the table to the left
func (ct *Cointop) TableScrollLeft() error {
ct.State.tableOffsetX++
if ct.State.tableOffsetX >= 0 {
ct.State.tableOffsetX = 0
}
ct.UpdateTable()
return nil
}
// TableScrollRight scrolls the the table to the right
func (ct *Cointop) TableScrollRight() error {
ct.State.tableOffsetX--
maxX := int(math.Min(float64(1-(ct.maxTableWidth-ct.width())), 0))
if ct.State.tableOffsetX <= maxX {
ct.State.tableOffsetX = maxX
}
ct.UpdateTable()
return nil
}
// MouseRelease is called on mouse releae event
func (ct *Cointop) MouseRelease() error {
return nil
}
// MouseLeftClick is called on mouse left click event
func (ct *Cointop) MouseLeftClick() error {
return nil
}
// MouseMiddleClick is called on mouse middle click event
func (ct *Cointop) MouseMiddleClick() error {
return nil
}
// MouseRightClick is called on mouse right click event
func (ct *Cointop) MouseRightClick() error {
return ct.OpenLink()
}
// MouseWheelUp is called on mouse wheel up event
func (ct *Cointop) MouseWheelUp() error {
return nil
}
// MouseWheelDown is called on mouse wheel down event
func (ct *Cointop) MouseWheelDown() error {
return nil
}

@ -9,7 +9,6 @@ import (
"time"
"github.com/miguelmota/cointop/pkg/humanize"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/table"
"github.com/miguelmota/cointop/pkg/ui"
)
@ -49,20 +48,10 @@ const dots = "..."
func (ct *Cointop) RefreshTable() error {
ct.debuglog("refreshTable()")
maxX := ct.width()
ct.table = table.New().SetWidth(maxX)
ct.table = table.NewTable().SetWidth(maxX)
ct.table.HideColumHeaders = true
if ct.State.portfolioVisible {
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
total := ct.GetPortfolioTotal()
for _, coin := range ct.State.coins {
@ -76,17 +65,13 @@ func (ct *Cointop) RefreshTable() error {
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
name := coin.Name
name := TruncateString(coin.Name, 20)
symbol := TruncateString(coin.Symbol, 6)
star := ct.colorscheme.TableRow(" ")
if coin.Favorite {
star = ct.colorscheme.TableRowFavorite("*")
}
rank := fmt.Sprintf("%s%v", star, ct.colorscheme.TableRow(fmt.Sprintf("%6v ", coin.Rank)))
if len(name) > 20 {
name = fmt.Sprintf("%s%s", name[0:18], dots)
}
namecolor := ct.colorscheme.TableRow
if coin.Favorite {
namecolor = ct.colorscheme.TableRowFavorite
@ -97,31 +82,75 @@ func (ct *Cointop) RefreshTable() error {
percentHoldings = 0
}
ct.table.AddRow(
rank,
namecolor(pad.Right(fmt.Sprintf("%.22s", name), 21, " ")),
ct.colorscheme.TableRow(pad.Right(fmt.Sprintf("%.6s", coin.Symbol), 5, " ")),
ct.colorscheme.TableRow(fmt.Sprintf("%13s", humanize.Commaf(coin.Price))),
ct.colorscheme.TableRow(fmt.Sprintf("%15s", strconv.FormatFloat(coin.Holdings, 'f', -1, 64))),
colorbalance(fmt.Sprintf("%15s", humanize.Commaf(coin.Balance))),
color24h(fmt.Sprintf("%8.2f%%", coin.PercentChange24H)),
ct.colorscheme.TableRow(fmt.Sprintf("%12.2f%%", percentHoldings)),
ct.colorscheme.TableRow(pad.Right(fmt.Sprintf("%17s", lastUpdated), 80, " ")),
rank := fmt.Sprintf("%s%v", star, ct.colorscheme.TableRow(fmt.Sprintf("%6v ", coin.Rank)))
ct.table.AddRowCells(
&table.RowCell{
LeftMargin: 0,
Width: 6,
LeftAlign: false,
Color: ct.colorscheme.Default,
Text: rank,
},
&table.RowCell{
LeftMargin: 1,
Width: 22,
LeftAlign: true,
Color: namecolor,
Text: name,
},
&table.RowCell{
LeftMargin: 1,
Width: 6,
LeftAlign: true,
Color: ct.colorscheme.TableRow,
Text: symbol,
},
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Price),
},
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: strconv.FormatFloat(coin.Holdings, 'f', -1, 64),
},
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: colorbalance,
Text: humanize.Commaf(coin.Balance),
},
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H),
},
&table.RowCell{
LeftMargin: 1,
Width: 14,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: fmt.Sprintf("%.2f%%", percentHoldings),
},
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: lastUpdated,
},
)
}
} else {
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
ct.table.AddCol("")
for _, coin := range ct.State.coins {
if coin == nil {
continue
@ -153,35 +182,106 @@ func (ct *Cointop) RefreshTable() error {
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}
name := coin.Name
name := TruncateString(coin.Name, 20)
symbol := TruncateString(coin.Symbol, 6)
star := ct.colorscheme.TableRow(" ")
if coin.Favorite {
star = ct.colorscheme.TableRowFavorite("*")
}
rank := fmt.Sprintf("%s%v", star, ct.colorscheme.TableRow(fmt.Sprintf("%6v ", coin.Rank)))
if len(name) > 20 {
name = fmt.Sprintf("%s%s", name[0:18], dots)
}
symbolpadding := 5
symbolpadding := 8
// NOTE: this is to adjust padding by 1 because when all name rows are
// yellow it messes the spacing (need to debug)
if ct.State.filterByFavorites {
symbolpadding = 6
symbolpadding++
}
ct.table.AddRow(
rank,
namecolor(pad.Right(fmt.Sprintf("%.22s", name), 21, " ")),
ct.colorscheme.TableRow(pad.Right(fmt.Sprintf("%.6s", coin.Symbol), symbolpadding, " ")),
ct.colorscheme.TableColumnPrice(fmt.Sprintf("%13s", humanize.Commaf(coin.Price))),
ct.colorscheme.TableRow(fmt.Sprintf("%17s", humanize.Commaf(coin.MarketCap))),
ct.colorscheme.TableRow(fmt.Sprintf("%15s", humanize.Commaf(coin.Volume24H))),
color1h(fmt.Sprintf("%8.2f%%", coin.PercentChange1H)),
color24h(fmt.Sprintf("%8.2f%%", coin.PercentChange24H)),
color7d(fmt.Sprintf("%8.2f%%", coin.PercentChange7D)),
ct.colorscheme.TableRow(fmt.Sprintf("%21s", humanize.Commaf(coin.TotalSupply))),
ct.colorscheme.TableRow(fmt.Sprintf("%18s", humanize.Commaf(coin.AvailableSupply))),
ct.colorscheme.TableRow(fmt.Sprintf("%18s", lastUpdated)),
rank := fmt.Sprintf("%s%v", star, ct.colorscheme.TableRow(fmt.Sprintf("%6v ", coin.Rank)))
ct.table.AddRowCells(
&table.RowCell{
LeftMargin: 0,
Width: 6,
LeftAlign: false,
Color: ct.colorscheme.Default,
Text: rank,
},
&table.RowCell{
LeftMargin: 1,
Width: 22,
LeftAlign: true,
Color: namecolor,
Text: name,
},
&table.RowCell{
LeftMargin: 1,
Width: symbolpadding,
LeftAlign: true,
Color: ct.colorscheme.TableRow,
Text: symbol,
},
&table.RowCell{
LeftMargin: 1,
Width: 12,
LeftAlign: false,
Color: ct.colorscheme.TableColumnPrice,
Text: humanize.Commaf(coin.Price),
},
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.MarketCap),
},
&table.RowCell{
LeftMargin: 1,
Width: 16,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Volume24H),
},
&table.RowCell{
LeftMargin: 1,
Width: 11,
LeftAlign: false,
Color: color1h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange1H),
},
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H),
},
&table.RowCell{
LeftMargin: 1,
Width: 10,
LeftAlign: false,
Color: color7d,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange7D),
},
&table.RowCell{
LeftMargin: 1,
Width: 22,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.TotalSupply),
},
&table.RowCell{
LeftMargin: 1,
Width: 19,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.AvailableSupply),
},
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: lastUpdated,
},
// TODO: add %percent of cap
)
}

@ -3,6 +3,7 @@ package cointop
import (
"bytes"
"encoding/gob"
"fmt"
"strings"
"github.com/miguelmota/cointop/pkg/open"
@ -31,3 +32,12 @@ func Slugify(s string) string {
s = strings.TrimSpace(strings.ToLower(s))
return s
}
// TruncateString returns a truncated string
func TruncateString(value string, maxLen int) string {
dots := "..."
if len(value) > maxLen {
value = fmt.Sprintf("%s%s", value[0:maxLen-3], dots)
}
return value
}

@ -26,8 +26,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@ -48,6 +46,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@ -67,17 +66,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/maruel/panicparse v1.1.2-0.20180806203336-f20d4c4d746f h1:mtX2D0ta3lWxCvv276VVIH6mMYzm4jhSfYP70ZJSOQU=
github.com/maruel/panicparse v1.1.2-0.20180806203336-f20d4c4d746f/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI=
github.com/maruel/panicparse v1.5.0 h1:etK4QAf/Spw8eyowKbOHRkOfhblp/kahGUy96RvbMjI=
github.com/maruel/panicparse v1.5.0/go.mod h1:aOutY/MUjdj80R0AEVI9qE2zHqig+67t2ffUDDiLzAM=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
@ -89,8 +83,6 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miguelmota/go-coinmarketcap v0.1.5 h1:NwAqQG+ClGNsYlReM06ERK8CqEkW1tF8BQsTLNp6TyU=
github.com/miguelmota/go-coinmarketcap v0.1.5/go.mod h1:Jdv/kqtKclIElmoNAZMMJn0DSQv+j7p/H1te/GGnxhA=
github.com/miguelmota/go-coinmarketcap v0.1.6 h1:YIe+VdFhEgyGESfmkL7BHRDIdf6CUOAjJisml01AFqs=
github.com/miguelmota/go-coinmarketcap v0.1.6/go.mod h1:Jdv/kqtKclIElmoNAZMMJn0DSQv+j7p/H1te/GGnxhA=
github.com/miguelmota/gocui v0.4.2 h1:nMYnYn3RjV7FlWFcidQa9eAkX3kT7XMI6yJMxEkAz6s=
@ -161,8 +153,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -180,15 +170,9 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -196,6 +180,7 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

@ -6,6 +6,7 @@ import (
"sort"
"strings"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/table/align"
)
@ -18,8 +19,8 @@ type Table struct {
HideColumHeaders bool
}
// New new table
func New() *Table {
// NewTable new table
func NewTable() *Table {
return &Table{}
}
@ -43,6 +44,23 @@ func (t *Table) AddRow(v ...interface{}) *Row {
return r
}
// AddRowCells add row using cells
func (t *Table) AddRowCells(cells ...*RowCell) *Row {
t.SetNumCol(len(cells))
v := make([]interface{}, len(cells))
for i, item := range cells {
v[i] = item.String()
}
return t.AddRow(v...)
}
// SetNumCol sets the number of columns
func (t *Table) SetNumCol(count int) {
for i := 0; i < count; i++ {
t.AddCol("")
}
}
// SortAscFn sort ascending function
func (t *Table) SortAscFn(n string, fn SortFn) *Table {
i := t.cols.Index(n)
@ -126,11 +144,11 @@ func (t *Table) Format() *Table {
}
if c.formatFn != nil {
r.strValues[j] = fmt.Sprintf("%s", c.formatFn(v)) + " "
r.strValues[j] = fmt.Sprintf("%s", c.formatFn(v))
} else if c.format != "" {
r.strValues[j] = fmt.Sprintf(c.format, v) + " "
r.strValues[j] = fmt.Sprintf(c.format, v)
} else {
r.strValues[j] = fmt.Sprintf("%v", v) + " "
r.strValues[j] = fmt.Sprintf("%v", v)
}
if len(r.strValues[j]) > t.cols[j].width {
@ -163,7 +181,10 @@ func (t *Table) Format() *Table {
break
}
t.cols[i].width += t.width - t.colWidth()
if len(t.cols) > 0 {
t.cols[i].width += t.width - t.colWidth()
}
return t
}
@ -223,3 +244,23 @@ func (t *Table) Fprint(w io.Writer) {
fmt.Fprintf(w, "\n")
}
}
// RowCell is a row cell struct
type RowCell struct {
LeftMargin int
Width int
LeftAlign bool
Color func(a ...interface{}) string
Text string
}
// String returns row cell as string
func (rc *RowCell) String() string {
t := strings.Repeat(" ", rc.LeftMargin) + rc.Text
if rc.LeftAlign {
t = pad.Right(t, rc.Width, " ")
} else {
t = fmt.Sprintf("%"+fmt.Sprintf("%v", rc.Width)+"s", t)
}
return rc.Color(t)
}

@ -4,12 +4,12 @@ import (
"github.com/miguelmota/gocui"
)
// UI ...
// UI is the UI view struct
type UI struct {
g *gocui.Gui
}
// NewUI ...
// NewUI returns a new UI instance
func NewUI() (*UI, error) {
g, err := gocui.NewGui(gocui.Output256)
if err != nil {
@ -21,44 +21,44 @@ func NewUI() (*UI, error) {
}, nil
}
// GetGocui ...
// GetGocui returns the underlying gocui instance
func (ui *UI) GetGocui() *gocui.Gui {
return ui.g
}
// SetFgColor ...
// SetFgColor sets the foreground color
func (ui *UI) SetFgColor(fgColor gocui.Attribute) {
ui.g.FgColor = fgColor
}
// SetBgColor ...
// SetBgColor sets the background color
func (ui *UI) SetBgColor(bgColor gocui.Attribute) {
ui.g.BgColor = bgColor
}
// SetInputEsc ...
// SetInputEsc enables the escape key
func (ui *UI) SetInputEsc(enabled bool) {
ui.g.InputEsc = true
}
// SetMouse ...
// SetMouse enables the mouse
func (ui *UI) SetMouse(enabled bool) {
ui.g.Mouse = true
}
// SetHighlight ...
// SetHighlight enables the highlight active state
func (ui *UI) SetHighlight(enabled bool) {
ui.g.Highlight = true
}
// SetManagerFunc ...
// SetManagerFunc sets the function to call for rendering UI
func (ui *UI) SetManagerFunc(fn func() error) {
ui.g.SetManagerFunc(func(*gocui.Gui) error {
return fn()
})
}
// MainLoop ...
// MainLoop starts the UI render loop
func (ui *UI) MainLoop() error {
return ui.g.MainLoop()
}
@ -68,7 +68,7 @@ func (ui *UI) Close() {
ui.g.Close()
}
// SetView ...
// SetView sets the view layout
func (ui *UI) SetView(view interface{}, x, y, w, h int) error {
if v, ok := view.(*View); ok {
gv, err := ui.g.SetView(v.Name(), x, y, w, h)

@ -6,14 +6,14 @@ import (
"github.com/miguelmota/gocui"
)
// IView is a cointop view
// IView is the view interface
type IView interface {
Backing() *gocui.View
SetBacking(gocuiView *gocui.View)
Name() string
}
// View is a cointop view
// View is a view sruct
type View struct {
backing *gocui.View
name string

Loading…
Cancel
Save