diff --git a/cmd/mop/main.go b/cmd/mop/main.go
index 5b7cc4a..2418a52 100644
--- a/cmd/mop/main.go
+++ b/cmd/mop/main.go
@@ -143,5 +143,5 @@ func main() {
defer screen.Close()
mainLoop(screen, profile)
- profile.Save()
+ profile.Save()
}
diff --git a/layout.go b/layout.go
index 5478981..7d495ae 100644
--- a/layout.go
+++ b/layout.go
@@ -168,7 +168,7 @@ func (layout *Layout) prettify(quotes *Quotes) []Stock {
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 layout.filter == nil { // Initialize filter on first invocation.
layout.filter = NewFilter(profile)
@@ -218,11 +218,11 @@ func buildMarketTemplate() *template.Template {
//-----------------------------------------------------------------------------
func buildQuotesTemplate() *template.Template {
- markup := `{{.Now}}>
+ markup := `
-{{.Header}}
+{{.Header}}>
{{range.Stocks}}{{if eq .Direction 1}}{{else if eq .Direction -1}}{{end}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePct}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}}{{.PreOpen}}{{.AfterHours}}>
{{end}}`
@@ -234,7 +234,7 @@ func highlight(collections ...map[string]string) {
for _, collection := range collections {
change := collection[`change`]
if change[len(change)-1:] == `%` {
- change = change[0:len(change)-1]
+ change = change[0 : len(change)-1]
}
adv, err := strconv.ParseFloat(change, 64)
if err == nil {
@@ -272,9 +272,9 @@ func group(stocks []Stock) []Stock {
func arrowFor(column int, profile *Profile) string {
if column == profile.SortColumn {
if profile.Ascending {
- return string('\U00002191')
+ return string('▲')
}
- return string('\U00002193')
+ return string('▼')
}
return ``
}
diff --git a/markup.go b/markup.go
index c99dbb4..331926f 100644
--- a/markup.go
+++ b/markup.go
@@ -5,9 +5,10 @@
package mop
import (
- `github.com/nsf/termbox-go`
- `regexp`
- `strings`
+ "regexp"
+ "strings"
+
+ "github.com/nsf/termbox-go"
)
// Markup implements some minimalistic text formatting conventions that
@@ -35,9 +36,6 @@ type Markup struct {
// colors and column alignments.
func NewMarkup(profile *Profile) *Markup {
markup := &Markup{}
- markup.Foreground = termbox.ColorDefault
- markup.Background = termbox.ColorDefault
- markup.RightAligned = false
markup.tags = make(map[string]termbox.Attribute)
markup.tags[`/`] = termbox.ColorDefault
@@ -67,6 +65,14 @@ func NewMarkup(profile *Profile) *Markup {
markup.tags[`gain`] = markup.tags[profile.Colors.Gain]
markup.tags[`loss`] = markup.tags[profile.Colors.Loss]
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.
@@ -138,7 +144,7 @@ func (markup *Markup) process(tag string, open bool) bool {
if attribute >= termbox.AttrBold {
markup.Foreground &= ^attribute // Clear the Termbox attribute.
} else {
- markup.Foreground = termbox.ColorDefault
+ markup.Foreground = markup.tags[`default`]
}
}
}
diff --git a/profile.go b/profile.go
index 4be37d0..d6a3779 100644
--- a/profile.go
+++ b/profile.go
@@ -16,22 +16,28 @@ import (
const defaultGainColor = "green"
const defaultLossColor = "red"
const defaultTagColor = "yellow"
+const defaultHeaderColor = "lightgray"
+const defaultTimeColor = "lightgray"
+const defaultColor = "lightgray"
// Profile manages Mop program settings as defined by user (ex. list of
// stock tickers). The settings are serialized using JSON and saved in
// the ~/.moprc file.
type Profile struct {
- Tickers []string // List of stock tickers to display.
- MarketRefresh int // Time interval to refresh market data.
- QuotesRefresh int // Time interval to refresh stock quotes.
- SortColumn int // Column number by which we sort stock quotes.
- Ascending bool // True when sort order is ascending.
- Grouped bool // True when stocks are grouped by advancing/declining.
- Filter string // Filter in human form
- Colors struct { // User defined colors
- Gain string
- Loss string
- Tag string
+ Tickers []string // List of stock tickers to display.
+ MarketRefresh int // Time interval to refresh market data.
+ QuotesRefresh int // Time interval to refresh stock quotes.
+ SortColumn int // Column number by which we sort stock quotes.
+ Ascending bool // True when sort order is ascending.
+ Grouped bool // True when stocks are grouped by advancing/declining.
+ Filter string // Filter in human form
+ Colors struct { // User defined colors
+ Gain string
+ Loss string
+ Tag string
+ Header string
+ Time string
+ Default string
}
filterExpression *govaluate.EvaluableExpression // The filter as a govaluate expression
selectedColumn int // Stores selected column number when the column editor is active.
@@ -40,24 +46,24 @@ type Profile struct {
func IsSupportedColor(colorName string) bool {
switch colorName {
- case
- "black",
- "red",
- "green",
- "yellow",
- "blue",
- "magenta",
- "cyan",
- "white",
- "darkgray",
- "lightred",
- "lightgreen",
- "lightyellow",
- "lightblue",
- "lightmagenta",
- "lightcyan",
- "lightgray":
- return true
+ case
+ "black",
+ "red",
+ "green",
+ "yellow",
+ "blue",
+ "magenta",
+ "cyan",
+ "white",
+ "darkgray",
+ "lightred",
+ "lightgreen",
+ "lightyellow",
+ "lightblue",
+ "lightmagenta",
+ "lightcyan",
+ "lightgray":
+ return true
}
return false
}
@@ -78,13 +84,19 @@ func NewProfile(filename string) *Profile {
profile.Colors.Gain = defaultGainColor
profile.Colors.Loss = defaultLossColor
profile.Colors.Tag = defaultTagColor
+ profile.Colors.Header = defaultHeaderColor
+ profile.Colors.Time = defaultTimeColor
+ profile.Colors.Default = defaultColor
profile.Save()
} else {
json.Unmarshal(data, profile)
- InitColor(profile.Colors.Gain, defaultGainColor)
- InitColor(profile.Colors.Loss, defaultLossColor)
- InitColor(profile.Colors.Tag, defaultTagColor)
+ InitColor(&profile.Colors.Gain, defaultGainColor)
+ InitColor(&profile.Colors.Loss, defaultLossColor)
+ InitColor(&profile.Colors.Tag, defaultTagColor)
+ InitColor(&profile.Colors.Header, defaultHeaderColor)
+ InitColor(&profile.Colors.Time, defaultTimeColor)
+ InitColor(&profile.Colors.Default, defaultColor)
profile.SetFilter(profile.Filter)
}
@@ -93,10 +105,10 @@ func NewProfile(filename string) *Profile {
return profile
}
-func InitColor(color string, defaultValue string) {
- color = strings.ToLower(color)
- if !IsSupportedColor(color) {
- color = defaultValue;
+func InitColor(color *string, defaultValue string) {
+ *color = strings.ToLower(*color)
+ if !IsSupportedColor(*color) {
+ *color = defaultValue
}
}
diff --git a/screen.go b/screen.go
index 91a2932..9a9b45d 100644
--- a/screen.go
+++ b/screen.go
@@ -5,11 +5,12 @@
package mop
import (
- `github.com/nsf/termbox-go`
- `strings`
- `time`
- `strconv`
- `fmt`
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/nsf/termbox-go"
)
// 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 {
zonename, _ := time.Now().In(time.Local).Zone()
if screen.pausedAt != nil {
- defer screen.DrawLine(0, 0, ``+screen.pausedAt.Format(`3:04:05pm ` + zonename)+``)
+ defer screen.DrawLine(0, 0, ``+screen.pausedAt.Format(`3:04:05pm `+zonename)+``)
}
for _, ptr := range objects {
switch ptr.(type) {
@@ -102,7 +103,7 @@ func (screen *Screen) Draw(objects ...interface{}) *Screen {
screen.draw(screen.layout.Quotes(object.Fetch()))
case time.Time:
timestamp := ptr.(time.Time).Format(`3:04:05pm ` + zonename)
- screen.DrawLine(0, 0, ``+timestamp+``)
+ screen.DrawLine(0, 0, ``)
default:
screen.draw(ptr.(string))
}
@@ -146,7 +147,7 @@ func (screen *Screen) draw(str string) {
drewHeading := false
tempFormat := "%" + strconv.Itoa(screen.width) + "s"
- blankLine := fmt.Sprintf(tempFormat,"")
+ blankLine := fmt.Sprintf(tempFormat, "")
allLines = strings.Split(str, "\n")
// Write the lines being updated.
@@ -154,9 +155,9 @@ func (screen *Screen) draw(str string) {
screen.DrawLine(0, row, allLines[row])
// Did we draw the underlined heading row? This is a crude
// check, but--see comments below...
- if strings.Contains(allLines[row],"Ticker") &&
- strings.Contains(allLines[row],"Last") &&
- strings.Contains(allLines[row],"Change") {
+ if strings.Contains(allLines[row], "Ticker") &&
+ strings.Contains(allLines[row], "Last") &&
+ strings.Contains(allLines[row], "Change") {
drewHeading = true
}
}
@@ -173,7 +174,7 @@ func (screen *Screen) draw(str string) {
// cycle. In that case, padding with blank lines would overwrite the
// stocks list.)
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)
}
}