Added basics of line editor

master
Michael Dvorkin 11 years ago
parent 713b87609d
commit 8f727f1204
  1. 10
      lib/format.go
  2. 64
      lib/line_editor.go
  3. 9
      lib/profile.go
  4. 92
      lib/screen.go
  5. 10
      lib/yahoo_market.go
  6. 8
      lib/yahoo_quotes.go
  7. 11
      mop.go

@ -3,12 +3,12 @@
package mop package mop
import ( import (
"fmt"
"time"
"bytes" "bytes"
"fmt"
"regexp" "regexp"
"strings" "strings"
"text/template" "text/template"
"time"
) )
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -172,8 +172,10 @@ func pad(str string, width int) string {
match := re.FindStringSubmatch(str) match := re.FindStringSubmatch(str)
if len(match) > 0 { if len(match) > 0 {
switch len(match[1]) { switch len(match[1]) {
case 2: str = strings.Replace(str, match[1], match[1] + "0", 1) case 2:
case 4, 5: str = strings.Replace(str, match[1], match[1][0:3], 1) str = strings.Replace(str, match[1], match[1]+"0", 1)
case 4, 5:
str = strings.Replace(str, match[1], match[1][0:3], 1)
} }
} }

@ -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, "<white>"+self.prompt+"</white>")
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
}

