Dynamic column widths

pull/94/head
Miguel Mota 3 years ago
parent ae65cc58d7
commit 184ebfb497

@ -15,11 +15,11 @@ var DefaultCoinTableHeaders = []string{
"name", "name",
"symbol", "symbol",
"price", "price",
"marketcap",
"24h_volume",
"1h_change", "1h_change",
"24h_change", "24h_change",
"7d_change", "7d_change",
"24h_volume",
"market_cap",
"total_supply", "total_supply",
"available_supply", "available_supply",
"last_updated", "last_updated",
@ -32,7 +32,6 @@ func (ct *Cointop) ValidCoinsTableHeader(name string) bool {
return true return true
} }
} }
return false return false
} }
@ -45,168 +44,201 @@ func (ct *Cointop) GetCoinsTableHeaders() []string {
func (ct *Cointop) GetCoinsTable() *table.Table { func (ct *Cointop) GetCoinsTable() *table.Table {
maxX := ct.width() maxX := ct.width()
t := table.NewTable().SetWidth(maxX) t := table.NewTable().SetWidth(maxX)
var rows [][]*table.RowCell
headers := ct.GetCoinsTableHeaders()
ct.ClearSyncMap(ct.State.tableColumnWidths)
ct.ClearSyncMap(ct.State.tableColumnAlignLeft)
for _, coin := range ct.State.coins { for _, coin := range ct.State.coins {
if coin == nil { if coin == nil {
continue continue
} }
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)))
name := TruncateString(coin.Name, 20)
symbol := TruncateString(coin.Symbol, 6)
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.IsFavoritesVisible() {
symbolpadding++
}
namecolor := ct.colorscheme.TableRow
color1h := ct.colorscheme.TableColumnChange
color24h := ct.colorscheme.TableColumnChange
color7d := ct.colorscheme.TableColumnChange
if coin.Favorite {
namecolor = ct.colorscheme.TableRowFavorite
}
if coin.PercentChange1H > 0 {
color1h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange1H < 0 {
color1h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange24H > 0 {
color24h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange7D > 0 {
color7d = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
headers := ct.GetCoinsTableHeaders()
var rowCells []*table.RowCell var rowCells []*table.RowCell
for _, header := range headers { for _, header := range headers {
leftMargin := 1
rightMargin := 1
switch header { switch header {
case "rank": case "rank":
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)))
ct.SetTableColumnWidth(header, 8)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, &table.RowCell{ rowCells = append(rowCells, &table.RowCell{
LeftMargin: 0, LeftMargin: leftMargin,
Width: 6, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.Default, Color: ct.colorscheme.Default,
Text: rank, Text: rank,
}) })
case "name": case "name":
name := TruncateString(coin.Name, 16)
namecolor := ct.colorscheme.TableRow
if coin.Favorite {
namecolor = ct.colorscheme.TableRowFavorite
}
ct.SetTableColumnWidthFromString(header, name)
ct.SetTableColumnAlignLeft(header, true)
rowCells = append(rowCells, &table.RowCell{ rowCells = append(rowCells, &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 22, RightMargin: rightMargin,
LeftAlign: true, LeftAlign: true,
Color: namecolor, Color: namecolor,
Text: name, Text: name,
}) })
case "symbol": case "symbol":
symbol := TruncateString(coin.Symbol, 6)
ct.SetTableColumnWidthFromString(header, symbol)
ct.SetTableColumnAlignLeft(header, true)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: symbolpadding, RightMargin: rightMargin,
LeftAlign: true, LeftAlign: true,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: symbol, Text: symbol,
}) })
case "price": case "price":
text := humanize.Commaf(coin.Price)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 12, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableColumnPrice, Color: ct.colorscheme.TableColumnPrice,
Text: humanize.Commaf(coin.Price), Text: text,
})
case "marketcap":
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: 1,
Width: 18,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.MarketCap),
}) })
case "24h_volume": case "24h_volume":
text := humanize.Commaf(coin.Volume24H)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 16, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Volume24H), Text: text,
}) })
case "1h_change": case "1h_change":
color1h := ct.colorscheme.TableColumnChange
if coin.PercentChange1H > 0 {
color1h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange1H < 0 {
color1h = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange1H)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 11, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color1h, Color: color1h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange1H), Text: text,
}) })
case "24h_change": case "24h_change":
color24h := ct.colorscheme.TableColumnChange
if coin.PercentChange24H > 0 {
color24h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange24H)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 10, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color24h, Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H), Text: text,
}) })
case "7d_change": case "7d_change":
color7d := ct.colorscheme.TableColumnChange
if coin.PercentChange7D > 0 {
color7d = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange7D)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 10, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color7d, Color: color7d,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange7D), Text: text,
})
case "market_cap":
text := humanize.Commaf(coin.MarketCap)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells,
&table.RowCell{
LeftMargin: leftMargin,
RightMargin: rightMargin,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: text,
}) })
case "total_supply": case "total_supply":
text := humanize.Commaf(coin.TotalSupply)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 22, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.TotalSupply), Text: text,
}) })
case "available_supply": case "available_supply":
text := humanize.Commaf(coin.AvailableSupply)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 20, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.AvailableSupply), Text: text,
}) })
case "last_updated": case "last_updated":
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
ct.SetTableColumnWidthFromString(header, lastUpdated)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 18, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: lastUpdated, Text: lastUpdated,
}) })
} }
} }
rows = append(rows, rowCells)
}
t.AddRowCells( for _, row := range rows {
rowCells..., for i, header := range headers {
// TODO: add %percent of cap row[i].Width = ct.GetTableColumnWidth(header)
) }
t.AddRowCells(row...)
} }
return t return t

