diff --git a/README.md b/README.md index 717b74f..6a45828 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,13 @@ ## Features - Quick sort shortcuts +- Custom key bindings config - Vim style keys -- Pagination -- 7 day charts -- Fuzzy Searching -- Custom key bindings -- Color coded +- Fast pagination +- 7 day charts for coins and global market graphs +- Fuzzy Searching (name/symbol) for finding coins +- Save and view favorite coins +- Color coding - Works on macOS, Linux, and Windows ## Installing @@ -90,14 +91,15 @@ Key|Action Page Down|Jump page down Home|Go to first line of page End|Go to last line of page -Enter|Visit highlighted coin on [CoinMarketCap](https://coinmarketcap.com/) -Esc|Alias to quit -Space|Alias to enter key +Enter|Toggle [c]hart for highlighted coin +Esc|Quit +Space|Toggle coin as favorite Ctrl+c|Alias to quit Ctrl+d|Jump page down (vim style) Ctrl+n|Go to next page Ctrl+p|Go to previous page Ctrl+r|Force refresh +Ctrl+s|Save config Ctrl+u|Jump page up (vim style) Alt+|Sort current column in ascending order Alt+|Sort current column in descending order @@ -110,6 +112,7 @@ Key|Action 7|Sort table by *[7] day change* a|Sort table by *[a]vailable supply* c|Toggle [c]hart for highlighted coin +f|Toggle show favorites g|Go to first line of page (vim style) G|Go to last line of page (vim style) h|Go to previous page (vim style) @@ -121,7 +124,7 @@ Key|Action m|Sort table by *[m]arket cap* M|Go to middle of visible table window (vim style) n|Sort table by *[n]ame* -o|[o]pen row link +o|[o]pen link to highlighted coin on [CoinMarketCap](https://coinmarketcap.com/) p|Sort table by *[p]rice* r|Sort table by *[r]ank* s|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+p" = "previous_page" "ctrl+r" = "refresh" + "ctrl+s" = "save" "ctrl+u" = "page_up" end = "move_to_page_last_row" - enter = "open_link" + enter = "toggle_row_chart" esc = "quit" + f = "toggle_show_favorites" F1 = "help" g = "move_to_page_first_row" h = "previous_page" @@ -193,7 +198,7 @@ You can then configure the actions you want for each key: q = "quit" r = "sort_column_rank" s = "sort_column_symbol" - space = "open_link" + space = "toggle_favorite" t = "sort_column_total_supply" u = "sort_column_last_updated" 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_right_column`|Sort the column to the right of the highlighted column `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 diff --git a/cointop/cointop.go b/cointop/cointop.go index 9fbbe08..b75d4dc 100644 --- a/cointop/cointop.go +++ b/cointop/cointop.go @@ -39,6 +39,7 @@ type Cointop struct { searchfield *gocui.View favorites map[string]bool filterByFavorites bool + savemux sync.Mutex } // Run runs cointop @@ -53,6 +54,7 @@ func Run() { forcerefresh: make(chan bool), maxtablewidth: 175, shortcutkeys: defaultShortcuts(), + favorites: map[string]bool{}, } err := ct.setupConfig() if err != nil { diff --git a/cointop/config.go b/cointop/config.go index d58985a..4e8db2e 100644 --- a/cointop/config.go +++ b/cointop/config.go @@ -11,7 +11,8 @@ import ( ) 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 { @@ -31,6 +32,24 @@ func (ct *Cointop) setupConfig() error { if err != nil { 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 } @@ -74,6 +93,24 @@ func (ct *Cointop) makeConfigFile() error { 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 { var conf config path := ct.configPath() @@ -86,14 +123,26 @@ func (ct *Cointop) parseConfig() error { } func (ct *Cointop) configToToml() ([]byte, error) { - s := defaultShortcuts() - ifcs := map[string]interface{}{} - for k, v := range s { + shortcutsIfcs := map[string]interface{}{} + for k, v := range ct.shortcutkeys { 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{ - Shortcuts: ifcs, + Shortcuts: shortcutsIfcs, + Favorites: favoritesIfcs, } var b bytes.Buffer diff --git a/cointop/favorites.go b/cointop/favorites.go index 4ce47fd..ac5f847 100644 --- a/cointop/favorites.go +++ b/cointop/favorites.go @@ -1,5 +1,22 @@ 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 { ct.filterByFavorites = !ct.filterByFavorites ct.updateTable() diff --git a/cointop/keybindings.go b/cointop/keybindings.go index 13ea444..0235510 100644 --- a/cointop/keybindings.go +++ b/cointop/keybindings.go @@ -264,8 +264,12 @@ func (ct *Cointop) keybindings(g *gocui.Gui) error { case "open_search": fn = ct.keyfn(ct.openSearch) view = "" - case "show_favorites": + case "toggle_favorite": + fn = ct.keyfn(ct.toggleFavorite) + case "toggle_show_favorites": fn = ct.keyfn(ct.toggleShowFavorites) + case "save": + fn = ct.keyfn(ct.save) case "quit": fn = ct.keyfn(ct.quit) view = "" diff --git a/cointop/refresh.go b/cointop/refresh.go index c1da215..b0d4dbb 100644 --- a/cointop/refresh.go +++ b/cointop/refresh.go @@ -12,12 +12,12 @@ func (ct *Cointop) refresh() error { func (ct *Cointop) refreshAll() error { ct.refreshmux.Lock() + defer ct.refreshmux.Unlock() ct.setRefreshStatus() ct.updateCoins() ct.updateTable() ct.updateMarketbar() ct.updateChart() - ct.refreshmux.Unlock() return nil } diff --git a/cointop/save.go b/cointop/save.go new file mode 100644 index 0000000..3967656 --- /dev/null +++ b/cointop/save.go @@ -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() + }() +} diff --git a/cointop/shortcuts.go b/cointop/shortcuts.go index dd25f19..576a20b 100644 --- a/cointop/shortcuts.go +++ b/cointop/shortcuts.go @@ -37,7 +37,8 @@ func actionsMap() map[string]bool { "sort_right_column": true, "toggle_row_chart": 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", "home": "move_to_page_first_row", "end": "move_to_page_last_row", - "enter": "open_link", + "enter": "toggle_row_chart", "esc": "quit", - "space": "open_link", + "space": "toggle_favorite", "ctrl+c": "quit", "ctrl+d": "page_down", "ctrl+n": "next_page", "ctrl+p": "previous_page", "ctrl+r": "refresh", + "ctrl+s": "save", "ctrl+u": "page_up", "alt+up": "sort_column_asc", "alt+down": "sort_column_desc", @@ -71,7 +73,7 @@ func defaultShortcuts() map[string]string { "7": "sort_column_7d_change", "a": "sort_column_available_supply", "c": "toggle_row_chart", - "f": "show_favorites", + "f": "toggle_show_favorites", "g": "move_to_page_first_row", "G": "move_to_page_last_row", "h": "previous_page", diff --git a/cointop/statusbar.go b/cointop/statusbar.go index 2b84e99..c6b8787 100644 --- a/cointop/statusbar.go +++ b/cointop/statusbar.go @@ -18,5 +18,5 @@ func (ct *Cointop) updateStatusbar(s string) { func (ct *Cointop) refreshRowLink() { url := ct.rowLink() - ct.updateStatusbar(fmt.Sprintf("[↵]%s", url)) + ct.updateStatusbar(fmt.Sprintf("[o]pen %s", url)) } diff --git a/cointop/table.go b/cointop/table.go index 3c84efb..6739a2b 100644 --- a/cointop/table.go +++ b/cointop/table.go @@ -58,10 +58,15 @@ func (ct *Cointop) refreshTable() error { color7d = color.Red } name := coin.Name + dots := "..." + if coin.Favorite { + dots = "..*" + name = fmt.Sprintf("%s*", name) + } lastchar := len(name) if lastchar > 20 { lastchar = 20 - name = fmt.Sprintf("%s...", name[0:18]) + name = fmt.Sprintf("%s%s", name[0:18], dots) } ct.table.AddRow( color.White(fmt.Sprintf("%7v ", coin.Rank)), diff --git a/pkg/open/open.go b/pkg/open/open.go index 41523c6..6b182da 100644 --- a/pkg/open/open.go +++ b/pkg/open/open.go @@ -9,6 +9,7 @@ var possibleCmds = []string{ "xdg-open", // linux "open", // mac "start", // windows? + "cygstart", // windows? } func init() {