@ -1,11 +1,12 @@
// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. // Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
package mop package mop
import ( import (
"strings"
"os/user"
"io/ioutil"
"encoding/json" "encoding/json"
"io/ioutil"
"os/user"
"strings"
) )
const rcfile = "/.moprc" const rcfile = "/.moprc"
@ -27,7 +28,7 @@ func LoadProfile() string {
// Set default values. // Set default values.
profile.MarketRefreshRate = 12 profile.MarketRefreshRate = 12
profile.QuotesRefreshRate = 5 profile.QuotesRefreshRate = 5
profile.Tickers = []string{ "AAPL", "C", "GOOG", "IBM", "KO", "ORCL", "V" } profile.Tickers = []string{"AAPL", "C", "GOOG", "IBM", "KO", "ORCL", "V"}
profile.SortBy = "Ticker" profile.SortBy = "Ticker"
profile.SortOrder = "Desc" profile.SortOrder = "Desc"
profile.Save() profile.Save()

@ -5,9 +5,9 @@ package mop
import ( import (
"github.com/michaeldv/just" "github.com/michaeldv/just"
"github.com/nsf/termbox-go" "github.com/nsf/termbox-go"
"time"
"regexp" "regexp"
"strings" "strings"
"time"
) )
// Can combine attributes and a single color using bitwise OR. // Can combine attributes and a single color using bitwise OR.
@ -31,71 +31,31 @@ var tags = map[string]termbox.Attribute{
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func DrawMarket() { func DrawMarket() {
market := GetMarket() 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)) drawScreen(FormatMarket(market))
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func DrawQuotes(stocks string) { func DrawQuotes(stocks string) {
quotes := GetQuotes(stocks) 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)) drawScreen(FormatQuotes(quotes))
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func DrawTime() { func DrawTime() {
now := time.Now().Format("3:04:05pm PST") now := time.Now().Format("3:04:05pm PST")
drawLine(0, 0, "<right>" + now + "</right>") DrawLine(0, 0, "<right>"+now+"</right>")
}
//
// Return regular expression that matches all possible tags, i.e.
// </?black>|</?red>| ... |</?white>
//-----------------------------------------------------------------------------
func tagsRegexp() *regexp.Regexp {
arr := []string{}
for tag, _ := range tags {
arr = append(arr, "</?"+tag+">")
}
return regexp.MustCompile(strings.Join(arr, "|"))
} }
//
// Return true if a string looks like a tag.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func isTag(str string) (is bool, open bool) { func ClearLine(x int, y int) {
is = (len(str) > 3 && str[0:1] == "<" && str[len(str)-1:] == ">") width, _ := termbox.Size()
open = (is && str[1:2] != "/") for i := x; i < width; i++ {
return termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
}
//
// Extract tag name from the given tag, i.e. "<hello>" => "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 drawLine(x int, y int, str string) { func DrawLine(x int, y int, str string) {
column, right := 0, false column, right := 0, false
foreground, background := termbox.ColorDefault, termbox.ColorDefault foreground, background := termbox.ColorDefault, termbox.ColorDefault
@ -133,6 +93,42 @@ func drawLine(x int, y int, str string) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func drawScreen(str string) { func drawScreen(str string) {
for row, line := range strings.Split(str, "\n") { 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.
// </?black>|</?red>| ... |</?white>
//-----------------------------------------------------------------------------
func tagsRegexp() *regexp.Regexp {
arr := []string{}
for tag, _ := range tags {
arr = append(arr, "</?"+tag+">")
}
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>" => "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]
} }
} }

@ -3,12 +3,11 @@
package mop package mop
import ( import (
//"fmt"
"bytes" "bytes"
"io/ioutil"
"net/http"
"regexp" "regexp"
"strings" "strings"
"net/http"
"io/ioutil"
) )
type Market struct { type Market struct {
@ -59,7 +58,7 @@ func extract(snippet []byte) Market {
regex := []string{ regex := []string{
"(Dow)", any, price, some, arrow, any, price, some, percent, any, "(Dow)", any, price, some, arrow, any, price, some, percent, any,
"(Nasdaq)", 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, "(S&P 500)", any, price, some, arrow, any, price, some, percent, any,
"(Advances)", any, price, space, percent, any, price, space, percent, any, "(Advances)", any, price, space, percent, any, price, space, percent, any,
"(Declines)", any, price, space, percent, any, price, space, percent, any, "(Declines)", any, price, space, percent, any, price, space, percent, any,
@ -90,6 +89,7 @@ func extract(snippet []byte) Market {
Highs: make(map[string]string), Highs: make(map[string]string),
Lows: make(map[string]string), Lows: make(map[string]string),
} }
return m
m.Dow[`name`] = matches[0][1] m.Dow[`name`] = matches[0][1]
m.Dow[`latest`] = matches[0][2] m.Dow[`latest`] = matches[0][2]
m.Dow[`change`] = matches[0][4] m.Dow[`change`] = matches[0][4]
@ -146,5 +146,5 @@ func extract(snippet []byte) Market {
m.Lows[`nyse`] = matches[0][35] m.Lows[`nyse`] = matches[0][35]
m.Lows[`nasdaq`] = matches[0][36] m.Lows[`nasdaq`] = matches[0][36]
return m; return m
} }

@ -3,11 +3,11 @@
package mop package mop
import ( import (
"fmt"
"bytes" "bytes"
"strings" "fmt"
"net/http"
"io/ioutil" "io/ioutil"
"net/http"
"strings"
) )
// See http://www.gummy-stuff.org/Yahoo-data.htm // See http://www.gummy-stuff.org/Yahoo-data.htm
@ -93,7 +93,7 @@ func parse(body []byte) Quotes {
lines := bytes.Split(body, []byte{'\n'}) lines := bytes.Split(body, []byte{'\n'})
quotes := make(Quotes, len(lines)) quotes := make(Quotes, len(lines))
for i,line := range lines { for i, line := range lines {
// fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line)) // fmt.Printf("\n\n{%d} -> [%s]\n\n", i, string(line))
parse_line(line, &quotes[i]) parse_line(line, &quotes[i])
} }

@ -18,6 +18,7 @@ func initTermbox() {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func mainLoop(profile string) { func mainLoop(profile string) {
var line_editor *mop.LineEditor
keyboard_queue := make(chan termbox.Event) keyboard_queue := make(chan termbox.Event)
timestamp_queue := time.NewTicker(1 * time.Second) timestamp_queue := time.NewTicker(1 * time.Second)
quotes_queue := time.NewTicker(5 * time.Second) quotes_queue := time.NewTicker(5 * time.Second)
@ -38,8 +39,18 @@ loop:
case event := <-keyboard_queue: case event := <-keyboard_queue:
switch event.Type { switch event.Type {
case termbox.EventKey: case termbox.EventKey:
if line_editor == nil {
if event.Key == termbox.KeyEsc { if event.Key == termbox.KeyEsc {
break loop 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: case termbox.EventResize:
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)

Loading…
Cancel
Save