From 8f727f1204e477c8a0c46f88712b27efc08297df Mon Sep 17 00:00:00 2001 From: Michael Dvorkin Date: Sat, 13 Jul 2013 14:06:39 -0700 Subject: [PATCH] Added basics of line editor --- lib/format.go | 102 +++++++++---------- lib/line_editor.go | 64 ++++++++++++ lib/profile.go | 63 ++++++------ lib/screen.go | 96 +++++++++--------- lib/yahoo_market.go | 236 ++++++++++++++++++++++---------------------- lib/yahoo_quotes.go | 108 ++++++++++---------- mop.go | 23 +++-- 7 files changed, 383 insertions(+), 309 deletions(-) create mode 100644 lib/line_editor.go diff --git a/lib/format.go b/lib/format.go index a3da2ba..7c63e57 100644 --- a/lib/format.go +++ b/lib/format.go @@ -3,25 +3,25 @@ package mop import ( - "fmt" - "time" "bytes" - "regexp" - "strings" + "fmt" + "regexp" + "strings" "text/template" + "time" ) //----------------------------------------------------------------------------- func FormatMarket(m Market) string { markup := `{{.Dow.name}}: {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, ` - markup += `{{.Sp500.name}}: {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, ` - markup += `{{.Nasdaq.name}}: {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}` - markup += "\n" - markup += `{{.Advances.name}}: {{.Advances.nyse}} ({{.Advances.nysep}}) on NYSE and {{.Advances.nasdaq}} ({{.Advances.nasdaqp}}) on Nasdaq. ` - markup += `{{.Declines.name}}: {{.Declines.nyse}} ({{.Declines.nysep}}) on NYSE and {{.Declines.nasdaq}} ({{.Declines.nasdaqp}}) on Nasdaq` - markup += "\n" - markup += `New highs: {{.Highs.nyse}} on NYSE and {{.Highs.nasdaq}} on Nasdaq. ` - markup += `New lows: {{.Lows.nyse}} on NYSE and {{.Lows.nasdaq}} on Nasdaq.` + markup += `{{.Sp500.name}}: {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, ` + markup += `{{.Nasdaq.name}}: {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}` + markup += "\n" + markup += `{{.Advances.name}}: {{.Advances.nyse}} ({{.Advances.nysep}}) on NYSE and {{.Advances.nasdaq}} ({{.Advances.nasdaqp}}) on Nasdaq. ` + markup += `{{.Declines.name}}: {{.Declines.nyse}} ({{.Declines.nysep}}) on NYSE and {{.Declines.nasdaq}} ({{.Declines.nasdaqp}}) on Nasdaq` + markup += "\n" + markup += `New highs: {{.Highs.nyse}} on NYSE and {{.Highs.nasdaq}} on Nasdaq. ` + markup += `New lows: {{.Lows.nyse}} on NYSE and {{.Lows.nasdaq}} on Nasdaq.` template, err := template.New("market").Parse(markup) if err != nil { panic(err) @@ -33,18 +33,18 @@ func FormatMarket(m Market) string { panic(err) } - return buffer.String() + return buffer.String() } //----------------------------------------------------------------------------- func FormatQuotes(quotes Quotes) string { vars := struct { Now string - Header string + Header string Stocks Quotes }{ time.Now().Format("3:04:05pm PST"), - header(), + header(), prettify(quotes), } @@ -67,27 +67,27 @@ func FormatQuotes(quotes Quotes) string { panic(err) } - return buffer.String() + return buffer.String() } func header() string { - str := fmt.Sprintf("%-7s ", "Ticker") - str += fmt.Sprintf("%9s ", "Last") - str += fmt.Sprintf("%9s ", "Change") - str += fmt.Sprintf("%9s ", "%Change") - str += fmt.Sprintf("%9s ", "Open") - str += fmt.Sprintf("%9s ", "Low") - str += fmt.Sprintf("%9s ", "High") - str += fmt.Sprintf("%9s ", "52w Low") - str += fmt.Sprintf("%9s ", "52w High") - str += fmt.Sprintf("%10s ", "Volume") - str += fmt.Sprintf("%10s ", "AvgVolume") - str += fmt.Sprintf("%9s ", "P/E") - str += fmt.Sprintf("%9s ", "Dividend") - str += fmt.Sprintf("%9s ", "Yield") - str += fmt.Sprintf("%10s", "MktCap") - - return str + str := fmt.Sprintf("%-7s ", "Ticker") + str += fmt.Sprintf("%9s ", "Last") + str += fmt.Sprintf("%9s ", "Change") + str += fmt.Sprintf("%9s ", "%Change") + str += fmt.Sprintf("%9s ", "Open") + str += fmt.Sprintf("%9s ", "Low") + str += fmt.Sprintf("%9s ", "High") + str += fmt.Sprintf("%9s ", "52w Low") + str += fmt.Sprintf("%9s ", "52w High") + str += fmt.Sprintf("%10s ", "Volume") + str += fmt.Sprintf("%10s ", "AvgVolume") + str += fmt.Sprintf("%9s ", "P/E") + str += fmt.Sprintf("%9s ", "Dividend") + str += fmt.Sprintf("%9s ", "Yield") + str += fmt.Sprintf("%10s", "MktCap") + + return str } func prettify(quotes Quotes) Quotes { @@ -113,19 +113,19 @@ func prettify(quotes Quotes) Quotes { } func nullify(str string) string { - if len(str) == 3 && str[0:3] == "N/A" { - return "-" - } else { - return str - } + if len(str) == 3 && str[0:3] == "N/A" { + return "-" + } else { + return str + } } func last_of_pair(str string) string { - if len(str) >= 6 && str[0:6] != "N/A - " { + if len(str) >= 6 && str[0:6] != "N/A - " { return str - } else { - return str[6:] - } + } else { + return str[6:] + } } func with_currency(str string) string { @@ -168,14 +168,16 @@ func ticker(str string, change string) string { } func pad(str string, width int) string { - re := regexp.MustCompile(`(\.\d+)[MB]?$`) - match := re.FindStringSubmatch(str) - if len(match) > 0 { - switch len(match[1]) { - case 2: str = strings.Replace(str, match[1], match[1] + "0", 1) - case 4, 5: str = strings.Replace(str, match[1], match[1][0:3], 1) - } - } + re := regexp.MustCompile(`(\.\d+)[MB]?$`) + match := re.FindStringSubmatch(str) + if len(match) > 0 { + switch len(match[1]) { + case 2: + str = strings.Replace(str, match[1], match[1]+"0", 1) + case 4, 5: + str = strings.Replace(str, match[1], match[1][0:3], 1) + } + } return fmt.Sprintf("%*s", width, str) } diff --git a/lib/line_editor.go b/lib/line_editor.go new file mode 100644 index 0000000..ea81415 --- /dev/null +++ b/lib/line_editor.go @@ -0,0 +1,64 @@ +// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +package mop + +import ( + "github.com/nsf/termbox-go" +) + +// const ( +// add_prompt = "Add tickers: " +// remove_prompt = "Remove tickers: " +// ) + +// const prompts = map[rune]string{'+': `Add tickers: `, '-': `Remove tickers: `} + +type LineEditor struct { + command rune + prompt string + cursor int + input string +} + +//----------------------------------------------------------------------------- +func (self *LineEditor) Prompt(command rune) { + prompts := map[rune]string{'+': `Add tickers: `, '-': `Remove tickers: `} + + self.command = command + switch self.command { + case '+', '-': + self.prompt = prompts[self.command] + // if self.command == '+' { + // self.prompt = add_prompt + // } else { + // self.prompt = remove_prompt + // } + DrawLine(0, 3, ""+self.prompt+"") + termbox.SetCursor(len(self.prompt), 3) + termbox.Flush() + } +} + +//----------------------------------------------------------------------------- +func (self *LineEditor) Handle(ev termbox.Event) bool { + switch ev.Key { + case termbox.KeyEsc: + ClearLine(0, 3) + termbox.HideCursor() + termbox.Flush() + return true + case termbox.KeyEnter: + ClearLine(0, 3) + termbox.HideCursor() + termbox.Flush() + return true + default: + if ev.Ch != 0 { + self.input += string(ev.Ch) + DrawLine(len(self.prompt), 3, self.input) + termbox.SetCursor(len(self.prompt)+len(self.input), 3) + termbox.Flush() + } + } + return false +} diff --git a/lib/profile.go b/lib/profile.go index fb00171..c6c09a4 100644 --- a/lib/profile.go +++ b/lib/profile.go @@ -1,56 +1,57 @@ // Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= package mop + import ( - "strings" - "os/user" - "io/ioutil" - "encoding/json" + "encoding/json" + "io/ioutil" + "os/user" + "strings" ) const rcfile = "/.moprc" type Profile struct { - MarketRefreshRate int - QuotesRefreshRate int - Tickers []string - SortBy string - SortOrder string + MarketRefreshRate int + QuotesRefreshRate int + Tickers []string + SortBy string + SortOrder string } var profile Profile //----------------------------------------------------------------------------- func LoadProfile() string { - data, err := ioutil.ReadFile(defaultProfile()) - if err != nil { - // Set default values. - profile.MarketRefreshRate = 12 - profile.QuotesRefreshRate = 5 - profile.Tickers = []string{ "AAPL", "C", "GOOG", "IBM", "KO", "ORCL", "V" } - profile.SortBy = "Ticker" - profile.SortOrder = "Desc" - profile.Save() - } else { - json.Unmarshal(data, &profile) - } + data, err := ioutil.ReadFile(defaultProfile()) + if err != nil { + // Set default values. + profile.MarketRefreshRate = 12 + profile.QuotesRefreshRate = 5 + profile.Tickers = []string{"AAPL", "C", "GOOG", "IBM", "KO", "ORCL", "V"} + profile.SortBy = "Ticker" + profile.SortOrder = "Desc" + profile.Save() + } else { + json.Unmarshal(data, &profile) + } return strings.Join(profile.Tickers, "+") } //----------------------------------------------------------------------------- func (profile *Profile) Save() error { - if data, err := json.Marshal(profile); err != nil { - return err - } else { - return ioutil.WriteFile(defaultProfile(), data, 0644) - } + if data, err := json.Marshal(profile); err != nil { + return err + } else { + return ioutil.WriteFile(defaultProfile(), data, 0644) + } } //----------------------------------------------------------------------------- func defaultProfile() string { - usr, err := user.Current() - if err != nil { - panic(err) - } - return usr.HomeDir + rcfile + usr, err := user.Current() + if err != nil { + panic(err) + } + return usr.HomeDir + rcfile } diff --git a/lib/screen.go b/lib/screen.go index 4c679de..b924c24 100644 --- a/lib/screen.go +++ b/lib/screen.go @@ -5,9 +5,9 @@ package mop import ( "github.com/michaeldv/just" "github.com/nsf/termbox-go" - "time" "regexp" "strings" + "time" ) // Can combine attributes and a single color using bitwise OR. @@ -31,71 +31,31 @@ var tags = map[string]termbox.Attribute{ //----------------------------------------------------------------------------- func DrawMarket() { market := GetMarket() - - // for _, m := range message { - // fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change) - // } - // fmt.Printf("%s\n", Format(message)) - drawScreen(FormatMarket(market)) } //----------------------------------------------------------------------------- func DrawQuotes(stocks string) { quotes := GetQuotes(stocks) - - // for _, m := range message { - // fmt.Printf("%s, %s, %s\n", m.Ticker, m.LastTrade, m.Change) - // } - // fmt.Printf("%s\n", Format(message)) - drawScreen(FormatQuotes(quotes)) } //----------------------------------------------------------------------------- func DrawTime() { - now := time.Now().Format("3:04:05pm PST") - drawLine(0, 0, "" + now + "") -} - -// -// Return regular expression that matches all possible tags, i.e. -// || ... | -//----------------------------------------------------------------------------- -func tagsRegexp() *regexp.Regexp { - arr := []string{} - - for tag, _ := range tags { - arr = append(arr, "") - } - - return regexp.MustCompile(strings.Join(arr, "|")) + now := time.Now().Format("3:04:05pm PST") + DrawLine(0, 0, ""+now+"") } -// -// Return true if a string looks like a tag. -//----------------------------------------------------------------------------- -func isTag(str string) (is bool, open bool) { - is = (len(str) > 3 && str[0:1] == "<" && str[len(str)-1:] == ">") - open = (is && str[1:2] != "/") - return -} - -// -// Extract tag name from the given tag, i.e. "" => "hello" //----------------------------------------------------------------------------- -func tagName(str string) string { - if len(str) < 3 { - return "" - } else if str[1:2] != "/" { - return str[1 : len(str)-1] - } else { - return str[2 : len(str)-1] +func ClearLine(x int, y int) { + width, _ := termbox.Size() + for i := x; i < width; i++ { + termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault) } } //----------------------------------------------------------------------------- -func drawLine(x int, y int, str string) { +func DrawLine(x int, y int, str string) { column, right := 0, false foreground, background := termbox.ColorDefault, termbox.ColorDefault @@ -127,12 +87,48 @@ func drawLine(x int, y int, str string) { column += 1 } } - termbox.Flush() + termbox.Flush() } //----------------------------------------------------------------------------- func drawScreen(str string) { for row, line := range strings.Split(str, "\n") { - drawLine(0, row, line) + DrawLine(0, row, line) + } +} + +// +// Return regular expression that matches all possible tags, i.e. +// || ... | +//----------------------------------------------------------------------------- +func tagsRegexp() *regexp.Regexp { + arr := []string{} + + for tag, _ := range tags { + arr = append(arr, "") + } + + return regexp.MustCompile(strings.Join(arr, "|")) +} + +// +// Return true if a string looks like a tag. +//----------------------------------------------------------------------------- +func isTag(str string) (is bool, open bool) { + is = (len(str) > 3 && str[0:1] == "<" && str[len(str)-1:] == ">") + open = (is && str[1:2] != "/") + return +} + +// +// Extract tag name from the given tag, i.e. "" => "hello" +//----------------------------------------------------------------------------- +func tagName(str string) string { + if len(str) < 3 { + return "" + } else if str[1:2] != "/" { + return str[1 : len(str)-1] + } else { + return str[2 : len(str)-1] } } diff --git a/lib/yahoo_market.go b/lib/yahoo_market.go index 186c0f6..70b492c 100644 --- a/lib/yahoo_market.go +++ b/lib/yahoo_market.go @@ -3,23 +3,22 @@ package mop import ( - //"fmt" - "bytes" - "regexp" - "strings" - "net/http" - "io/ioutil" + "bytes" + "io/ioutil" + "net/http" + "regexp" + "strings" ) type Market struct { - Dow map[string]string - Nasdaq map[string]string - Sp500 map[string]string - Advances map[string]string - Declines map[string]string - Unchanged map[string]string - Highs map[string]string - Lows map[string]string + Dow map[string]string + Nasdaq map[string]string + Sp500 map[string]string + Advances map[string]string + Declines map[string]string + Unchanged map[string]string + Highs map[string]string + Lows map[string]string } const yahoo_market_url = `http://finance.yahoo.com/marketupdate/overview` @@ -37,114 +36,115 @@ func GetMarket() Market { panic(err) } - return extract(trim(body)) + return extract(trim(body)) } func trim(body []byte) []byte { - start := bytes.Index(body, []byte("` - const some = `<.+?` - const space = `\s*` - const arrow = `"(Up|Down)">\s*` - const price = `([\d\.,]+)` - const percent = `\(([\d\.,%]+)\)` - - regex := []string{ - "(Dow)", any, price, some, arrow, any, price, some, percent, any, - "(Nasdaq)", any, price, some, arrow, any, price, some, percent, any, - "(S&P 500)", any, price, some, arrow, any, price, some, percent, any, - "(Advances)", any, price, space, percent, any, price, space, percent, any, - "(Declines)", any, price, space, percent, any, price, space, percent, any, - "(Unchanged)", any, price, space, percent, any, price, space, percent, any, - "(New Hi's)", any, price, any, price, any, - "(New Lo's)", any, price, any, price, any, - } - - re := regexp.MustCompile(strings.Join(regex, "")) - matches := re.FindAllStringSubmatch(string(snippet), -1) - - // if len(matches) > 0 { - // fmt.Printf("%d matches\n", len(matches[0])) - // for i, str := range matches[0][1:] { - // fmt.Printf("%d) [%s]\n", i, str) - // } - // } else { - // println("No matches") - // } - - m := Market{ - Dow: make(map[string]string), - Nasdaq: make(map[string]string), - Sp500: make(map[string]string), - Advances: make(map[string]string), - Declines: make(map[string]string), - Unchanged: make(map[string]string), - Highs: make(map[string]string), - Lows: make(map[string]string), - } - m.Dow[`name`] = matches[0][1] - m.Dow[`latest`] = matches[0][2] - m.Dow[`change`] = matches[0][4] - if matches[0][3] == "Up" { - m.Dow[`change`] = "+" + matches[0][4] - m.Dow[`percent`] = "+" + matches[0][5] - } else { - m.Dow[`change`] = "-" + matches[0][4] - m.Dow[`percent`] = "-" + matches[0][5] - } - - m.Nasdaq[`name`] = matches[0][6] - m.Nasdaq[`latest`] = matches[0][7] - if matches[0][8] == "Up" { - m.Nasdaq[`change`] = "+" + matches[0][9] - m.Nasdaq[`percent`] = "+" + matches[0][10] - } else { - m.Nasdaq[`change`] = "-" + matches[0][9] - m.Nasdaq[`percent`] = "-" + matches[0][10] - } - - m.Sp500[`name`] = matches[0][11] - m.Sp500[`latest`] = matches[0][12] - if matches[0][13] == "Up" { - m.Sp500[`change`] = "+" + matches[0][14] - m.Sp500[`percent`] = "+" + matches[0][15] - } else { - m.Sp500[`change`] = "-" + matches[0][14] - m.Sp500[`percent`] = "-" + matches[0][15] - } - - m.Advances[`name`] = matches[0][16] - m.Advances[`nyse`] = matches[0][17] - m.Advances[`nysep`] = matches[0][18] - m.Advances[`nasdaq`] = matches[0][19] - m.Advances[`nasdaqp`] = matches[0][20] - - m.Declines[`name`] = matches[0][21] - m.Declines[`nyse`] = matches[0][22] - m.Declines[`nysep`] = matches[0][23] - m.Declines[`nasdaq`] = matches[0][24] - m.Declines[`nasdaqp`] = matches[0][25] - - m.Unchanged[`name`] = matches[0][26] - m.Unchanged[`nyse`] = matches[0][27] - m.Unchanged[`nysep`] = matches[0][28] - m.Unchanged[`nasdaq`] = matches[0][29] - m.Unchanged[`nasdaqp`] = matches[0][30] - - m.Highs[`name`] = matches[0][31] - m.Highs[`nyse`] = matches[0][32] - m.Highs[`nasdaq`] = matches[0][33] - m.Lows[`name`] = matches[0][34] - m.Lows[`nyse`] = matches[0][35] - m.Lows[`nasdaq`] = matches[0][36] - - return m; + const any = `\s*<.+?>` + const some = `<.+?` + const space = `\s*` + const arrow = `"(Up|Down)">\s*` + const price = `([\d\.,]+)` + const percent = `\(([\d\.,%]+)\)` + + regex := []string{ + "(Dow)", any, price, some, arrow, any, price, some, percent, any, + "(Nasdaq)", any, price, /*some, arrow,*/ any, price, some, percent, any, + "(S&P 500)", any, price, some, arrow, any, price, some, percent, any, + "(Advances)", any, price, space, percent, any, price, space, percent, any, + "(Declines)", any, price, space, percent, any, price, space, percent, any, + "(Unchanged)", any, price, space, percent, any, price, space, percent, any, + "(New Hi's)", any, price, any, price, any, + "(New Lo's)", any, price, any, price, any, + } + + re := regexp.MustCompile(strings.Join(regex, "")) + matches := re.FindAllStringSubmatch(string(snippet), -1) + + // if len(matches) > 0 { + // fmt.Printf("%d matches\n", len(matches[0])) + // for i, str := range matches[0][1:] { + // fmt.Printf("%d) [%s]\n", i, str) + // } + // } else { + // println("No matches") + // } + + m := Market{ + Dow: make(map[string]string), + Nasdaq: make(map[string]string), + Sp500: make(map[string]string), + Advances: make(map[string]string), + Declines: make(map[string]string), + Unchanged: make(map[string]string), + Highs: make(map[string]string), + Lows: make(map[string]string), + } + return m + m.Dow[`name`] = matches[0][1] + m.Dow[`latest`] = matches[0][2] + m.Dow[`change`] = matches[0][4] + if matches[0][3] == "Up" { + m.Dow[`change`] = "+" + matches[0][4] + m.Dow[`percent`] = "+" + matches[0][5] + } else { + m.Dow[`change`] = "-" + matches[0][4] + m.Dow[`percent`] = "-" + matches[0][5] + } + + m.Nasdaq[`name`] = matches[0][6] + m.Nasdaq[`latest`] = matches[0][7] + if matches[0][8] == "Up" { + m.Nasdaq[`change`] = "+" + matches[0][9] + m.Nasdaq[`percent`] = "+" + matches[0][10] + } else { + m.Nasdaq[`change`] = "-" + matches[0][9] + m.Nasdaq[`percent`] = "-" + matches[0][10] + } + + m.Sp500[`name`] = matches[0][11] + m.Sp500[`latest`] = matches[0][12] + if matches[0][13] == "Up" { + m.Sp500[`change`] = "+" + matches[0][14] + m.Sp500[`percent`] = "+" + matches[0][15] + } else { + m.Sp500[`change`] = "-" + matches[0][14] + m.Sp500[`percent`] = "-" + matches[0][15] + } + + m.Advances[`name`] = matches[0][16] + m.Advances[`nyse`] = matches[0][17] + m.Advances[`nysep`] = matches[0][18] + m.Advances[`nasdaq`] = matches[0][19] + m.Advances[`nasdaqp`] = matches[0][20] + + m.Declines[`name`] = matches[0][21] + m.Declines[`nyse`] = matches[0][22] + m.Declines[`nysep`] = matches[0][23] + m.Declines[`nasdaq`] = matches[0][24] + m.Declines[`nasdaqp`] = matches[0][25] + + m.Unchanged[`name`] = matches[0][26] + m.Unchanged[`nyse`] = matches[0][27] + m.Unchanged[`nysep`] = matches[0][28] + m.Unchanged[`nasdaq`] = matches[0][29] + m.Unchanged[`nasdaqp`] = matches[0][30] + + m.Highs[`name`] = matches[0][31] + m.Highs[`nyse`] = matches[0][32] + m.Highs[`nasdaq`] = matches[0][33] + m.Lows[`name`] = matches[0][34] + m.Lows[`nyse`] = matches[0][35] + m.Lows[`nasdaq`] = matches[0][36] + + return m } diff --git a/lib/yahoo_quotes.go b/lib/yahoo_quotes.go index f49e329..7f0f324 100644 --- a/lib/yahoo_quotes.go +++ b/lib/yahoo_quotes.go @@ -3,11 +3,11 @@ package mop import ( - "fmt" - "bytes" - "strings" - "net/http" - "io/ioutil" + "bytes" + "fmt" + "io/ioutil" + "net/http" + "strings" ) // See http://www.gummy-stuff.org/Yahoo-data.htm @@ -37,31 +37,31 @@ const yahoo_quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f= // "TSLA", 120.09, "+4.85", "N/A - +4.21%", 118.75, 115.70, 120.28, 25.52, 121.89, 6827497, 9464530, N/A, N/A, 0.00, N/A, N/A, 13.877B type Quote struct { - Ticker string - LastTrade string - Change string - ChangePercent string - Open string - Low string - High string - Low52 string - High52 string - Volume string - AvgVolume string - PeRatio string - PeRatioX string - Dividend string - Yield string - MarketCap string - MarketCapX string + Ticker string + LastTrade string + Change string + ChangePercent string + Open string + Low string + High string + Low52 string + High52 string + Volume string + AvgVolume string + PeRatio string + PeRatioX string + Dividend string + Yield string + MarketCap string + MarketCapX string } type Quotes []Quote func GetQuotes(tickers string) Quotes { - // Format the URL and send the request. - // url := fmt.Sprintf(yahoo_quotes_url, strings.Join(tickers, "+")) - url := fmt.Sprintf(yahoo_quotes_url, tickers) + // Format the URL and send the request. + // url := fmt.Sprintf(yahoo_quotes_url, strings.Join(tickers, "+")) + url := fmt.Sprintf(yahoo_quotes_url, tickers) response, err := http.Get(url) if err != nil { panic(err) @@ -74,7 +74,7 @@ func GetQuotes(tickers string) Quotes { panic(err) } - return parse(sanitize(body)) + return parse(sanitize(body)) } func (q *Quote) Color() string { @@ -86,46 +86,46 @@ func (q *Quote) Color() string { } func sanitize(body []byte) []byte { - return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1) + return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1) } func parse(body []byte) Quotes { - lines := bytes.Split(body, []byte{'\n'}) - quotes := make(Quotes, len(lines)) + lines := bytes.Split(body, []byte{'\n'}) + quotes := make(Quotes, len(lines)) - for i,line := range lines { - // fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line)) - parse_line(line, "es[i]) - } + for i, line := range lines { + // fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line)) + parse_line(line, "es[i]) + } - return quotes + return quotes } func parse_line(line []byte, quote *Quote) { - columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) + columns := bytes.Split(bytes.TrimSpace(line), []byte{','}) - quote.Ticker = string(columns[0]) - quote.LastTrade = string(columns[1]) - quote.Change = string(columns[2]) - quote.ChangePercent = string(columns[3]) - quote.Open = string(columns[4]) - quote.Low = string(columns[5]) - quote.High = string(columns[6]) - quote.Low52 = string(columns[7]) - quote.High52 = string(columns[8]) - quote.Volume = string(columns[9]) - quote.AvgVolume = string(columns[10]) - quote.PeRatio = string(columns[11]) - quote.PeRatioX = string(columns[12]) - quote.Dividend = string(columns[13]) - quote.Yield = string(columns[14]) - quote.MarketCap = string(columns[15]) - quote.MarketCapX = string(columns[16]) + quote.Ticker = string(columns[0]) + quote.LastTrade = string(columns[1]) + quote.Change = string(columns[2]) + quote.ChangePercent = string(columns[3]) + quote.Open = string(columns[4]) + quote.Low = string(columns[5]) + quote.High = string(columns[6]) + quote.Low52 = string(columns[7]) + quote.High52 = string(columns[8]) + quote.Volume = string(columns[9]) + quote.AvgVolume = string(columns[10]) + quote.PeRatio = string(columns[11]) + quote.PeRatioX = string(columns[12]) + quote.Dividend = string(columns[13]) + quote.Yield = string(columns[14]) + quote.MarketCap = string(columns[15]) + quote.MarketCapX = string(columns[16]) } // func (quotes Quotes) Format() string { // str := time.Now().Format("3:04:05pm PST\n") -// +// // for _, q := range quotes { // str += fmt.Sprintf("%s - %s - %s - %s\n", q.Ticker, q.Ask, q.Change, q.ChangePercent) // } @@ -319,4 +319,4 @@ func parse_line(line []byte, quote *Quote) { // ] // } // } -// } \ No newline at end of file +// } diff --git a/mop.go b/mop.go index 8a7a926..f7c6a82 100644 --- a/mop.go +++ b/mop.go @@ -18,6 +18,7 @@ func initTermbox() { //----------------------------------------------------------------------------- func mainLoop(profile string) { + var line_editor *mop.LineEditor keyboard_queue := make(chan termbox.Event) timestamp_queue := time.NewTicker(1 * time.Second) quotes_queue := time.NewTicker(5 * time.Second) @@ -29,7 +30,7 @@ func mainLoop(profile string) { } }() - termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) + termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) mop.DrawMarket() mop.DrawQuotes(profile) loop: @@ -38,13 +39,23 @@ loop: case event := <-keyboard_queue: switch event.Type { case termbox.EventKey: - if event.Key == termbox.KeyEsc { - break loop + if line_editor == nil { + if event.Key == termbox.KeyEsc { + break loop + } else if event.Ch == '+' || event.Ch == '-' { + line_editor = new(mop.LineEditor) + line_editor.Prompt(event.Ch) + } + } else { + done := line_editor.Handle(event) + if done { + line_editor = nil + } } case termbox.EventResize: - termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) - mop.DrawMarket() - mop.DrawQuotes(profile) + termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) + mop.DrawMarket() + mop.DrawQuotes(profile) } case <-timestamp_queue.C: