Add sementic colors for time, header and "default"

master
joce 3 years ago
parent b45fbfe908
commit 3df70dc52c
  1. 2
      cmd/mop/main.go
  2. 12
      layout.go
  3. 20
      markup.go
  4. 84
      profile.go
  5. 25
      screen.go

@ -143,5 +143,5 @@ func main() {
defer screen.Close() defer screen.Close()
mainLoop(screen, profile) mainLoop(screen, profile)
profile.Save() profile.Save()
} }

@ -168,7 +168,7 @@ func (layout *Layout) prettify(quotes *Quotes) []Stock {
profile := quotes.profile profile := quotes.profile
if profile.Filter != ""{ // Fix for blank display if invalid filter expression was cleared. if profile.Filter != "" { // Fix for blank display if invalid filter expression was cleared.
if profile.filterExpression != nil { if profile.filterExpression != nil {
if layout.filter == nil { // Initialize filter on first invocation. if layout.filter == nil { // Initialize filter on first invocation.
layout.filter = NewFilter(profile) layout.filter = NewFilter(profile)
@ -218,11 +218,11 @@ func buildMarketTemplate() *template.Template {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func buildQuotesTemplate() *template.Template { func buildQuotesTemplate() *template.Template {
markup := `<right><white>{{.Now}}</></right> markup := `<right><time>{{.Now}}</></right>
{{.Header}} <header>{{.Header}}</>
{{range.Stocks}}{{if eq .Direction 1}}<gain>{{else if eq .Direction -1}}<loss>{{end}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePct}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}}{{.PreOpen}}{{.AfterHours}}</> {{range.Stocks}}{{if eq .Direction 1}}<gain>{{else if eq .Direction -1}}<loss>{{end}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePct}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}}{{.PreOpen}}{{.AfterHours}}</>
{{end}}` {{end}}`
@ -234,7 +234,7 @@ func highlight(collections ...map[string]string) {
for _, collection := range collections { for _, collection := range collections {
change := collection[`change`] change := collection[`change`]
if change[len(change)-1:] == `%` { if change[len(change)-1:] == `%` {
change = change[0:len(change)-1] change = change[0 : len(change)-1]
} }
adv, err := strconv.ParseFloat(change, 64) adv, err := strconv.ParseFloat(change, 64)
if err == nil { if err == nil {
@ -272,9 +272,9 @@ func group(stocks []Stock) []Stock {
func arrowFor(column int, profile *Profile) string { func arrowFor(column int, profile *Profile) string {
if column == profile.SortColumn { if column == profile.SortColumn {
if profile.Ascending { if profile.Ascending {
return string('\U00002191') return string('')
} }
return string('\U00002193') return string('')
} }
return `` return ``
} }

@ -5,9 +5,10 @@
package mop package mop
import ( import (
`github.com/nsf/termbox-go` "regexp"
`regexp` "strings"
`strings`
"github.com/nsf/termbox-go"
) )
// Markup implements some minimalistic text formatting conventions that // Markup implements some minimalistic text formatting conventions that
@ -35,9 +36,6 @@ type Markup struct {
// colors and column alignments. // colors and column alignments.
func NewMarkup(profile *Profile) *Markup { func NewMarkup(profile *Profile) *Markup {
markup := &Markup{} markup := &Markup{}
markup.Foreground = termbox.ColorDefault
markup.Background = termbox.ColorDefault
markup.RightAligned = false
markup.tags = make(map[string]termbox.Attribute) markup.tags = make(map[string]termbox.Attribute)
markup.tags[`/`] = termbox.ColorDefault markup.tags[`/`] = termbox.ColorDefault
@ -67,6 +65,14 @@ func NewMarkup(profile *Profile) *Markup {
markup.tags[`gain`] = markup.tags[profile.Colors.Gain] markup.tags[`gain`] = markup.tags[profile.Colors.Gain]
markup.tags[`loss`] = markup.tags[profile.Colors.Loss] markup.tags[`loss`] = markup.tags[profile.Colors.Loss]
markup.tags[`tag`] = markup.tags[profile.Colors.Tag] markup.tags[`tag`] = markup.tags[profile.Colors.Tag]
markup.tags[`header`] = markup.tags[profile.Colors.Header]
markup.tags[`time`] = markup.tags[profile.Colors.Time]
markup.tags[`default`] = markup.tags[profile.Colors.Default]
markup.Foreground = markup.tags[profile.Colors.Default]
markup.Background = termbox.ColorDefault
markup.RightAligned = false
markup.regex = markup.supportedTags() // Once we have the hash we could build the regex. markup.regex = markup.supportedTags() // Once we have the hash we could build the regex.
@ -138,7 +144,7 @@ func (markup *Markup) process(tag string, open bool) bool {
if attribute >= termbox.AttrBold { if attribute >= termbox.AttrBold {
markup.Foreground &= ^attribute // Clear the Termbox attribute. markup.Foreground &= ^attribute // Clear the Termbox attribute.
} else { } else {
markup.Foreground = termbox.ColorDefault markup.Foreground = markup.tags[`default`]
} }
} }
} }

@ -16,22 +16,28 @@ import (
const defaultGainColor = "green" const defaultGainColor = "green"
const defaultLossColor = "red" const defaultLossColor = "red"
const defaultTagColor = "yellow" const defaultTagColor = "yellow"
const defaultHeaderColor = "lightgray"
const defaultTimeColor = "lightgray"
const defaultColor = "lightgray"
// Profile manages Mop program settings as defined by user (ex. list of // Profile manages Mop program settings as defined by user (ex. list of
// stock tickers). The settings are serialized using JSON and saved in // stock tickers). The settings are serialized using JSON and saved in
// the ~/.moprc file. // the ~/.moprc file.
type Profile struct { type Profile struct {
Tickers []string // List of stock tickers to display. Tickers []string // List of stock tickers to display.
MarketRefresh int // Time interval to refresh market data. MarketRefresh int // Time interval to refresh market data.
QuotesRefresh int // Time interval to refresh stock quotes. QuotesRefresh int // Time interval to refresh stock quotes.
SortColumn int // Column number by which we sort stock quotes. SortColumn int // Column number by which we sort stock quotes.
Ascending bool // True when sort order is ascending. Ascending bool // True when sort order is ascending.
Grouped bool // True when stocks are grouped by advancing/declining. Grouped bool // True when stocks are grouped by advancing/declining.
Filter string // Filter in human form Filter string // Filter in human form
Colors struct { // User defined colors Colors struct { // User defined colors
Gain string Gain string
Loss string Loss string
Tag string Tag string
Header string
Time string
Default string
} }
filterExpression *govaluate.EvaluableExpression // The filter as a govaluate expression filterExpression *govaluate.EvaluableExpression // The filter as a govaluate expression
selectedColumn int // Stores selected column number when the column editor is active. selectedColumn int // Stores selected column number when the column editor is active.
@ -40,24 +46,24 @@ type Profile struct {
func IsSupportedColor(colorName string) bool { func IsSupportedColor(colorName string) bool {
switch colorName { switch colorName {
case case
"black", "black",
"red", "red",
"green", "green",
"yellow", "yellow",
"blue", "blue",
"magenta", "magenta",
"cyan", "cyan",
"white", "white",
"darkgray", "darkgray",
"lightred", "lightred",
"lightgreen", "lightgreen",
"lightyellow", "lightyellow",
"lightblue", "lightblue",
"lightmagenta", "lightmagenta",
"lightcyan", "lightcyan",
"lightgray": "lightgray":
return true return true
} }
return false return false
} }
@ -78,13 +84,19 @@ func NewProfile(filename string) *Profile {
profile.Colors.Gain = defaultGainColor profile.Colors.Gain = defaultGainColor
profile.Colors.Loss = defaultLossColor profile.Colors.Loss = defaultLossColor
profile.Colors.Tag = defaultTagColor profile.Colors.Tag = defaultTagColor
profile.Colors.Header = defaultHeaderColor
profile.Colors.Time = defaultTimeColor
profile.Colors.Default = defaultColor
profile.Save() profile.Save()
} else { } else {
json.Unmarshal(data, profile) json.Unmarshal(data, profile)
InitColor(profile.Colors.Gain, defaultGainColor) InitColor(&profile.Colors.Gain, defaultGainColor)
InitColor(profile.Colors.Loss, defaultLossColor) InitColor(&profile.Colors.Loss, defaultLossColor)
InitColor(profile.Colors.Tag, defaultTagColor) InitColor(&profile.Colors.Tag, defaultTagColor)
InitColor(&profile.Colors.Header, defaultHeaderColor)
InitColor(&profile.Colors.Time, defaultTimeColor)
InitColor(&profile.Colors.Default, defaultColor)
profile.SetFilter(profile.Filter) profile.SetFilter(profile.Filter)
} }
@ -93,10 +105,10 @@ func NewProfile(filename string) *Profile {
return profile return profile
} }
func InitColor(color string, defaultValue string) { func InitColor(color *string, defaultValue string) {
color = strings.ToLower(color) *color = strings.ToLower(*color)
if !IsSupportedColor(color) { if !IsSupportedColor(*color) {
color = defaultValue; *color = defaultValue
} }
} }

@ -5,11 +5,12 @@
package mop package mop
import ( import (
`github.com/nsf/termbox-go` "fmt"
`strings` "strconv"
`time` "strings"
`strconv` "time"
`fmt`
"github.com/nsf/termbox-go"
) )
// Screen is thin wrapper around Termbox library to provide basic display // Screen is thin wrapper around Termbox library to provide basic display
@ -90,7 +91,7 @@ func (screen *Screen) ClearLine(x int, y int) *Screen {
func (screen *Screen) Draw(objects ...interface{}) *Screen { func (screen *Screen) Draw(objects ...interface{}) *Screen {
zonename, _ := time.Now().In(time.Local).Zone() zonename, _ := time.Now().In(time.Local).Zone()
if screen.pausedAt != nil { if screen.pausedAt != nil {
defer screen.DrawLine(0, 0, `<right><r>`+screen.pausedAt.Format(`3:04:05pm ` + zonename)+`</r></right>`) defer screen.DrawLine(0, 0, `<right><r>`+screen.pausedAt.Format(`3:04:05pm `+zonename)+`</r></right>`)
} }
for _, ptr := range objects { for _, ptr := range objects {
switch ptr.(type) { switch ptr.(type) {
@ -102,7 +103,7 @@ func (screen *Screen) Draw(objects ...interface{}) *Screen {
screen.draw(screen.layout.Quotes(object.Fetch())) screen.draw(screen.layout.Quotes(object.Fetch()))
case time.Time: case time.Time:
timestamp := ptr.(time.Time).Format(`3:04:05pm ` + zonename) timestamp := ptr.(time.Time).Format(`3:04:05pm ` + zonename)
screen.DrawLine(0, 0, `<right>`+timestamp+`</right>`) screen.DrawLine(0, 0, `<right><time>`+timestamp+`</></right>`)
default: default:
screen.draw(ptr.(string)) screen.draw(ptr.(string))
} }
@ -146,7 +147,7 @@ func (screen *Screen) draw(str string) {
drewHeading := false drewHeading := false
tempFormat := "%" + strconv.Itoa(screen.width) + "s" tempFormat := "%" + strconv.Itoa(screen.width) + "s"
blankLine := fmt.Sprintf(tempFormat,"") blankLine := fmt.Sprintf(tempFormat, "")
allLines = strings.Split(str, "\n") allLines = strings.Split(str, "\n")
// Write the lines being updated. // Write the lines being updated.
@ -154,9 +155,9 @@ func (screen *Screen) draw(str string) {
screen.DrawLine(0, row, allLines[row]) screen.DrawLine(0, row, allLines[row])
// Did we draw the underlined heading row? This is a crude // Did we draw the underlined heading row? This is a crude
// check, but--see comments below... // check, but--see comments below...
if strings.Contains(allLines[row],"Ticker") && if strings.Contains(allLines[row], "Ticker") &&
strings.Contains(allLines[row],"Last") && strings.Contains(allLines[row], "Last") &&
strings.Contains(allLines[row],"Change") { strings.Contains(allLines[row], "Change") {
drewHeading = true drewHeading = true
} }
} }
@ -173,7 +174,7 @@ func (screen *Screen) draw(str string) {
// cycle. In that case, padding with blank lines would overwrite the // cycle. In that case, padding with blank lines would overwrite the
// stocks list.) // stocks list.)
if drewHeading { if drewHeading {
for i := len(allLines)-1; i < screen.height; i++ { for i := len(allLines) - 1; i < screen.height; i++ {
screen.DrawLine(0, i, blankLine) screen.DrawLine(0, i, blankLine)
} }
} }

Loading…
Cancel
Save