diff --git a/lib/layout.go b/lib/layout.go index 0bc4c19..0443da8 100644 --- a/lib/layout.go +++ b/lib/layout.go @@ -49,19 +49,19 @@ func (self *Layout) Initialize() *Layout { func (self *Layout) Market(m *Market) string { markup := `{{.Dow.name}}: ` if m.Dow[`change`][0:1] != `-` { - markup += `{{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, ` + markup += `{{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, ` } else { markup += `{{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, ` } markup += `{{.Sp500.name}}: ` if m.Sp500[`change`][0:1] != `-` { - markup += `{{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, ` + markup += `{{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, ` } else { markup += `{{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, ` } markup += `{{.Nasdaq.name}}: ` if m.Nasdaq[`change`][0:1] != `-` { - markup += `{{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}` + markup += `{{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}` } else { markup += `{{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}` } @@ -100,7 +100,7 @@ func (self *Layout) Quotes(quotes *Quotes) string { self.prettify(quotes), } - markup := `{{.Now}} + markup := `{{.Now}} @@ -256,26 +256,6 @@ func percent(str string) string { } } -//----------------------------------------------------------------------------- -func colorize(str string) string { - if str == `N/A` { - return `-` - } else if str[0:1] == `-` { - return `` + str + `` - } else { - return `` + str + `` - } -} - -//----------------------------------------------------------------------------- -func ticker(str string, change string) string { - if change[0:1] == `-` { - return `` + str + `` - } else { - return `` + str + `` - } -} - //----------------------------------------------------------------------------- func pad(str string, width int) string { re := regexp.MustCompile(`(\.\d+)[MB]?$`) diff --git a/lib/line_editor.go b/lib/line_editor.go index 039ed59..39864e1 100644 --- a/lib/line_editor.go +++ b/lib/line_editor.go @@ -32,7 +32,7 @@ func (self *LineEditor) Prompt(command rune) { self.prompt = prompt self.command = command - self.screen.DrawLine(0, 3, `` + self.prompt + ``) + self.screen.DrawLine(0, 3, `` + self.prompt + ``) termbox.SetCursor(len(self.prompt), 3) termbox.Flush() } diff --git a/lib/markup.go b/lib/markup.go new file mode 100644 index 0000000..aedb2df --- /dev/null +++ b/lib/markup.go @@ -0,0 +1,138 @@ +// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +package mop + +import ( + `github.com/nsf/termbox-go` + `regexp` + `strings` +) + +type Markup struct { + tags map[string]termbox.Attribute + Foreground termbox.Attribute + Background termbox.Attribute + RightAligned bool +} + +//----------------------------------------------------------------------------- +func (self *Markup) Initialize() *Markup { + self.tags = make(map[string]termbox.Attribute) + self.tags[`/`] = termbox.ColorDefault + 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 + self.Foreground = termbox.ColorDefault + self.Background = termbox.ColorDefault + self.RightAligned = false + + return self +} + +//----------------------------------------------------------------------------- +func (self *Markup) Tokenize(str string) []string { + matches := self.supported_tags().FindAllStringIndex(str, -1) + strings := make([]string, 0, len(matches)) + + head, tail := 0, 0 + for _, match := range matches { + tail = match[0] + if match[1] != 0 { + if head != 0 || tail != 0 { + strings = append(strings, str[head:tail]) // Apend text between tags. + } + strings = append(strings, str[match[0]:match[1]]) // Append tag. + } + head = match[1] + } + + if head != len(str) && tail != len(str) { + strings = append(strings, str[head:]) + } + + return strings +} + +//----------------------------------------------------------------------------- +func (self *Markup) IsTag(str string) bool { + tag, open := probe_tag(str) + + if tag == `` { + return false + } + + return self.process(tag, open) +} + +//----------------------------------------------------------------------------- +func (self *Markup) process(tag string, open bool) bool { + if attribute, ok := self.tags[tag]; ok { + switch tag { + case `right`: + self.RightAligned = open + default: + if open { + if attribute >= termbox.AttrBold { + self.Foreground |= attribute + } else { + self.Foreground = attribute + } + } else { + if attribute >= termbox.AttrBold { + self.Foreground &= ^attribute + } else { + self.Foreground = termbox.ColorDefault + } + } + } + } + + return true +} + +// +// Return regular expression that matches all possible tags, i.e. +// || ... | +//----------------------------------------------------------------------------- +func (self *Markup) supported_tags() *regexp.Regexp { + arr := []string{} + + for tag, _ := range self.tags { + arr = append(arr, ``) + } + + return regexp.MustCompile(strings.Join(arr, `|`)) +} + +//----------------------------------------------------------------------------- +func probe_tag(str string) (string, bool) { + if len(str) > 2 && str[0:1] == `<` && str[len(str)-1:] == `>` { + return extract_tag_name(str), str[1:2] != `/` + } + + return ``, false +} + +// +// Extract tag name from the given tag, i.e. `` => `hello` +//----------------------------------------------------------------------------- +func extract_tag_name(str string) string { + if len(str) < 3 { + return `` + } else if str[1:2] != `/` { + return str[1 : len(str)-1] + } else if len(str) > 3 { + return str[2 : len(str)-1] + } else { + return `/` + } +} diff --git a/lib/screen.go b/lib/screen.go index b3b78db..49ddc0f 100644 --- a/lib/screen.go +++ b/lib/screen.go @@ -3,18 +3,15 @@ package mop import ( - `github.com/michaeldv/just` `github.com/nsf/termbox-go` - `regexp` `strings` `time` ) type Screen struct { - width int - height int - cleared bool - tags map[string]termbox.Attribute + width int + height int + cleared bool } //----------------------------------------------------------------------------- @@ -24,28 +21,14 @@ func (self *Screen) Initialize() *Screen { 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 + return self.Resize() } //----------------------------------------------------------------------------- func (self *Screen) Resize() *Screen { self.width, self.height = termbox.Size() self.cleared = false + return self } @@ -53,12 +36,15 @@ func (self *Screen) Resize() *Screen { func (self *Screen) Clear() *Screen { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) self.cleared = true + return self } //----------------------------------------------------------------------------- -func (self *Screen) Close() { +func (self *Screen) Close() *Screen { termbox.Close() + + return self } //----------------------------------------------------------------------------- @@ -92,43 +78,21 @@ func (self *Screen) ClearLine(x int, y int) { //----------------------------------------------------------------------------- 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(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`: - right = open - default: - if open { - if value >= termbox.AttrBold { - foreground |= value - } else { - foreground = value - } - } else { - if value >= termbox.AttrBold { - foreground &= ^value - } else { - foreground = termbox.ColorDefault - } - } + start, column := 0, 0 + + markup := new(Markup).Initialize() + for _, token := range markup.Tokenize(str) { + if !markup.IsTag(token) { + for i, char := range token { + if !markup.RightAligned { + start = x + column + column++ + } else { + start = self.width - len(token) + i } + termbox.SetCell(start, y, char, markup.Foreground, markup.Background) } } - - for i, char := range token { - if !right { - termbox.SetCell(x+column, y, char, foreground, background) - } else { - termbox.SetCell(self.width-len(token)+i, y, char, foreground, background) - } - column++ - } } termbox.Flush() } @@ -143,39 +107,3 @@ func (self *Screen) draw(str string) { self.DrawLine(0, row, line) } } - -// -// Return regular expression that matches all possible tags, i.e. -// || ... | -//----------------------------------------------------------------------------- -func (self *Screen) possible_tags() *regexp.Regexp { - arr := []string{} - - for tag, _ := range self.tags { - arr = append(arr, ``) - } - - return regexp.MustCompile(strings.Join(arr, `|`)) -} - -// -// Return true if a string looks like a tag. -//----------------------------------------------------------------------------- -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 -} - -// -// Extract tag name from the given tag, i.e. `` => `hello` -//----------------------------------------------------------------------------- -func (self *Screen) tag_name(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_quotes.go b/lib/yahoo_quotes.go index db45094..64453dc 100644 --- a/lib/yahoo_quotes.go +++ b/lib/yahoo_quotes.go @@ -151,7 +151,7 @@ func (self *Quotes) sanitize(body []byte) []byte { //----------------------------------------------------------------------------- func (stock *Stock) Color() string { if strings.Index(stock.Change, "-") == -1 { - return `` + return `` } else { return `` // `` }