diff --git a/Gopkg.lock b/Gopkg.lock index 30e4c4a..2cb87ca 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -65,7 +65,7 @@ branch = "master" name = "github.com/miguelmota/go-coinmarketcap" packages = ["."] - revision = "05fd2d0c45f763462f90e630da2ddc0392d2cdd3" + revision = "9c6b4c2a42d7189f8778825da9640c3efda17d7e" [[projects]] branch = "master" @@ -79,12 +79,6 @@ packages = ["."] revision = "e2050e41c8847748ec5288741c0b19a8cb26d084" -[[projects]] - branch = "master" - name = "github.com/willf/pad" - packages = ["."] - revision = "b3d7806010228b1a954b4d9c4ee4cf6cb476b063" - [[projects]] branch = "master" name = "go4.org" @@ -98,7 +92,7 @@ "html", "html/atom" ] - revision = "6078986fec03a1dcc236c34816c71b0e05018fda" + revision = "b68f30494add4df6bd8ef5e82803f308e7f7c59c" [[projects]] branch = "master" @@ -109,6 +103,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "ff54fa52bac3cde3f10f5c237dad28da497594584e4291356b5efd040501fe4e" + inputs-digest = "cc43de082ffa9bbc96488c9bfc6659269a914a24c4ff2a04e1d43bfc66a992a4" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 7106cb0..8253968 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -49,10 +49,6 @@ branch = "master" name = "github.com/miguelmota/go-coinmarketcap" -[[constraint]] - branch = "master" - name = "github.com/willf/pad" - [prune] go-tests = true unused-packages = true diff --git a/Makefile b/Makefile index 79efba3..2d29546 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ all: @echo "no default" run: - go run cointop.go keybindings.go navigation.go sort.go + go run cointop.go keybindings.go navigation.go sort.go layout.go status.go chart.go table.go -build: - go build +build: clean + go build -ldflags "-s -w" -o bin/cointop && upx bin/cointop + +clean: + go clean && rm -f bin/cointop diff --git a/README.md b/README.md index 5420d20..347f5c0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ Make sure to have [golang](https://golang.org/) installed, then do: go install github.com/miguelmota/cointop ``` +### Alternatively + +``` +``` + ## Usage ```bash diff --git a/bin/cointop.REMOVED.git-id b/bin/cointop.REMOVED.git-id new file mode 100644 index 0000000..77e60bd --- /dev/null +++ b/bin/cointop.REMOVED.git-id @@ -0,0 +1 @@ +afb3d36c7d062f773b2646a50def45506046b9e8 \ No newline at end of file diff --git a/chart.go b/chart.go new file mode 100644 index 0000000..e8ee468 --- /dev/null +++ b/chart.go @@ -0,0 +1,84 @@ +package main + +import ( + "fmt" + "log" + "time" + + "github.com/gizak/termui" +) + +func (ct *Cointop) updateChart() error { + maxX, _ := ct.g.Size() + if len(ct.chartpoints) == 0 { + ct.chartPoints(maxX, "bitcoin") + } + + for i := range ct.chartpoints { + var s string + for j := range ct.chartpoints[i] { + p := ct.chartpoints[i][j] + s = fmt.Sprintf("%s%c", s, p.Ch) + } + fmt.Fprintln(ct.chartview, s) + } + return nil +} + +func (ct *Cointop) chartPoints(maxX int, coin string) error { + chart := termui.NewLineChart() + chart.Height = 10 + chart.AxesColor = termui.ColorWhite + chart.LineColor = termui.ColorCyan + chart.Border = false + + now := time.Now() + secs := now.Unix() + start := secs - oneDay + end := secs + + _ = coin + //graphData, err := cmc.GetCoinGraphData(coin, start, end) + graphData, err := ct.api.GetGlobalMarketGraphData(start, end) + if err != nil { + log.Fatal(err) + return nil + } + + var data []float64 + /* + for i := range graphData.PriceUSD { + data = append(data, graphData.PriceUSD[i][1]) + } + */ + for i := range graphData.MarketCapByAvailableSupply { + data = append(data, graphData.MarketCapByAvailableSupply[i][1]) + } + chart.Data = data + termui.Body = termui.NewGrid() + termui.Body.Width = maxX + termui.Body.AddRows( + termui.NewRow( + termui.NewCol(12, 0, chart), + ), + ) + + var points [][]termui.Cell + // calculate layout + termui.Body.Align() + w := termui.Body.Width + h := 10 + row := termui.Body.Rows[0] + b := row.Buffer() + for i := 0; i < h; i = i + 1 { + var rowpoints []termui.Cell + for j := 0; j < w; j = j + 1 { + p := b.At(j, i) + rowpoints = append(rowpoints, p) + } + points = append(points, rowpoints) + } + + ct.chartpoints = points + return nil +} diff --git a/cointop.go b/cointop.go index c40f8af..a6a082f 100644 --- a/cointop.go +++ b/cointop.go @@ -3,19 +3,13 @@ package main import ( "fmt" "log" - "os/exec" - "strconv" - "strings" - "time" - humanize "github.com/dustin/go-humanize" "github.com/gizak/termui" "github.com/jroimartin/gocui" - "github.com/miguelmota/cointop/apis" - apitypes "github.com/miguelmota/cointop/apis/types" - "github.com/miguelmota/cointop/color" - "github.com/miguelmota/cointop/pad" - "github.com/miguelmota/cointop/table" + "github.com/miguelmota/cointop/pkg/api" + apitypes "github.com/miguelmota/cointop/pkg/api/types" + "github.com/miguelmota/cointop/pkg/pad" + "github.com/miguelmota/cointop/pkg/table" ) var ( @@ -30,6 +24,7 @@ var ( // Cointop cointop type Cointop struct { g *gocui.Gui + marketview *gocui.View chartview *gocui.View chartpoints [][]termui.Cell headersview *gocui.View @@ -38,81 +33,10 @@ type Cointop struct { statusview *gocui.View sortdesc bool currentsort string - api apis.Interface + api api.Interface coins []*apitypes.Coin } -func (ct *Cointop) layout(g *gocui.Gui) error { - maxX, maxY := g.Size() - chartHeight := 10 - if v, err := g.SetView("chart", 0, 0, maxX, chartHeight); err != nil { - if err != gocui.ErrUnknownView { - return err - } - ct.chartview = v - ct.chartview.Frame = false - ct.updateChart() - } - - if v, err := g.SetView("header", 0, chartHeight, maxX, maxY); err != nil { - if err != gocui.ErrUnknownView { - return err - } - t := table.New().SetWidth(maxX) - headers := []string{ - pad.Right("[r]ank", 13, " "), - pad.Right("[n]ame", 13, " "), - pad.Right("[s]ymbol", 8, " "), - pad.Left("[p]rice", 10, " "), - pad.Left("[m]arket cap", 17, " "), - pad.Left("24H [v]olume", 15, " "), - pad.Left("[1]H%", 9, " "), - pad.Left("[2]4H%", 9, " "), - pad.Left("[7]D%", 9, " "), - pad.Left("[t]otal supply", 20, " "), - pad.Left("[a]vailable supply", 19, " "), - pad.Left("[l]ast updated", 17, " "), - } - for _, h := range headers { - t.AddCol(h) - } - - t.Format().Fprint(v) - ct.headersview = v - ct.headersview.Frame = false - ct.headersview.Highlight = true - ct.headersview.SelBgColor = gocui.ColorGreen - ct.headersview.SelFgColor = gocui.ColorBlack - } - - if v, err := g.SetView("table", 0, chartHeight+1, maxX, maxY-1); err != nil { - if err != gocui.ErrUnknownView { - return err - } - ct.tableview = v - ct.tableview.Frame = false - ct.tableview.Highlight = true - ct.tableview.SelBgColor = gocui.ColorCyan - ct.tableview.SelFgColor = gocui.ColorBlack - ct.updateTable() - ct.rowChanged() - } - - if v, err := g.SetView("status", 0, maxY-2, maxX, maxY); err != nil { - if err != gocui.ErrUnknownView { - return err - } - ct.statusview = v - ct.statusview.Frame = false - ct.statusview.Highlight = true - ct.statusview.SelBgColor = gocui.ColorCyan - ct.statusview.SelFgColor = gocui.ColorBlack - ct.updateStatus("") - } - - return nil -} - func (ct *Cointop) rowChanged() { ct.showLink() } @@ -133,188 +57,13 @@ func (ct *Cointop) fetchData() ([]*apitypes.Coin, error) { return result, nil } -func (ct *Cointop) chartPoints(maxX int, coin string) error { - chart := termui.NewLineChart() - chart.Height = 10 - chart.AxesColor = termui.ColorWhite - chart.LineColor = termui.ColorCyan - chart.Border = false - - now := time.Now() - secs := now.Unix() - start := secs - oneDay - end := secs - - _ = coin - //graphData, err := cmc.GetCoinGraphData(coin, start, end) - graphData, err := ct.api.GetGlobalMarketGraphData(start, end) - if err != nil { - log.Fatal(err) - return nil - } - - var data []float64 - /* - for i := range graphData.PriceUSD { - data = append(data, graphData.PriceUSD[i][1]) - } - */ - for i := range graphData.MarketCapByAvailableSupply { - data = append(data, graphData.MarketCapByAvailableSupply[i][1]) - } - chart.Data = data - termui.Body = termui.NewGrid() - termui.Body.Width = maxX - termui.Body.AddRows( - termui.NewRow( - termui.NewCol(12, 0, chart), - ), - ) - - var points [][]termui.Cell - // calculate layout - termui.Body.Align() - w := termui.Body.Width - h := 10 - row := termui.Body.Rows[0] - b := row.Buffer() - for i := 0; i < h; i = i + 1 { - var rowpoints []termui.Cell - for j := 0; j < w; j = j + 1 { - p := b.At(j, i) - rowpoints = append(rowpoints, p) - } - points = append(points, rowpoints) - } - - ct.chartpoints = points - return nil -} - -func (ct *Cointop) updateChart() error { +func (ct *Cointop) updateMarket() error { maxX, _ := ct.g.Size() - if len(ct.chartpoints) == 0 { - ct.chartPoints(maxX, "bitcoin") - } - - for i := range ct.chartpoints { - var s string - for j := range ct.chartpoints[i] { - p := ct.chartpoints[i][j] - s = fmt.Sprintf("%s%c", s, p.Ch) - } - fmt.Fprintln(ct.chartview, s) - } + s := "barfoo" + fmt.Fprintln(ct.marketview, pad.Right(fmt.Sprintf("[q]uit %s", s), maxX, " ")) return nil } -func (ct *Cointop) updateTable() error { - maxX, _ := ct.g.Size() - ct.table = table.New().SetWidth(maxX) - 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("") - ct.table.HideColumHeaders = true - var err error - if len(ct.coins) == 0 { - ct.coins, err = ct.fetchData() - if err != nil { - return err - } - } - for _, coin := range ct.coins { - unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64) - lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02") - colorprice := color.Cyan - color1h := color.White - color24h := color.White - color7d := color.White - if coin.PercentChange1H > 0 { - color1h = color.Green - } - if coin.PercentChange1H < 0 { - color1h = color.Red - } - if coin.PercentChange24H > 0 { - color24h = color.Green - } - if coin.PercentChange24H < 0 { - color24h = color.Red - } - if coin.PercentChange7D > 0 { - color7d = color.Green - } - if coin.PercentChange7D < 0 { - color7d = color.Red - } - ct.table.AddRow( - pad.Left(fmt.Sprint(coin.Rank), 4, " "), - pad.Right(coin.Name, 22, " "), - pad.Right(coin.Symbol, 6, " "), - colorprice(pad.Left(humanize.Commaf(coin.PriceUSD), 12, " ")), - pad.Left(humanize.Commaf(coin.MarketCapUSD), 17, " "), - pad.Left(humanize.Commaf(coin.USD24HVolume), 15, " "), - color1h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange1H), 9, " ")), - color24h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange24H), 9, " ")), - color7d(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange7D), 9, " ")), - pad.Left(humanize.Commaf(coin.TotalSupply), 20, " "), - pad.Left(humanize.Commaf(coin.AvailableSupply), 18, " "), - pad.Left(fmt.Sprintf("%s", lastUpdated), 18, " "), - // add %percent of cap - ) - } - - ct.table.Format().Fprint(ct.tableview) - return nil -} - -func (ct *Cointop) updateStatus(s string) { - maxX, _ := ct.g.Size() - ct.statusview.Clear() - fmt.Fprintln(ct.statusview, pad.Right(fmt.Sprintf("[q]uit %s", s), maxX, " ")) -} - -func (ct *Cointop) showLink() { - url := ct.rowLink() - ct.g.Update(func(g *gocui.Gui) error { - ct.updateStatus(fmt.Sprintf("[enter]=%s", url)) - return nil - }) -} - -func (ct *Cointop) enter(g *gocui.Gui, v *gocui.View) error { - exec.Command("open", ct.rowLink()).Output() - return nil -} - -func (ct *Cointop) quit(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit -} - -func (ct *Cointop) selectedRowIndex() int { - _, y := ct.tableview.Origin() - _, cy := ct.tableview.Cursor() - return y + cy -} - -func (ct *Cointop) selectedCoin() *apitypes.Coin { - return ct.coins[ct.selectedRowIndex()] -} - -func (ct *Cointop) rowLink() string { - slug := strings.ToLower(strings.Replace(ct.selectedCoin().Name, " ", "-", -1)) - return fmt.Sprintf("https://coinmarketcap.com/currencies/%s", slug) -} - func main() { g, err := gocui.NewGui(gocui.Output256) if err != nil { @@ -324,17 +73,14 @@ func main() { g.Cursor = true g.Mouse = true g.Highlight = true - ct := Cointop{ g: g, - api: apis.NewCMC(), + api: api.NewCMC(), } g.SetManagerFunc(ct.layout) - if err := ct.keybindings(g); err != nil { log.Fatalf("keybindings: %v", err) } - if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { log.Fatalf("main loop: %v", err) } diff --git a/keybindings.go b/keybindings.go index 1d7cd0b..cd72383 100644 --- a/keybindings.go +++ b/keybindings.go @@ -2,6 +2,7 @@ package main import ( "log" + "os/exec" "github.com/jroimartin/gocui" ) @@ -45,3 +46,12 @@ func (ct *Cointop) keybindings(g *gocui.Gui) error { ct.setKeybinding(gocui.KeyEsc, ct.quit) return nil } + +func (ct *Cointop) enter(g *gocui.Gui, v *gocui.View) error { + exec.Command("open", ct.rowLink()).Output() + return nil +} + +func (ct *Cointop) quit(g *gocui.Gui, v *gocui.View) error { + return gocui.ErrQuit +} diff --git a/layout.go b/layout.go new file mode 100644 index 0000000..16f14cb --- /dev/null +++ b/layout.go @@ -0,0 +1,93 @@ +package main + +import ( + "github.com/jroimartin/gocui" + "github.com/miguelmota/cointop/pkg/pad" + "github.com/miguelmota/cointop/pkg/table" +) + +func (ct *Cointop) layout(g *gocui.Gui) error { + maxX, maxY := g.Size() + chartHeight := 10 + topOffset := 0 + + if v, err := g.SetView("market", 0, topOffset, maxX, 2); err != nil { + if err != gocui.ErrUnknownView { + return err + } + ct.marketview = v + ct.marketview.Frame = false + ct.marketview.BgColor = gocui.ColorBlack + ct.marketview.FgColor = gocui.ColorWhite + ct.updateMarket() + } + + topOffset = topOffset + 1 + if v, err := g.SetView("chart", 0, topOffset, maxX, topOffset+chartHeight); err != nil { + if err != gocui.ErrUnknownView { + return err + } + ct.chartview = v + ct.chartview.Frame = false + ct.updateChart() + } + + topOffset = topOffset + chartHeight + if v, err := g.SetView("header", 0, topOffset, maxX, topOffset+2); err != nil { + if err != gocui.ErrUnknownView { + return err + } + t := table.New().SetWidth(maxX) + headers := []string{ + pad.Right("[r]ank", 13, " "), + pad.Right("[n]ame", 13, " "), + pad.Right("[s]ymbol", 8, " "), + pad.Left("[p]rice", 10, " "), + pad.Left("[m]arket cap", 17, " "), + pad.Left("24H [v]olume", 15, " "), + pad.Left("[1]H%", 9, " "), + pad.Left("[2]4H%", 9, " "), + pad.Left("[7]D%", 9, " "), + pad.Left("[t]otal supply", 20, " "), + pad.Left("[a]vailable supply", 19, " "), + pad.Left("[l]ast updated", 17, " "), + } + for _, h := range headers { + t.AddCol(h) + } + + t.Format().Fprint(v) + ct.headersview = v + ct.headersview.Frame = false + ct.headersview.Highlight = true + ct.headersview.SelBgColor = gocui.ColorGreen + ct.headersview.SelFgColor = gocui.ColorBlack + } + + topOffset = topOffset + 1 + if v, err := g.SetView("table", 0, topOffset, maxX, maxY-1); err != nil { + if err != gocui.ErrUnknownView { + return err + } + ct.tableview = v + ct.tableview.Frame = false + ct.tableview.Highlight = true + ct.tableview.SelBgColor = gocui.ColorCyan + ct.tableview.SelFgColor = gocui.ColorBlack + ct.updateTable() + ct.rowChanged() + } + + if v, err := g.SetView("status", 0, maxY-2, maxX, maxY); err != nil { + if err != gocui.ErrUnknownView { + return err + } + ct.statusview = v + ct.statusview.Frame = false + ct.statusview.BgColor = gocui.ColorCyan + ct.statusview.FgColor = gocui.ColorBlack + ct.updateStatus("") + } + + return nil +} diff --git a/apis/apis.go b/pkg/api/api.go similarity index 59% rename from apis/apis.go rename to pkg/api/api.go index 8a52002..80d3576 100644 --- a/apis/apis.go +++ b/pkg/api/api.go @@ -1,7 +1,7 @@ -package apis +package api import ( - cmc "github.com/miguelmota/cointop/apis/cmc" + cmc "github.com/miguelmota/cointop/pkg/api/cmc" ) // NewCMC new CoinMarketCap api diff --git a/apis/cmc/cmc.go b/pkg/api/cmc/cmc.go similarity index 96% rename from apis/cmc/cmc.go rename to pkg/api/cmc/cmc.go index aef7bf6..a5c7cab 100644 --- a/apis/cmc/cmc.go +++ b/pkg/api/cmc/cmc.go @@ -1,7 +1,7 @@ -package apis +package api import ( - types "github.com/miguelmota/cointop/apis/types" + types "github.com/miguelmota/cointop/pkg/api/types" cmc "github.com/miguelmota/go-coinmarketcap" ) diff --git a/apis/interface.go b/pkg/api/interface.go similarity index 89% rename from apis/interface.go rename to pkg/api/interface.go index 9c0cfbb..7e59931 100644 --- a/apis/interface.go +++ b/pkg/api/interface.go @@ -1,7 +1,7 @@ -package apis +package api import ( - types "github.com/miguelmota/cointop/apis/types" + types "github.com/miguelmota/cointop/pkg/api/types" ) // Interface interface diff --git a/apis/types/types.go b/pkg/api/types/types.go similarity index 98% rename from apis/types/types.go rename to pkg/api/types/types.go index 082e95b..2c406b4 100644 --- a/apis/types/types.go +++ b/pkg/api/types/types.go @@ -1,4 +1,4 @@ -package apis +package api // Coin struct type Coin struct { diff --git a/color/color.go b/pkg/color/color.go similarity index 100% rename from color/color.go rename to pkg/color/color.go diff --git a/pad/pad.go b/pkg/pad/pad.go similarity index 100% rename from pad/pad.go rename to pkg/pad/pad.go diff --git a/table/README.md b/pkg/table/README.md similarity index 100% rename from table/README.md rename to pkg/table/README.md diff --git a/table/align.go b/pkg/table/align.go similarity index 100% rename from table/align.go rename to pkg/table/align.go diff --git a/table/align/align.go b/pkg/table/align/align.go similarity index 100% rename from table/align/align.go rename to pkg/table/align/align.go diff --git a/table/column.go b/pkg/table/column.go similarity index 100% rename from table/column.go rename to pkg/table/column.go diff --git a/table/row.go b/pkg/table/row.go similarity index 100% rename from table/row.go rename to pkg/table/row.go diff --git a/table/sort.go b/pkg/table/sort.go similarity index 100% rename from table/sort.go rename to pkg/table/sort.go diff --git a/table/table.go b/pkg/table/table.go similarity index 98% rename from table/table.go rename to pkg/table/table.go index ccfd6d8..c98d398 100644 --- a/table/table.go +++ b/pkg/table/table.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/miguelmota/cointop/table/align" + "github.com/miguelmota/cointop/pkg/table/align" ) // Table table diff --git a/status.go b/status.go new file mode 100644 index 0000000..3e13168 --- /dev/null +++ b/status.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + + "github.com/jroimartin/gocui" + "github.com/miguelmota/cointop/pkg/pad" +) + +func (ct *Cointop) updateStatus(s string) { + maxX, _ := ct.g.Size() + ct.statusview.Clear() + fmt.Fprintln(ct.statusview, pad.Right(fmt.Sprintf("[q]uit %s", s), maxX, " ")) +} + +func (ct *Cointop) showLink() { + url := ct.rowLink() + ct.g.Update(func(g *gocui.Gui) error { + ct.updateStatus(fmt.Sprintf("[↵]%s", url)) + return nil + }) +} diff --git a/table.go b/table.go new file mode 100644 index 0000000..ec511cf --- /dev/null +++ b/table.go @@ -0,0 +1,98 @@ +package main + +import ( + "fmt" + "strconv" + "strings" + "time" + + humanize "github.com/dustin/go-humanize" + apitypes "github.com/miguelmota/cointop/pkg/api/types" + "github.com/miguelmota/cointop/pkg/color" + "github.com/miguelmota/cointop/pkg/pad" + "github.com/miguelmota/cointop/pkg/table" +) + +func (ct *Cointop) updateTable() error { + maxX, _ := ct.g.Size() + ct.table = table.New().SetWidth(maxX) + 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("") + ct.table.HideColumHeaders = true + var err error + if len(ct.coins) == 0 { + ct.coins, err = ct.fetchData() + if err != nil { + return err + } + } + for _, coin := range ct.coins { + unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64) + lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02") + colorprice := color.Cyan + color1h := color.White + color24h := color.White + color7d := color.White + if coin.PercentChange1H > 0 { + color1h = color.Green + } + if coin.PercentChange1H < 0 { + color1h = color.Red + } + if coin.PercentChange24H > 0 { + color24h = color.Green + } + if coin.PercentChange24H < 0 { + color24h = color.Red + } + if coin.PercentChange7D > 0 { + color7d = color.Green + } + if coin.PercentChange7D < 0 { + color7d = color.Red + } + ct.table.AddRow( + pad.Left(fmt.Sprint(coin.Rank), 4, " "), + pad.Right(coin.Name, 22, " "), + pad.Right(coin.Symbol, 6, " "), + colorprice(pad.Left(humanize.Commaf(coin.PriceUSD), 12, " ")), + pad.Left(humanize.Commaf(coin.MarketCapUSD), 17, " "), + pad.Left(humanize.Commaf(coin.USD24HVolume), 15, " "), + color1h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange1H), 9, " ")), + color24h(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange24H), 9, " ")), + color7d(pad.Left(fmt.Sprintf("%.2f%%", coin.PercentChange7D), 9, " ")), + pad.Left(humanize.Commaf(coin.TotalSupply), 20, " "), + pad.Left(humanize.Commaf(coin.AvailableSupply), 18, " "), + pad.Left(fmt.Sprintf("%s", lastUpdated), 18, " "), + // add %percent of cap + ) + } + + ct.table.Format().Fprint(ct.tableview) + return nil +} + +func (ct *Cointop) selectedRowIndex() int { + _, y := ct.tableview.Origin() + _, cy := ct.tableview.Cursor() + return y + cy +} + +func (ct *Cointop) selectedCoin() *apitypes.Coin { + return ct.coins[ct.selectedRowIndex()] +} + +func (ct *Cointop) rowLink() string { + slug := strings.ToLower(strings.Replace(ct.selectedCoin().Name, " ", "-", -1)) + return fmt.Sprintf("https://coinmarketcap.com/currencies/%s", slug) +}