mirror of
https://github.com/miguelmota/cointop
synced 2024-11-10 13:10:26 +00:00
save config shortcut
Former-commit-id: da4ed457483f8e2f81bfcaf4adf7f735af7a773c [formerly da4ed457483f8e2f81bfcaf4adf7f735af7a773c [formerly 9053a0ca313c2bfc1af7f2e23be70ff7201b66a5 [formerly 0fc35046d8bf4af9d727e528aec25a6abe75bef8]]] Former-commit-id: 5e93a7a2b94a72c66d093ec6eeb6ca43627fa37b Former-commit-id: 958cf0dc53eab6eac4739d8735c3fc85fa32acdc [formerly 18fb23615a48126f1c1299ef558aa3492736eab6] Former-commit-id: 4dc280d3c2251611b2a03abd14c4b4172b1ab016
This commit is contained in:
parent
7af2fb98fd
commit
a77b73b597
30
README.md
30
README.md
@ -22,12 +22,13 @@
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Quick sort shortcuts
|
- Quick sort shortcuts
|
||||||
|
- Custom key bindings config
|
||||||
- Vim style keys
|
- Vim style keys
|
||||||
- Pagination
|
- Fast pagination
|
||||||
- 7 day charts
|
- 7 day charts for coins and global market graphs
|
||||||
- Fuzzy Searching
|
- Fuzzy Searching (name/symbol) for finding coins
|
||||||
- Custom key bindings
|
- Save and view favorite coins
|
||||||
- Color coded
|
- Color coding
|
||||||
- Works on macOS, Linux, and Windows
|
- Works on macOS, Linux, and Windows
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
@ -90,14 +91,15 @@ Key|Action
|
|||||||
<kbd>Page Down</kbd>|Jump page down
|
<kbd>Page Down</kbd>|Jump page down
|
||||||
<kbd>Home</kbd>|Go to first line of page
|
<kbd>Home</kbd>|Go to first line of page
|
||||||
<kbd>End</kbd>|Go to last line of page
|
<kbd>End</kbd>|Go to last line of page
|
||||||
<kbd>Enter</kbd>|Visit highlighted coin on [CoinMarketCap](https://coinmarketcap.com/)
|
<kbd>Enter</kbd>|Toggle [c]hart for highlighted coin
|
||||||
<kbd>Esc</kbd>|Alias to quit
|
<kbd>Esc</kbd>|Quit
|
||||||
<kbd>Space</kbd>|Alias to enter key
|
<kbd>Space</kbd>|Toggle coin as favorite
|
||||||
<kbd>Ctrl</kbd>+<kbd>c</kbd>|Alias to quit
|
<kbd>Ctrl</kbd>+<kbd>c</kbd>|Alias to quit
|
||||||
<kbd>Ctrl</kbd>+<kbd>d</kbd>|Jump page down (vim style)
|
<kbd>Ctrl</kbd>+<kbd>d</kbd>|Jump page down (vim style)
|
||||||
<kbd>Ctrl</kbd>+<kbd>n</kbd>|Go to next page
|
<kbd>Ctrl</kbd>+<kbd>n</kbd>|Go to next page
|
||||||
<kbd>Ctrl</kbd>+<kbd>p</kbd>|Go to previous page
|
<kbd>Ctrl</kbd>+<kbd>p</kbd>|Go to previous page
|
||||||
<kbd>Ctrl</kbd>+<kbd>r</kbd>|Force refresh
|
<kbd>Ctrl</kbd>+<kbd>r</kbd>|Force refresh
|
||||||
|
<kbd>Ctrl</kbd>+<kbd>s</kbd>|Save config
|
||||||
<kbd>Ctrl</kbd>+<kbd>u</kbd>|Jump page up (vim style)
|
<kbd>Ctrl</kbd>+<kbd>u</kbd>|Jump page up (vim style)
|
||||||
<kbd>Alt</kbd>+<kbd>↑</kbd>|Sort current column in ascending order
|
<kbd>Alt</kbd>+<kbd>↑</kbd>|Sort current column in ascending order
|
||||||
<kbd>Alt</kbd>+<kbd>↓</kbd>|Sort current column in descending order
|
<kbd>Alt</kbd>+<kbd>↓</kbd>|Sort current column in descending order
|
||||||
@ -110,6 +112,7 @@ Key|Action
|
|||||||
<kbd>7</kbd>|Sort table by *[7] day change*
|
<kbd>7</kbd>|Sort table by *[7] day change*
|
||||||
<kbd>a</kbd>|Sort table by *[a]vailable supply*
|
<kbd>a</kbd>|Sort table by *[a]vailable supply*
|
||||||
<kbd>c</kbd>|Toggle [c]hart for highlighted coin
|
<kbd>c</kbd>|Toggle [c]hart for highlighted coin
|
||||||
|
<kbd>f</kbd>|Toggle show favorites
|
||||||
<kbd>g</kbd>|Go to first line of page (vim style)
|
<kbd>g</kbd>|Go to first line of page (vim style)
|
||||||
<kbd>G</kbd>|Go to last line of page (vim style)
|
<kbd>G</kbd>|Go to last line of page (vim style)
|
||||||
<kbd>h</kbd>|Go to previous page (vim style)
|
<kbd>h</kbd>|Go to previous page (vim style)
|
||||||
@ -121,7 +124,7 @@ Key|Action
|
|||||||
<kbd>m</kbd>|Sort table by *[m]arket cap*
|
<kbd>m</kbd>|Sort table by *[m]arket cap*
|
||||||
<kbd>M</kbd>|Go to middle of visible table window (vim style)
|
<kbd>M</kbd>|Go to middle of visible table window (vim style)
|
||||||
<kbd>n</kbd>|Sort table by *[n]ame*
|
<kbd>n</kbd>|Sort table by *[n]ame*
|
||||||
<kbd>o</kbd>|[o]pen row link
|
<kbd>o</kbd>|[o]pen link to highlighted coin on [CoinMarketCap](https://coinmarketcap.com/)
|
||||||
<kbd>p</kbd>|Sort table by *[p]rice*
|
<kbd>p</kbd>|Sort table by *[p]rice*
|
||||||
<kbd>r</kbd>|Sort table by *[r]ank*
|
<kbd>r</kbd>|Sort table by *[r]ank*
|
||||||
<kbd>s</kbd>|Sort table by *[s]ymbol*
|
<kbd>s</kbd>|Sort table by *[s]ymbol*
|
||||||
@ -173,10 +176,12 @@ You can then configure the actions you want for each key:
|
|||||||
"ctrl+n" = "next_page"
|
"ctrl+n" = "next_page"
|
||||||
"ctrl+p" = "previous_page"
|
"ctrl+p" = "previous_page"
|
||||||
"ctrl+r" = "refresh"
|
"ctrl+r" = "refresh"
|
||||||
|
"ctrl+s" = "save"
|
||||||
"ctrl+u" = "page_up"
|
"ctrl+u" = "page_up"
|
||||||
end = "move_to_page_last_row"
|
end = "move_to_page_last_row"
|
||||||
enter = "open_link"
|
enter = "toggle_row_chart"
|
||||||
esc = "quit"
|
esc = "quit"
|
||||||
|
f = "toggle_show_favorites"
|
||||||
F1 = "help"
|
F1 = "help"
|
||||||
g = "move_to_page_first_row"
|
g = "move_to_page_first_row"
|
||||||
h = "previous_page"
|
h = "previous_page"
|
||||||
@ -193,7 +198,7 @@ You can then configure the actions you want for each key:
|
|||||||
q = "quit"
|
q = "quit"
|
||||||
r = "sort_column_rank"
|
r = "sort_column_rank"
|
||||||
s = "sort_column_symbol"
|
s = "sort_column_symbol"
|
||||||
space = "open_link"
|
space = "toggle_favorite"
|
||||||
t = "sort_column_total_supply"
|
t = "sort_column_total_supply"
|
||||||
u = "sort_column_last_updated"
|
u = "sort_column_last_updated"
|
||||||
v = "sort_column_24h_volume"
|
v = "sort_column_24h_volume"
|
||||||
@ -238,6 +243,9 @@ Action|Description
|
|||||||
`sort_left_column`|Sort the column to the left of the highlighted column
|
`sort_left_column`|Sort the column to the left of the highlighted column
|
||||||
`sort_right_column`|Sort the column to the right of the highlighted column
|
`sort_right_column`|Sort the column to the right of the highlighted column
|
||||||
`toggle_row_chart`|Toggle the chart for the highlighted row
|
`toggle_row_chart`|Toggle the chart for the highlighted row
|
||||||
|
`toggle_favorite`|Toggle coin as favorite
|
||||||
|
`toggle_show_favorites`|Toggle show favorites
|
||||||
|
`save`|Save config
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ type Cointop struct {
|
|||||||
searchfield *gocui.View
|
searchfield *gocui.View
|
||||||
favorites map[string]bool
|
favorites map[string]bool
|
||||||
filterByFavorites bool
|
filterByFavorites bool
|
||||||
|
savemux sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs cointop
|
// Run runs cointop
|
||||||
@ -53,6 +54,7 @@ func Run() {
|
|||||||
forcerefresh: make(chan bool),
|
forcerefresh: make(chan bool),
|
||||||
maxtablewidth: 175,
|
maxtablewidth: 175,
|
||||||
shortcutkeys: defaultShortcuts(),
|
shortcutkeys: defaultShortcuts(),
|
||||||
|
favorites: map[string]bool{},
|
||||||
}
|
}
|
||||||
err := ct.setupConfig()
|
err := ct.setupConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -11,7 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Shortcuts map[string]interface{} `toml:"shortcuts"`
|
Shortcuts map[string]interface{} `toml:"shortcuts"`
|
||||||
|
Favorites map[string][]interface{} `toml:"favorites"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ct *Cointop) setupConfig() error {
|
func (ct *Cointop) setupConfig() error {
|
||||||
@ -31,6 +32,24 @@ func (ct *Cointop) setupConfig() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = ct.loadFavoritesFromConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) loadFavoritesFromConfig() error {
|
||||||
|
for k, arr := range ct.config.Favorites {
|
||||||
|
if k == "symbols" {
|
||||||
|
for _, ifc := range arr {
|
||||||
|
v, ok := ifc.(string)
|
||||||
|
if ok {
|
||||||
|
ct.favorites[strings.ToUpper(v)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +93,24 @@ func (ct *Cointop) makeConfigFile() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) saveConfig() error {
|
||||||
|
ct.savemux.Lock()
|
||||||
|
defer ct.savemux.Unlock()
|
||||||
|
path := ct.configPath()
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
fo, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
|
||||||
|
defer fo.Close()
|
||||||
|
b, err := ct.configToToml()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := fo.Write(b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ct *Cointop) parseConfig() error {
|
func (ct *Cointop) parseConfig() error {
|
||||||
var conf config
|
var conf config
|
||||||
path := ct.configPath()
|
path := ct.configPath()
|
||||||
@ -86,14 +123,26 @@ func (ct *Cointop) parseConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ct *Cointop) configToToml() ([]byte, error) {
|
func (ct *Cointop) configToToml() ([]byte, error) {
|
||||||
s := defaultShortcuts()
|
shortcutsIfcs := map[string]interface{}{}
|
||||||
ifcs := map[string]interface{}{}
|
for k, v := range ct.shortcutkeys {
|
||||||
for k, v := range s {
|
|
||||||
var i interface{} = v
|
var i interface{} = v
|
||||||
ifcs[k] = i
|
shortcutsIfcs[k] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var favorites []interface{}
|
||||||
|
for k, ok := range ct.favorites {
|
||||||
|
if ok {
|
||||||
|
var i interface{} = strings.ToUpper(k)
|
||||||
|
favorites = append(favorites, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
favoritesIfcs := map[string][]interface{}{
|
||||||
|
"symbols": favorites,
|
||||||
|
}
|
||||||
|
|
||||||
var inputs = &config{
|
var inputs = &config{
|
||||||
Shortcuts: ifcs,
|
Shortcuts: shortcutsIfcs,
|
||||||
|
Favorites: favoritesIfcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
package cointop
|
package cointop
|
||||||
|
|
||||||
|
func (ct *Cointop) toggleFavorite() error {
|
||||||
|
coin := ct.highlightedRowCoin()
|
||||||
|
if coin == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, ok := ct.favorites[coin.Symbol]
|
||||||
|
if ok {
|
||||||
|
delete(ct.favorites, coin.Symbol)
|
||||||
|
coin.Favorite = false
|
||||||
|
} else {
|
||||||
|
ct.favorites[coin.Symbol] = true
|
||||||
|
coin.Favorite = true
|
||||||
|
}
|
||||||
|
ct.updateTable()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ct *Cointop) toggleShowFavorites() error {
|
func (ct *Cointop) toggleShowFavorites() error {
|
||||||
ct.filterByFavorites = !ct.filterByFavorites
|
ct.filterByFavorites = !ct.filterByFavorites
|
||||||
ct.updateTable()
|
ct.updateTable()
|
||||||
|
@ -264,8 +264,12 @@ func (ct *Cointop) keybindings(g *gocui.Gui) error {
|
|||||||
case "open_search":
|
case "open_search":
|
||||||
fn = ct.keyfn(ct.openSearch)
|
fn = ct.keyfn(ct.openSearch)
|
||||||
view = ""
|
view = ""
|
||||||
case "show_favorites":
|
case "toggle_favorite":
|
||||||
|
fn = ct.keyfn(ct.toggleFavorite)
|
||||||
|
case "toggle_show_favorites":
|
||||||
fn = ct.keyfn(ct.toggleShowFavorites)
|
fn = ct.keyfn(ct.toggleShowFavorites)
|
||||||
|
case "save":
|
||||||
|
fn = ct.keyfn(ct.save)
|
||||||
case "quit":
|
case "quit":
|
||||||
fn = ct.keyfn(ct.quit)
|
fn = ct.keyfn(ct.quit)
|
||||||
view = ""
|
view = ""
|
||||||
|
@ -12,12 +12,12 @@ func (ct *Cointop) refresh() error {
|
|||||||
|
|
||||||
func (ct *Cointop) refreshAll() error {
|
func (ct *Cointop) refreshAll() error {
|
||||||
ct.refreshmux.Lock()
|
ct.refreshmux.Lock()
|
||||||
|
defer ct.refreshmux.Unlock()
|
||||||
ct.setRefreshStatus()
|
ct.setRefreshStatus()
|
||||||
ct.updateCoins()
|
ct.updateCoins()
|
||||||
ct.updateTable()
|
ct.updateTable()
|
||||||
ct.updateMarketbar()
|
ct.updateMarketbar()
|
||||||
ct.updateChart()
|
ct.updateChart()
|
||||||
ct.refreshmux.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
cointop/save.go
Normal file
15
cointop/save.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package cointop
|
||||||
|
|
||||||
|
func (ct *Cointop) save() error {
|
||||||
|
ct.setSavingStatus()
|
||||||
|
ct.saveConfig()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *Cointop) setSavingStatus() {
|
||||||
|
go func() {
|
||||||
|
ct.loadingTicks("saving", 900)
|
||||||
|
ct.updateStatusbar("")
|
||||||
|
ct.rowChanged()
|
||||||
|
}()
|
||||||
|
}
|
@ -37,7 +37,8 @@ func actionsMap() map[string]bool {
|
|||||||
"sort_right_column": true,
|
"sort_right_column": true,
|
||||||
"toggle_row_chart": true,
|
"toggle_row_chart": true,
|
||||||
"open_search": true,
|
"open_search": true,
|
||||||
"show_favorites": true,
|
"toggle_favorite": true,
|
||||||
|
"toggle_show_favorites": true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +52,15 @@ func defaultShortcuts() map[string]string {
|
|||||||
"pageup": "page_up",
|
"pageup": "page_up",
|
||||||
"home": "move_to_page_first_row",
|
"home": "move_to_page_first_row",
|
||||||
"end": "move_to_page_last_row",
|
"end": "move_to_page_last_row",
|
||||||
"enter": "open_link",
|
"enter": "toggle_row_chart",
|
||||||
"esc": "quit",
|
"esc": "quit",
|
||||||
"space": "open_link",
|
"space": "toggle_favorite",
|
||||||
"ctrl+c": "quit",
|
"ctrl+c": "quit",
|
||||||
"ctrl+d": "page_down",
|
"ctrl+d": "page_down",
|
||||||
"ctrl+n": "next_page",
|
"ctrl+n": "next_page",
|
||||||
"ctrl+p": "previous_page",
|
"ctrl+p": "previous_page",
|
||||||
"ctrl+r": "refresh",
|
"ctrl+r": "refresh",
|
||||||
|
"ctrl+s": "save",
|
||||||
"ctrl+u": "page_up",
|
"ctrl+u": "page_up",
|
||||||
"alt+up": "sort_column_asc",
|
"alt+up": "sort_column_asc",
|
||||||
"alt+down": "sort_column_desc",
|
"alt+down": "sort_column_desc",
|
||||||
@ -71,7 +73,7 @@ func defaultShortcuts() map[string]string {
|
|||||||
"7": "sort_column_7d_change",
|
"7": "sort_column_7d_change",
|
||||||
"a": "sort_column_available_supply",
|
"a": "sort_column_available_supply",
|
||||||
"c": "toggle_row_chart",
|
"c": "toggle_row_chart",
|
||||||
"f": "show_favorites",
|
"f": "toggle_show_favorites",
|
||||||
"g": "move_to_page_first_row",
|
"g": "move_to_page_first_row",
|
||||||
"G": "move_to_page_last_row",
|
"G": "move_to_page_last_row",
|
||||||
"h": "previous_page",
|
"h": "previous_page",
|
||||||
|
@ -18,5 +18,5 @@ func (ct *Cointop) updateStatusbar(s string) {
|
|||||||
|
|
||||||
func (ct *Cointop) refreshRowLink() {
|
func (ct *Cointop) refreshRowLink() {
|
||||||
url := ct.rowLink()
|
url := ct.rowLink()
|
||||||
ct.updateStatusbar(fmt.Sprintf("[↵]%s", url))
|
ct.updateStatusbar(fmt.Sprintf("[o]pen %s", url))
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,15 @@ func (ct *Cointop) refreshTable() error {
|
|||||||
color7d = color.Red
|
color7d = color.Red
|
||||||
}
|
}
|
||||||
name := coin.Name
|
name := coin.Name
|
||||||
|
dots := "..."
|
||||||
|
if coin.Favorite {
|
||||||
|
dots = "..*"
|
||||||
|
name = fmt.Sprintf("%s*", name)
|
||||||
|
}
|
||||||
lastchar := len(name)
|
lastchar := len(name)
|
||||||
if lastchar > 20 {
|
if lastchar > 20 {
|
||||||
lastchar = 20
|
lastchar = 20
|
||||||
name = fmt.Sprintf("%s...", name[0:18])
|
name = fmt.Sprintf("%s%s", name[0:18], dots)
|
||||||
}
|
}
|
||||||
ct.table.AddRow(
|
ct.table.AddRow(
|
||||||
color.White(fmt.Sprintf("%7v ", coin.Rank)),
|
color.White(fmt.Sprintf("%7v ", coin.Rank)),
|
||||||
|
@ -9,6 +9,7 @@ var possibleCmds = []string{
|
|||||||
"xdg-open", // linux
|
"xdg-open", // linux
|
||||||
"open", // mac
|
"open", // mac
|
||||||
"start", // windows?
|
"start", // windows?
|
||||||
|
"cygstart", // windows?
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
Loading…
Reference in New Issue
Block a user