From 0a9ae0fea8ef98992a177afc0e9ea419bdaaa515 Mon Sep 17 00:00:00 2001 From: Michael Dvorkin Date: Thu, 18 Jul 2013 20:38:47 -0700 Subject: [PATCH] Refactored screen --- lib/format.go | 4 +- lib/line_editor.go | 28 +++++++----- lib/screen.go | 109 +++++++++++++++++++++++++++++---------------- mop.go | 39 +++++++--------- 4 files changed, 105 insertions(+), 75 deletions(-) diff --git a/lib/format.go b/lib/format.go index 7e8fe64..32d9d88 100644 --- a/lib/format.go +++ b/lib/format.go @@ -86,7 +86,7 @@ func FormatQuotes(quotes Quotes) string { } func header() string { - str := fmt.Sprintf(`%-7s `, `Ticker`) + str := fmt.Sprintf(`%-7s `, `Ticker`) str += fmt.Sprintf(`%9s `, `Last`) str += fmt.Sprintf(`%9s `, `Change`) str += fmt.Sprintf(`%9s `, `%Change`) @@ -100,7 +100,7 @@ func header() string { str += fmt.Sprintf(`%9s `, `P/E`) str += fmt.Sprintf(`%9s `, `Dividend`) str += fmt.Sprintf(`%9s `, `Yield`) - str += fmt.Sprintf(`%10s`, `MktCap`) + str += fmt.Sprintf(`%10s`, `MktCap`) return str } diff --git a/lib/line_editor.go b/lib/line_editor.go index c182ac3..e9aaa0b 100644 --- a/lib/line_editor.go +++ b/lib/line_editor.go @@ -13,18 +13,26 @@ type LineEditor struct { prompt string cursor int input string + screen *Screen profile *Profile } //----------------------------------------------------------------------------- -func (self *LineEditor) Prompt(command rune, profile *Profile) { +func (self *LineEditor) Initialize(screen *Screen, profile *Profile) *LineEditor { + self.screen = screen + self.profile = profile + + return self +} + +//----------------------------------------------------------------------------- +func (self *LineEditor) Prompt(command rune) { prompts := map[rune]string{'+': `Add tickers: `, '-': `Remove tickers: `} if prompt, ok := prompts[command]; ok { self.prompt = prompt self.command = command - self.profile = profile - DrawLine(0, 3, `` + self.prompt + ``) + self.screen.DrawLine(0, 3, `` + self.prompt + ``) termbox.SetCursor(len(self.prompt), 3) termbox.Flush() } @@ -67,7 +75,7 @@ func (self *LineEditor) Handle(ev termbox.Event) bool { self.insert_character(ev.Ch) } } - //DrawLine(20,20, fmt.Sprintf(`cursor: %02d [%s] %08d`, self.cursor, self.input, ev.Ch)) + //self.screen.DrawLine(20,20, fmt.Sprintf(`cursor: %02d [%s] %08d`, self.cursor, self.input, ev.Ch)) return false } @@ -81,7 +89,7 @@ func (self *LineEditor) delete_previous_character() { // Remove last input character. self.input = self.input[ : len(self.input)-1] } - DrawLine(len(self.prompt), 3, self.input + ` `) // Erase last character. + self.screen.DrawLine(len(self.prompt), 3, self.input + ` `) // Erase last character. self.move_left() } } @@ -95,7 +103,7 @@ func (self *LineEditor) insert_character(ch rune) { // Append the character to the end of the input string. self.input += string(ch) } - DrawLine(len(self.prompt), 3, self.input) + self.screen.DrawLine(len(self.prompt), 3, self.input) self.move_right() } @@ -129,7 +137,7 @@ func (self *LineEditor) jump_to_end() { //----------------------------------------------------------------------------- func (self *LineEditor) done() { - ClearLine(0, 3) + self.screen.ClearLine(0, 3) termbox.HideCursor() } @@ -140,7 +148,7 @@ func (self *LineEditor) execute() { tickers := self.tokenize() if len(tickers) > 0 { self.profile.AddTickers(tickers) - DrawQuotes(self.profile.Quotes()) + self.screen.DrawQuotes(self.profile.Quotes()) } case '-': tickers := self.tokenize() @@ -149,9 +157,9 @@ func (self *LineEditor) execute() { self.profile.RemoveTickers(tickers) after := len(self.profile.Tickers) if after < before { - DrawQuotes(self.profile.Quotes()) + self.screen.DrawQuotes(self.profile.Quotes()) for i := before; i > after; i-- { - ClearLine(0, i + 4) + self.screen.ClearLine(0, i + 4) } } } diff --git a/lib/screen.go b/lib/screen.go index d5808f4..6e44354 100644 --- a/lib/screen.go +++ b/lib/screen.go @@ -10,59 +10,90 @@ import ( `time` ) -// Can combine attributes and a single color using bitwise OR. -// -// AttrBold Attribute = 1 << (iota + 4) -// AttrUnderline -// AttrReverse -// -var tags = map[string]termbox.Attribute{ - `black`: termbox.ColorBlack, - `red`: termbox.ColorRed, - `green`: termbox.ColorGreen, - `yellow`: termbox.ColorYellow, - `blue`: termbox.ColorBlue, - `magenta`: termbox.ColorMagenta, - `cyan`: termbox.ColorCyan, - `white`: termbox.ColorWhite, - `right`: termbox.ColorDefault, +type Screen struct { + width int + height int + tags map[string]termbox.Attribute +} + +//----------------------------------------------------------------------------- +func (self *Screen) Initialize() *Screen { + err := termbox.Init() + if err != nil { + panic(err) + } + + self.Resize() + self.tags = make(map[string]termbox.Attribute) + self.tags[`black`] = termbox.ColorBlack + self.tags[`red`] = termbox.ColorRed + self.tags[`green`] = termbox.ColorGreen + self.tags[`yellow`] = termbox.ColorYellow + self.tags[`blue`] = termbox.ColorBlue + self.tags[`magenta`] = termbox.ColorMagenta + self.tags[`cyan`] = termbox.ColorCyan + self.tags[`white`] = termbox.ColorWhite + self.tags[`right`] = termbox.ColorDefault // Termbox can combine attributes and a single color using bitwise OR. + self.tags[`b`] = termbox.AttrBold // Attribute = 1 << (iota + 4) + self.tags[`u`] = termbox.AttrUnderline + self.tags[`r`] = termbox.AttrReverse + + return self } //----------------------------------------------------------------------------- -func DrawMarket() { +func (self *Screen) Resize() *Screen { + self.width, self.height = termbox.Size() + return self +} + +//----------------------------------------------------------------------------- +func (self *Screen) Clear() *Screen { + termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) + return self +} + +//----------------------------------------------------------------------------- +func (self *Screen) Close() { + termbox.Close() +} + +//----------------------------------------------------------------------------- +func (self *Screen) DrawMarket() { market := GetMarket() - drawScreen(FormatMarket(market)) + self.draw(FormatMarket(market)) } //----------------------------------------------------------------------------- -func DrawQuotes(stocks string) { +func (self *Screen) DrawQuotes(stocks string) { quotes := GetQuotes(stocks) - drawScreen(FormatQuotes(quotes)) + self.draw(FormatQuotes(quotes)) } //----------------------------------------------------------------------------- -func DrawTime() { +func (self *Screen) DrawTime() { now := time.Now().Format(`3:04:05pm PST`) - DrawLine(0, 0, `` + now + ``) + self.DrawLine(0, 0, `` + now + ``) } //----------------------------------------------------------------------------- -func ClearLine(x int, y int) { - width, _ := termbox.Size() - for i := x; i < width; i++ { +func (self *Screen) ClearLine(x int, y int) { + for i := x; i < self.width; i++ { termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault) } + + termbox.Flush() } //----------------------------------------------------------------------------- -func DrawLine(x int, y int, str string) { +func (self *Screen) DrawLine(x int, y int, str string) { column, right := 0, false foreground, background := termbox.ColorDefault, termbox.ColorDefault - for _, token := range just.Split(tagsRegexp(), str) { - if tag, open := isTag(token); tag { - key := tagName(token) - if value, ok := tags[key]; ok { + for _, token := range just.Split(self.possible_tags(), str) { + if tag, open := self.is_tag(token); tag { + key := self.tag_name(token) + if value, ok := self.tags[key]; ok { token = `` switch key { case `right`: @@ -81,8 +112,7 @@ func DrawLine(x int, y int, str string) { if !right { termbox.SetCell(x+column, y, char, foreground, background) } else { - width, _ := termbox.Size() - termbox.SetCell(width-len(token)+i, y, char, foreground, background) + termbox.SetCell(self.width-len(token)+i, y, char, foreground, background) } column += 1 } @@ -90,10 +120,11 @@ func DrawLine(x int, y int, str string) { termbox.Flush() } +// private //----------------------------------------------------------------------------- -func drawScreen(str string) { +func (self *Screen) draw(str string) { for row, line := range strings.Split(str, "\n") { - DrawLine(0, row, line) + self.DrawLine(0, row, line) } } @@ -101,10 +132,10 @@ func drawScreen(str string) { // Return regular expression that matches all possible tags, i.e. // || ... | //----------------------------------------------------------------------------- -func tagsRegexp() *regexp.Regexp { +func (self *Screen) possible_tags() *regexp.Regexp { arr := []string{} - for tag, _ := range tags { + for tag, _ := range self.tags { arr = append(arr, ``) } @@ -114,8 +145,8 @@ func tagsRegexp() *regexp.Regexp { // // 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:] == `>`) +func (self *Screen) is_tag(str string) (is bool, open bool) { + is = (len(str) > 2 && str[0:1] == `<` && str[len(str)-1:] == `>`) open = (is && str[1:2] != `/`) return } @@ -123,7 +154,7 @@ func isTag(str string) (is bool, open bool) { // // Extract tag name from the given tag, i.e. `` => `hello` //----------------------------------------------------------------------------- -func tagName(str string) string { +func (self *Screen) tag_name(str string) string { if len(str) < 3 { return `` } else if str[1:2] != `/` { diff --git a/mop.go b/mop.go index cd31484..0c6b15e 100644 --- a/mop.go +++ b/mop.go @@ -9,15 +9,7 @@ import ( ) //----------------------------------------------------------------------------- -func initTermbox() { - err := termbox.Init() - if err != nil { - panic(err) - } -} - -//----------------------------------------------------------------------------- -func mainLoop(profile *mop.Profile) { +func mainLoop(screen *mop.Screen, profile *mop.Profile) { var line_editor *mop.LineEditor keyboard_queue := make(chan termbox.Event) timestamp_queue := time.NewTicker(1 * time.Second) @@ -30,9 +22,9 @@ func mainLoop(profile *mop.Profile) { } }() - termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) - mop.DrawMarket() - mop.DrawQuotes(profile.Quotes()) + screen.Clear() + screen.DrawMarket() + screen.DrawQuotes(profile.Quotes()) loop: for { select { @@ -43,8 +35,8 @@ loop: if event.Key == termbox.KeyEsc { break loop } else if event.Ch == '+' || event.Ch == '-' { - line_editor = new(mop.LineEditor) - line_editor.Prompt(event.Ch, profile) + line_editor = new(mop.LineEditor).Initialize(screen, profile) + line_editor.Prompt(event.Ch) } } else { done := line_editor.Handle(event) @@ -53,29 +45,28 @@ loop: } } case termbox.EventResize: - termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) - mop.DrawMarket() - mop.DrawQuotes(profile.Quotes()) + screen.Resize().Clear() + screen.DrawMarket() + screen.DrawQuotes(profile.Quotes()) } case <-timestamp_queue.C: - mop.DrawTime() + screen.DrawTime() case <-quotes_queue.C: - mop.DrawQuotes(profile.Quotes()) + screen.DrawQuotes(profile.Quotes()) case <-market_queue.C: - mop.DrawMarket() + screen.DrawMarket() } } } //----------------------------------------------------------------------------- func main() { - - initTermbox() - defer termbox.Close() + screen := new(mop.Screen).Initialize() + defer screen.Close() profile := new(mop.Profile).Initialize() - mainLoop(profile) + mainLoop(screen, profile) }