@ -75,6 +75,8 @@ type State struct {
sortBy string sortBy string
tableOffsetX int tableOffsetX int
onlyTable bool onlyTable bool
tableColumnWidths sync.Map
tableColumnAlignLeft sync.Map
chartHeight int chartHeight int
priceAlerts *PriceAlerts priceAlerts *PriceAlerts
priceAlertEditID string priceAlertEditID string
@ -236,6 +238,8 @@ func NewCointop(config *Config) (*Cointop, error) {
portfolioTableColumns: DefaultPortfolioTableHeaders, portfolioTableColumns: DefaultPortfolioTableHeaders,
chartHeight: 10, chartHeight: 10,
tableOffsetX: 0, tableOffsetX: 0,
tableColumnWidths: sync.Map{},
tableColumnAlignLeft: sync.Map{},
priceAlerts: &PriceAlerts{ priceAlerts: &PriceAlerts{
Entries: make([]*PriceAlert, 0), Entries: make([]*PriceAlert, 0),
SoundEnabled: true, SoundEnabled: true,

@ -239,6 +239,8 @@ func (c *Colorscheme) Default(a ...interface{}) string {
} }
func (c *Colorscheme) toSprintf(name string) ISprintf { func (c *Colorscheme) toSprintf(name string) ISprintf {
c.cacheMutex.Lock()
defer c.cacheMutex.Unlock()
if cached, ok := c.cache[name]; ok { if cached, ok := c.cache[name]; ok {
return cached return cached
} }
@ -265,9 +267,7 @@ func (c *Colorscheme) toSprintf(name string) ISprintf {
} }
} }
c.cacheMutex.Lock()
c.cache[name] = fcolor.New(attrs...).SprintFunc() c.cache[name] = fcolor.New(attrs...).SprintFunc()
c.cacheMutex.Unlock()
return c.cache[name] return c.cache[name]
} }

@ -7,7 +7,6 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -243,12 +242,8 @@ func (ct *Cointop) configToToml() ([]byte, error) {
}) })
portfolioIfc["holdings"] = holdingsIfc portfolioIfc["holdings"] = holdingsIfc
if reflect.DeepEqual(DefaultPortfolioTableHeaders, ct.State.portfolioTableColumns) { var columnsIfc interface{} = ct.State.portfolioTableColumns
portfolioIfc["columns"] = []string{} portfolioIfc["columns"] = columnsIfc
} else {
var columnsIfc interface{} = ct.State.portfolioTableColumns
portfolioIfc["columns"] = columnsIfc
}
var currencyIfc interface{} = ct.State.currencyConversion var currencyIfc interface{} = ct.State.currencyConversion
var defaultViewIfc interface{} = ct.State.defaultView var defaultViewIfc interface{} = ct.State.defaultView
@ -281,12 +276,7 @@ func (ct *Cointop) configToToml() ([]byte, error) {
var coinsTableColumnsIfc interface{} = ct.State.coinsTableColumns var coinsTableColumnsIfc interface{} = ct.State.coinsTableColumns
tableMapIfc := map[string]interface{}{} tableMapIfc := map[string]interface{}{}
tableMapIfc["columns"] = coinsTableColumnsIfc
if reflect.DeepEqual(DefaultCoinTableHeaders, ct.State.coinsTableColumns) {
tableMapIfc["columns"] = []string{}
} else {
tableMapIfc["columns"] = coinsTableColumnsIfc
}
var inputs = &config{ var inputs = &config{
API: apiChoiceIfc, API: apiChoiceIfc,
@ -374,6 +364,8 @@ func (ct *Cointop) loadDefaultViewFromConfig() error {
ct.SetSelectedView(PortfolioView) ct.SetSelectedView(PortfolioView)
case "favorites": case "favorites":
ct.SetSelectedView(FavoritesView) ct.SetSelectedView(FavoritesView)
case "alerts", "price_alerts":
ct.SetSelectedView(PriceAlertsView)
case "default": case "default":
fallthrough fallthrough
default: default:

@ -44,7 +44,7 @@ func (ct *Cointop) UpdateHelp() {
body = fmt.Sprintf("%s%s\n", body, row) body = fmt.Sprintf("%s%s\n", body, row)
} }
versionLine := fmt.Sprintf("cointop %s - (C) 2017-2020 Miguel Mota", ct.Version()) versionLine := fmt.Sprintf("cointop %s - (C) 2017-2021 Miguel Mota", ct.Version())
licenseLine := "Released under the Apache 2.0 License." licenseLine := "Released under the Apache 2.0 License."
instructionsLine := "List of keyboard shortcuts" instructionsLine := "List of keyboard shortcuts"
infoLine := "See git.io/cointop for more info.\n Press ESC to return." infoLine := "See git.io/cointop for more info.\n Press ESC to return."

@ -93,21 +93,9 @@ func (ct *Cointop) ParseKeys(s string) (interface{}, gocui.Modifier) {
key = gocui.KeyCtrlZ key = gocui.KeyCtrlZ
case "~": case "~":
key = gocui.KeyCtrlTilde key = gocui.KeyCtrlTilde
case "[": case "[", "lsqrbracket", "leftsqrbracket", "leftsquarebracket":
fallthrough
case "lsqrbracket":
fallthrough
case "leftsqrbracket":
fallthrough
case "leftsquarebracket":
key = gocui.KeyCtrlLsqBracket key = gocui.KeyCtrlLsqBracket
case "]": case "]", "rsqrbracket", "rightsqrbracket", "rightsquarebracket":
fallthrough
case "rsqrbracket":
fallthrough
case "rightsqrbracket":
fallthrough
case "rightsquarebracket":
key = gocui.KeyCtrlRsqBracket key = gocui.KeyCtrlRsqBracket
case "space": case "space":
key = gocui.KeyCtrlSpace key = gocui.KeyCtrlSpace
@ -130,41 +118,19 @@ func (ct *Cointop) ParseKeys(s string) (interface{}, gocui.Modifier) {
s = strings.ToLower(s) s = strings.ToLower(s)
switch s { switch s {
case "arrowup": case "arrowup", "uparrow", "up":
fallthrough
case "uparrow":
fallthrough
case "up":
key = gocui.KeyArrowUp key = gocui.KeyArrowUp
case "arrowdown": case "arrowdown", "downarrow", "down":
fallthrough
case "downarrow":
fallthrough
case "down":
key = gocui.KeyArrowDown key = gocui.KeyArrowDown
case "arrowleft": case "arrowleft", "leftarrow", "left":
fallthrough
case "leftarrow":
fallthrough
case "left":
key = gocui.KeyArrowLeft key = gocui.KeyArrowLeft
case "arrowright": case "arrowright", "rightarrow", "right":
fallthrough
case "rightarrow":
fallthrough
case "right":
key = gocui.KeyArrowRight key = gocui.KeyArrowRight
case "enter": case "enter", "return":
fallthrough
case "return":
key = gocui.KeyEnter key = gocui.KeyEnter
case "space": case "space", "spacebar":
fallthrough
case "spacebar":
key = gocui.KeySpace key = gocui.KeySpace
case "esc": case "esc", "escape":
fallthrough
case "escape":
key = gocui.KeyEsc key = gocui.KeyEsc
case "f1": case "f1":
key = gocui.KeyF1 key = gocui.KeyF1
@ -186,15 +152,9 @@ func (ct *Cointop) ParseKeys(s string) (interface{}, gocui.Modifier) {
key = gocui.KeyF9 key = gocui.KeyF9
case "tab": case "tab":
key = gocui.KeyTab key = gocui.KeyTab
case "pageup": case "pageup", "pgup":
fallthrough
case "pgup":
key = gocui.KeyPgup key = gocui.KeyPgup
case "pagedown": case "pagedown", "pgdown", "pgdn":
fallthrough
case "pgdown":
fallthrough
case "pgdn":
key = gocui.KeyPgdn key = gocui.KeyPgdn
case "home": case "home":
key = gocui.KeyHome key = gocui.KeyHome
@ -248,9 +208,7 @@ func (ct *Cointop) Keybindings(g *gocui.Gui) error {
fn = ct.Keyfn(ct.SortPrevCol) fn = ct.Keyfn(ct.SortPrevCol)
case "sort_right_column": case "sort_right_column":
fn = ct.Keyfn(ct.SortNextCol) fn = ct.Keyfn(ct.SortNextCol)
case "help": case "help", "toggle_show_help":
fallthrough
case "toggle_show_help":
fn = ct.Keyfn(ct.ToggleHelp) fn = ct.Keyfn(ct.ToggleHelp)
view = "" view = ""
case "show_help": case "show_help":
@ -276,7 +234,7 @@ func (ct *Cointop) Keybindings(g *gocui.Gui) error {
case "move_to_page_visible_last_row": case "move_to_page_visible_last_row":
fn = ct.Keyfn(ct.navigatePageLastLine) fn = ct.Keyfn(ct.navigatePageLastLine)
case "sort_column_market_cap": case "sort_column_market_cap":
fn = ct.Sortfn("marketcap", true) fn = ct.Sortfn("market_cap", true)
case "move_to_page_visible_middle_row": case "move_to_page_visible_middle_row":
fn = ct.Keyfn(ct.NavigatePageMiddleLine) fn = ct.Keyfn(ct.NavigatePageMiddleLine)
case "scroll_left": case "scroll_left":

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"math" "math"
"os" "os"
"regexp"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -54,157 +53,195 @@ func (ct *Cointop) GetPortfolioTable() *table.Table {
total := ct.GetPortfolioTotal() total := ct.GetPortfolioTotal()
maxX := ct.width() maxX := ct.width()
t := table.NewTable().SetWidth(maxX) t := table.NewTable().SetWidth(maxX)
var rows [][]*table.RowCell
headers := ct.GetPortfolioTableHeaders()
ct.ClearSyncMap(ct.State.tableColumnWidths)
ct.ClearSyncMap(ct.State.tableColumnAlignLeft)
for _, coin := range ct.State.coins { for _, coin := range ct.State.coins {
star := ct.colorscheme.TableRow(" ") leftMargin := 1
name := TruncateString(coin.Name, 20) rightMargin := 1
symbol := TruncateString(coin.Symbol, 6)
if coin.Favorite {
star = ct.colorscheme.TableRowFavorite("*")
}
rank := fmt.Sprintf("%s%v", star, ct.colorscheme.TableRow(fmt.Sprintf("%6v ", coin.Rank)))
namecolor := ct.colorscheme.TableRow
if coin.Favorite {
namecolor = ct.colorscheme.TableRowFavorite
}
colorbalance := ct.colorscheme.TableColumnPrice
color1h := ct.colorscheme.TableColumnChange
color24h := ct.colorscheme.TableColumnChange
color7d := ct.colorscheme.TableColumnChange
if coin.PercentChange1H > 0 {
color1h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange1H < 0 {
color1h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange24H > 0 {
color24h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
if coin.PercentChange7D > 0 {
color7d = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}
percentHoldings := (coin.Balance / total) * 1e2
if math.IsNaN(percentHoldings) {
percentHoldings = 0
}
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
headers := ct.GetPortfolioTableHeaders()
var rowCells []*table.RowCell var rowCells []*table.RowCell
for _, header := range headers { for _, header := range headers {
switch header { switch header {
case "rank": case "rank":
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)))
ct.SetTableColumnWidth(header, 8)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, &table.RowCell{ rowCells = append(rowCells, &table.RowCell{
LeftMargin: 0, LeftMargin: leftMargin,
Width: 6, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.Default, Color: ct.colorscheme.Default,
Text: rank, Text: rank,
}) })
case "name": case "name":
name := TruncateString(coin.Name, 18)
namecolor := ct.colorscheme.TableRow
if coin.Favorite {
namecolor = ct.colorscheme.TableRowFavorite
}
ct.SetTableColumnWidthFromString(header, name)
ct.SetTableColumnAlignLeft(header, true)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 22, RightMargin: rightMargin,
LeftAlign: true, LeftAlign: true,
Color: namecolor, Color: namecolor,
Text: name, Text: name,
}) })
case "symbol": case "symbol":
symbol := TruncateString(coin.Symbol, 6)
ct.SetTableColumnWidthFromString(header, symbol)
ct.SetTableColumnAlignLeft(header, true)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 6, RightMargin: rightMargin,
LeftAlign: true, LeftAlign: true,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: symbol, Text: symbol,
}) })
case "price": case "price":
text := humanize.Commaf(coin.Price)
symbolPadding := 1
ct.SetTableColumnWidth(header, len(text)+symbolPadding)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 14, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: humanize.Commaf(coin.Price), Text: text,
}) })
case "holdings": case "holdings":
text := strconv.FormatFloat(coin.Holdings, 'f', -1, 64)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 16, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: strconv.FormatFloat(coin.Holdings, 'f', -1, 64), Text: text,
}) })
case "balance": case "balance":
text := humanize.Commaf(coin.Balance)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
colorBalance := ct.colorscheme.TableColumnPrice
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 16, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: colorbalance, Color: colorBalance,
Text: humanize.Commaf(coin.Balance), Text: text,
}) })
case "1h_change": case "1h_change":
color1h := ct.colorscheme.TableColumnChange
if coin.PercentChange1H > 0 {
color1h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange1H < 0 {
color1h = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange1H)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 11, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color1h, Color: color1h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange1H), Text: text,
}) })
case "24h_change": case "24h_change":
color24h := ct.colorscheme.TableColumnChange
if coin.PercentChange24H > 0 {
color24h = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange24H < 0 {
color24h = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange24H)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 10, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color24h, Color: color24h,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange24H), Text: text,
}) })
case "7d_change": case "7d_change":
color7d := ct.colorscheme.TableColumnChange
if coin.PercentChange7D > 0 {
color7d = ct.colorscheme.TableColumnChangeUp
}
if coin.PercentChange7D < 0 {
color7d = ct.colorscheme.TableColumnChangeDown
}
text := fmt.Sprintf("%.2f%%", coin.PercentChange7D)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 10, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: color7d, Color: color7d,
Text: fmt.Sprintf("%.2f%%", coin.PercentChange7D), Text: text,
}) })
case "percent_holdings": case "percent_holdings":
percentHoldings := (coin.Balance / total) * 1e2
if math.IsNaN(percentHoldings) {
percentHoldings = 0
}
text := fmt.Sprintf("%.2f%%", percentHoldings)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 14, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: fmt.Sprintf("%.2f%%", percentHoldings), Text: text,
}) })
case "last_updated": case "last_updated":
unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64)
lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02")
ct.SetTableColumnWidthFromString(header, lastUpdated)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, rowCells = append(rowCells,
&table.RowCell{ &table.RowCell{
LeftMargin: 1, LeftMargin: leftMargin,
Width: 18, RightMargin: rightMargin,
LeftAlign: false, LeftAlign: false,
Color: ct.colorscheme.TableRow, Color: ct.colorscheme.TableRow,
Text: lastUpdated, Text: lastUpdated,
}) })
} }
} }
t.AddRowCells(rowCells...) rows = append(rows, rowCells)
}
for _, row := range rows {
for i, header := range headers {
row[i].Width = ct.GetTableColumnWidth(header)
}
t.AddRowCells(row...)
} }
return t return t
@ -752,14 +789,3 @@ func (ct *Cointop) PrintTotalHoldings(options *TablePrintOptions) error {
func (ct *Cointop) IsPortfolioVisible() bool { func (ct *Cointop) IsPortfolioVisible() bool {
return ct.State.selectedView == PortfolioView return ct.State.selectedView == PortfolioView
} }
// NormalizeFloatString normalizes a float as a string
func normalizeFloatString(input string) string {
re := regexp.MustCompile(`(\d+\.\d+|\.\d+|\d+)`)
result := re.FindStringSubmatch(input)
if len(result) > 0 {
return result[0]
}
return ""
}

@ -45,7 +45,10 @@ func (ct *Cointop) GetPriceAlertsTable() *table.Table {
ct.debuglog("getPriceAlertsTable()") ct.debuglog("getPriceAlertsTable()")
maxX := ct.width() maxX := ct.width()
t := table.NewTable().SetWidth(maxX) t := table.NewTable().SetWidth(maxX)
var rows [][]*table.RowCell
headers := ct.GetPriceAlertsTableHeaders()
ct.ClearSyncMap(ct.State.tableColumnWidths)
ct.ClearSyncMap(ct.State.tableColumnAlignLeft)
for _, entry := range ct.State.priceAlerts.Entries { for _, entry := range ct.State.priceAlerts.Entries {
if entry.Expired { if entry.Expired {
continue continue
@ -58,53 +61,83 @@ func (ct *Cointop) GetPriceAlertsTable() *table.Table {
if !ok { if !ok {
continue continue
} }
name := TruncateString(entry.CoinName, 20)
symbol := TruncateString(coin.Symbol, 6)
namecolor := ct.colorscheme.TableRow
frequency := entry.Frequency
_, ok = PriceAlertOperatorMap[entry.Operator] _, ok = PriceAlertOperatorMap[entry.Operator]
if !ok { if !ok {
continue continue
} }
targetPrice := fmt.Sprintf("%s %s", entry.Operator, humanize.Commaf(entry.TargetPrice))
leftMargin := 1
t.AddRowCells( rightMargin := 1
&table.RowCell{ var rowCells []*table.RowCell
LeftMargin: 1, for _, header := range headers {
Width: 22, switch header {
LeftAlign: true, case "name":
Color: namecolor, name := TruncateString(entry.CoinName, 16)
Text: name, ct.SetTableColumnWidthFromString(header, name)
}, ct.SetTableColumnAlignLeft(header, true)
&table.RowCell{ namecolor := ct.colorscheme.TableRow
LeftMargin: 1, rowCells = append(rowCells, &table.RowCell{
Width: 10, LeftMargin: leftMargin,
LeftAlign: true, RightMargin: rightMargin,
Color: ct.colorscheme.TableRow, LeftAlign: true,
Text: symbol, Color: namecolor,
}, Text: name,
&table.RowCell{ })
LeftMargin: 1, case "symbol":
Width: 14, symbol := TruncateString(coin.Symbol, 6)
LeftAlign: false, ct.SetTableColumnWidthFromString(header, symbol)
Color: ct.colorscheme.TableColumnPrice, ct.SetTableColumnAlignLeft(header, true)
Text: targetPrice, rowCells = append(rowCells, &table.RowCell{
}, LeftMargin: leftMargin,
&table.RowCell{ RightMargin: rightMargin,
LeftMargin: 1, LeftAlign: true,
Width: 11, Color: ct.colorscheme.TableRow,
LeftAlign: false, Text: symbol,
Color: ct.colorscheme.TableRow, })
Text: humanize.Commaf(coin.Price),
}, case "target_price":
&table.RowCell{ targetPrice := fmt.Sprintf("%s %s", entry.Operator, humanize.Commaf(entry.TargetPrice))
LeftMargin: 4, ct.SetTableColumnWidthFromString(header, targetPrice)
Width: 10, ct.SetTableColumnAlignLeft(header, false)
LeftAlign: true, rowCells = append(rowCells, &table.RowCell{
Color: ct.colorscheme.TableRow, LeftMargin: leftMargin,
Text: frequency, RightMargin: rightMargin,
}, LeftAlign: false,
) Color: ct.colorscheme.TableColumnPrice,
Text: targetPrice,
})
case "price":
text := humanize.Commaf(coin.Price)
ct.SetTableColumnWidthFromString(header, text)
ct.SetTableColumnAlignLeft(header, false)
rowCells = append(rowCells, &table.RowCell{
LeftMargin: leftMargin,
RightMargin: rightMargin,
LeftAlign: false,
Color: ct.colorscheme.TableRow,
Text: text,
})
case "frequency":
frequency := entry.Frequency
ct.SetTableColumnWidthFromString(header, frequency)
ct.SetTableColumnAlignLeft(header, true)
rowCells = append(rowCells, &table.RowCell{
LeftMargin: leftMargin,
RightMargin: rightMargin,
LeftAlign: true,
Color: ct.colorscheme.TableRow,
Text: frequency,
})
}
}
rows = append(rows, rowCells)
}
for _, row := range rows {
for i, header := range headers {
row[i].Width = ct.GetTableColumnWidth(header)
}
t.AddRowCells(row...)
} }
return t return t

@ -47,7 +47,7 @@ func (ct *Cointop) Sort(sortBy string, desc bool, list []*Coin, renderHeaders bo
return a.Holdings < b.Holdings return a.Holdings < b.Holdings
case "balance": case "balance":
return a.Balance < b.Balance return a.Balance < b.Balance
case "marketcap": case "market_cap":
return a.MarketCap < b.MarketCap return a.MarketCap < b.MarketCap
case "24h_volume": case "24h_volume":
return a.Volume24H < b.Volume24H return a.Volume24H < b.Volume24H

@ -26,7 +26,7 @@ func TableColumnOrder() []string {
"price", "price",
"holdings", "holdings",
"balance", "balance",
"marketcap", "market_cap",
"24h_volume", "24h_volume",
"1h_change", "1h_change",
"7d_change", "7d_change",

@ -2,11 +2,116 @@ package cointop
import ( import (
"fmt" "fmt"
"math"
"strings" "strings"
"unicode/utf8"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui" "github.com/miguelmota/cointop/pkg/ui"
) )
// ArrowUp is up arrow unicode character
var ArrowUp = "▲"
// ArrowDown is down arrow unicode character
var ArrowDown = "▼"
// HeaderColumn is header column struct
type HeaderColumn struct {
Slug string
Label string
PlainLabel string
}
// HeaderColumns are the header column widths
var HeaderColumns = map[string]*HeaderColumn{
"rank": &HeaderColumn{
Slug: "rank",
Label: "[r]ank",
PlainLabel: "rank",
},
"name": &HeaderColumn{
Slug: "name",
Label: "[n]ame",
PlainLabel: "name",
},
"symbol": &HeaderColumn{
Slug: "symbol",
Label: "[s]ymbol",
PlainLabel: "symbol",
},
"target_price": &HeaderColumn{
Slug: "target_price",
Label: "[t]target price",
PlainLabel: "target price",
},
"price": &HeaderColumn{
Slug: "price",
Label: "[p]rice",
PlainLabel: "price",
},
"frequency": &HeaderColumn{
Slug: "frequency",
Label: "frequency",
PlainLabel: "frequency",
},
"holdings": &HeaderColumn{
Slug: "holdings",
Label: "[h]oldings",
PlainLabel: "holdings",
},
"balance": &HeaderColumn{
Slug: "balance",
Label: "[b]alance",
PlainLabel: "balance",
},
"market_cap": &HeaderColumn{
Slug: "market_cap",
Label: "[m]arket cap",
PlainLabel: "market cap",
},
"24h_volume": &HeaderColumn{
Slug: "24h_volume",
Label: "24H [v]olume",
PlainLabel: "24H volume",
},
"1h_change": &HeaderColumn{
Slug: "1h_change",
Label: "[1]H%",
PlainLabel: "1H%",
},
"24h_change": &HeaderColumn{
Slug: "24h_change",
Label: "[2]4H%",
PlainLabel: "24H%",
},
"7d_change": &HeaderColumn{
Slug: "7d_change",
Label: "[7]D%",
PlainLabel: "7D%",
},
"total_supply": &HeaderColumn{
Slug: "total_supply",
Label: "[t]otal supply",
PlainLabel: "total supply",
},
"available_supply": &HeaderColumn{
Slug: "available_supply",
Label: "[a]vailable supply",
PlainLabel: "available supply",
},
"percent_holdings": &HeaderColumn{
Slug: "percent_holdings",
Label: "[%]holdings",
PlainLabel: "%holdings",
},
"last_updated": &HeaderColumn{
Slug: "last_updated",
Label: "last [u]pdated",
PlainLabel: "last updated",
},
}
// TableHeaderView is structure for table header view // TableHeaderView is structure for table header view
type TableHeaderView = ui.View type TableHeaderView = ui.View
@ -20,56 +125,8 @@ func NewTableHeaderView() *TableHeaderView {
func (ct *Cointop) UpdateTableHeader() error { func (ct *Cointop) UpdateTableHeader() error {
ct.debuglog("UpdateTableHeader()") ct.debuglog("UpdateTableHeader()")
type t struct {
colorfn func(a ...interface{}) string
displaytext string
padleft int
padright int
arrow string
}
baseColor := ct.colorscheme.TableHeaderSprintf() baseColor := ct.colorscheme.TableHeaderSprintf()
offset := 0
lb := "["
rb := "]"
noSort := ct.IsPriceAlertsVisible() noSort := ct.IsPriceAlertsVisible()
if noSort {
offset = 2
lb = ""
rb = ""
}
possibleHeaders := map[string]*t{
"rank": {baseColor, fmt.Sprintf("%sr%sank", lb, rb), 0, 1 + offset, " "},
"name": {baseColor, fmt.Sprintf("%sn%same", lb, rb), 0, 11 + offset, " "},
"symbol": {baseColor, fmt.Sprintf("%ss%symbol", lb, rb), 4, 0 + offset, " "},
"target_price": {baseColor, fmt.Sprintf("%st%sarget price", lb, rb), 2, 0 + offset, " "},
"price": {baseColor, fmt.Sprintf("%sp%srice", lb, rb), 2, 0 + offset, " "},
"frequency": {baseColor, "frequency", 1, 0, " "},
"holdings": {baseColor, fmt.Sprintf("%sh%soldings", lb, rb), 5, 0 + offset, " "},
"balance": {baseColor, fmt.Sprintf("%sb%salance", lb, rb), 5, 0, " "},
"marketcap": {baseColor, fmt.Sprintf("%sm%sarket cap", lb, rb), 5, 0 + offset, " "},
"24h_volume": {baseColor, fmt.Sprintf("24H %sv%solume", lb, rb), 3, 0 + offset, " "},
"1h_change": {baseColor, fmt.Sprintf("%s1%sH%%", lb, rb), 5, 0 + offset, " "},
"24h_change": {baseColor, fmt.Sprintf("%s2%s4H%%", lb, rb), 3, 0 + offset, " "},
"7d_change": {baseColor, fmt.Sprintf("%s7%sD%%", lb, rb), 4, 0 + offset, " "},
"total_supply": {baseColor, fmt.Sprintf("%st%sotal supply", lb, rb), 7, 0 + offset, " "},
"available_supply": {baseColor, fmt.Sprintf("%sa%svailable supply", lb, rb), 1, 0 + offset, " "},
"percent_holdings": {baseColor, fmt.Sprintf("%s%%%sholdings", lb, rb), 2, 0 + offset, " "},
"last_updated": {baseColor, fmt.Sprintf("last %su%spdated", lb, rb), 3, 0, " "},
}
for k := range possibleHeaders {
possibleHeaders[k].arrow = " "
if ct.State.sortBy == k {
possibleHeaders[k].colorfn = ct.colorscheme.TableHeaderColumnActiveSprintf()
if ct.State.sortDesc {
possibleHeaders[k].arrow = "▼"
} else {
possibleHeaders[k].arrow = "▲"
}
}
}
var cols []string var cols []string
switch ct.State.selectedView { switch ct.State.selectedView {
case PortfolioView: case PortfolioView:
@ -81,24 +138,56 @@ func (ct *Cointop) UpdateTableHeader() error {
} }
var headers []string var headers []string
for _, v := range cols { for i, col := range cols {
s, ok := possibleHeaders[v] hc, ok := HeaderColumns[col]
if !ok { if !ok {
continue continue
} }
var str string width := ct.GetTableColumnWidth(col)
d := s.arrow + s.displaytext if width == 0 {
if v == "price" || v == "balance" { continue
d = s.arrow + ct.CurrencySymbol() + s.displaytext
} }
arrow := " "
str = fmt.Sprintf( colorfn := baseColor
if !noSort {
if ct.State.sortBy == col {
colorfn = ct.colorscheme.TableHeaderColumnActiveSprintf()
if ct.State.sortDesc {
arrow = ArrowDown
} else {
arrow = ArrowUp
}
}
}
label := hc.Label
if noSort {
label = hc.PlainLabel
}
leftAlign := ct.GetTableColumnAlignLeft(col)
switch col {
case "price", "balance":
label = ct.CurrencySymbol() + label
}
if leftAlign {
label = label + arrow
} else {
label = arrow + label
}
padfn := pad.Left
padLeft := 1
if !noSort && i == 0 {
padLeft = 0
}
if leftAlign {
padfn = pad.Right
}
colStr := fmt.Sprintf(
"%s%s%s", "%s%s%s",
strings.Repeat(" ", s.padleft), strings.Repeat(" ", padLeft),
s.colorfn(d), colorfn(padfn(label, width+(1-padLeft), " ")),
strings.Repeat(" ", s.padright), strings.Repeat(" ", 1),
) )
headers = append(headers, str) headers = append(headers, colStr)
} }
ct.UpdateUI(func() error { ct.UpdateUI(func() error {
@ -107,3 +196,49 @@ func (ct *Cointop) UpdateTableHeader() error {
return nil return nil
} }
// SetTableColumnAlignLeft sets the column alignment direction for header
func (ct *Cointop) SetTableColumnAlignLeft(header string, alignLeft bool) {
ct.State.tableColumnAlignLeft.Store(header, alignLeft)
}
// GetTableColumnAlignLeft gets the column alignment direction for header
func (ct *Cointop) GetTableColumnAlignLeft(header string) bool {
ifc, ok := ct.State.tableColumnAlignLeft.Load(header)
if ok {
return ifc.(bool)
}
return false
}
// SetTableColumnWidth sets the column width for header
func (ct *Cointop) SetTableColumnWidth(header string, width int) {
prevIfc, ok := ct.State.tableColumnWidths.Load(header)
var prev int
if ok {
prev = prevIfc.(int)
} else {
hc := HeaderColumns[header]
prev = utf8.RuneCountInString(hc.Label) + 1
switch header {
case "price", "balance":
prev++
}
}
ct.State.tableColumnWidths.Store(header, int(math.Max(float64(width), float64(prev))))
}
// SetTableColumnWidthFromString sets the column width for header given size of string
func (ct *Cointop) SetTableColumnWidthFromString(header string, text string) {
ct.SetTableColumnWidth(header, utf8.RuneCountInString(text))
}
// GetTableColumnWidth gets the column width for header
func (ct *Cointop) GetTableColumnWidth(header string) int {
ifc, ok := ct.State.tableColumnWidths.Load(header)
if ok {
return ifc.(int)
}
return 0
}

@ -4,7 +4,9 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"regexp"
"strings" "strings"
"sync"
"github.com/miguelmota/cointop/pkg/open" "github.com/miguelmota/cointop/pkg/open"
) )
@ -41,3 +43,22 @@ func TruncateString(value string, maxLen int) string {
} }
return value return value
} }
// ClearSyncMap clears a sync.Map
func (ct *Cointop) ClearSyncMap(syncMap sync.Map) {
syncMap.Range(func(key interface{}, value interface{}) bool {
syncMap.Delete(key)
return true
})
}
// NormalizeFloatString normalizes a float as a string
func normalizeFloatString(input string) string {
re := regexp.MustCompile(`(\d+\.\d+|\.\d+|\d+)`)
result := re.FindStringSubmatch(input)
if len(result) > 0 {
return result[0]
}
return ""
}

@ -1,5 +1,7 @@
package pad package pad
import "unicode/utf8"
func times(str string, n int) (out string) { func times(str string, n int) (out string) {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
out += str out += str
@ -10,10 +12,10 @@ func times(str string, n int) (out string) {
// Left left-pads the string with pad up to len runes // Left left-pads the string with pad up to len runes
// len may be exceeded if // len may be exceeded if
func Left(str string, length int, pad string) string { func Left(str string, length int, pad string) string {
return times(pad, length-len(str)) + str return times(pad, length-utf8.RuneCountInString(str)) + str
} }
// Right right-pads the string with pad up to len runes // Right right-pads the string with pad up to len runes
func Right(str string, length int, pad string) string { func Right(str string, length int, pad string) string {
return str + times(pad, length-len(str)) return str + times(pad, length-utf8.RuneCountInString(str))
} }

@ -248,20 +248,22 @@ func (t *Table) Fprint(w io.Writer) {
// RowCell is a row cell struct // RowCell is a row cell struct
type RowCell struct { type RowCell struct {
LeftMargin int LeftMargin int
Width int RightMargin int
LeftAlign bool Width int
Color func(a ...interface{}) string LeftAlign bool
Text string Color func(a ...interface{}) string
Text string
} }
// String returns row cell as string // String returns row cell as string
func (rc *RowCell) String() string { func (rc *RowCell) String() string {
t := strings.Repeat(" ", rc.LeftMargin) + rc.Text t := rc.Text
if rc.LeftAlign { if rc.LeftAlign {
t = pad.Right(t, rc.Width, " ") t = pad.Right(t, rc.Width, " ")
} else { } else {
t = fmt.Sprintf("%"+fmt.Sprintf("%v", rc.Width)+"s", t) t = fmt.Sprintf("%"+fmt.Sprintf("%v", rc.Width)+"s", t)
} }
t = strings.Repeat(" ", rc.LeftMargin) + t + strings.Repeat(" ", rc.RightMargin)
return rc.Color(t) return rc.Color(t)
} }

Loading…
Cancel
Save