diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9fe1ace --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bombadillo diff --git a/cmdparse/lexer.go b/cmdparse/lexer.go index 2553cc1..4be43d9 100644 --- a/cmdparse/lexer.go +++ b/cmdparse/lexer.go @@ -2,34 +2,32 @@ package cmdparse import ( "bufio" - "strings" - "io" "bytes" + "io" + "strings" ) - - //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ type Token struct { - kind tok - val string + kind tok + val string } type scanner struct { - r *bufio.Reader + r *bufio.Reader } type tok int - //------------------------------------------------\\ // + + + V A R I A B L E S + + + \\ //--------------------------------------------------\\ var eof rune = rune(0) + const ( Word tok = iota Action @@ -43,7 +41,6 @@ const ( illegal ) - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ @@ -74,9 +71,9 @@ func (s *scanner) scanText() Token { capInput := strings.ToUpper(buf.String()) switch capInput { - case "DELETE", "ADD", "WRITE", "SET", "RECALL", "R", "SEARCH", - "W", "A", "D", "S", "Q", "QUIT", "B", "BOOKMARKS", "H", "HOME", "HELP": - return Token{Action, capInput} + case "DELETE", "ADD", "WRITE", "SET", "RECALL", "R", "SEARCH", + "W", "A", "D", "S", "Q", "QUIT", "B", "BOOKMARKS", "H", "HOME", "HELP": + return Token{Action, capInput} } return Token{Word, buf.String()} @@ -94,7 +91,7 @@ func (s *scanner) scanWhitespace() Token { s.unread() break } else { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } } @@ -105,7 +102,7 @@ func (s *scanner) scanWhitespace() Token { func (s *scanner) scanNumber() Token { var buf bytes.Buffer buf.WriteRune(s.read()) - + for { if ch := s.read(); ch == eof { break @@ -113,10 +110,10 @@ func (s *scanner) scanNumber() Token { s.unread() break } else { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } } - + return Token{Value, buf.String()} } @@ -134,7 +131,7 @@ func (s *scanner) scan() Token { } else if isLetter(char) { s.unread() return s.scanText() - } + } if char == eof { return Token{End, ""} @@ -143,7 +140,6 @@ func (s *scanner) scan() Token { return Token{illegal, string(char)} } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ @@ -167,4 +163,3 @@ func isDigit(ch rune) bool { func isEOF(ch rune) bool { return ch == rune(0) } - diff --git a/cmdparse/parser.go b/cmdparse/parser.go index 202bfb3..5ea8af4 100644 --- a/cmdparse/parser.go +++ b/cmdparse/parser.go @@ -1,31 +1,31 @@ package cmdparse import ( - "io" "fmt" + "io" ) - //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ type Parser struct { - s *scanner - buffer struct { - token Token - size int + s *scanner + buffer struct { + token Token + size int } } type Command struct { - Action string - Target string - Value []string - Type Comtype + Action string + Target string + Value []string + Type Comtype } type Comtype int + const ( GOURL Comtype = iota GOLINK @@ -35,7 +35,6 @@ const ( DOAS ) - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ @@ -55,7 +54,7 @@ func (p *Parser) scan() (current Token) { } p.buffer.token = current - return + return } func (p *Parser) unscan() { p.buffer.size = 1 } @@ -88,17 +87,17 @@ func (p *Parser) parseAction() (*Command, error) { cm.Action = t.val t = p.scan() switch t.kind { - case End: - cm.Type = SIMPLE - return cm, nil - case Value: - cm.Target = t.val - cm.Type = DOLINK - case Word: - cm.Value = append(cm.Value, t.val) - cm.Type = DOAS - case Action, Whitespace: - return nil, fmt.Errorf("Found %q (%d), expected value", t.val, t.kind) + case End: + cm.Type = SIMPLE + return cm, nil + case Value: + cm.Target = t.val + cm.Type = DOLINK + case Word: + cm.Value = append(cm.Value, t.val) + cm.Type = DOAS + case Action, Whitespace: + return nil, fmt.Errorf("Found %q (%d), expected value", t.val, t.kind) } t = p.scan() if t.kind == End { @@ -118,7 +117,7 @@ func (p *Parser) parseAction() (*Command, error) { } else if token.kind == Whitespace { continue } - cm.Value = append(cm.Value, token.val) + cm.Value = append(cm.Value, token.val) } } return cm, nil @@ -132,7 +131,6 @@ func (p *Parser) Parse() (*Command, error) { } } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ diff --git a/config/lexer.go b/config/lexer.go index 3be62a2..fd398d9 100644 --- a/config/lexer.go +++ b/config/lexer.go @@ -2,29 +2,26 @@ package config import ( "bufio" - "io" "bytes" "fmt" + "io" ) - - //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ type Token struct { - kind TokenType - val string + kind TokenType + val string } type scanner struct { - r *bufio.Reader + r *bufio.Reader } type TokenType int - //------------------------------------------------\\ // + + + V A R I A B L E S + + + \\ //--------------------------------------------------\\ @@ -35,7 +32,6 @@ var r_brace rune = ']' var newline rune = '\n' var equal rune = '=' - const ( TOK_SECTION TokenType = iota TOK_KEY @@ -47,7 +43,6 @@ const ( TOK_WHITESPACE ) - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ @@ -68,7 +63,7 @@ func (s *scanner) skipWhitespace() { } else if !isWhitespace(ch) { s.unread() break - } + } } } @@ -87,7 +82,7 @@ func (s *scanner) skipToEndOfLine() { func (s *scanner) scanSection() Token { var buf bytes.Buffer buf.WriteRune(s.read()) - + for { if ch := s.read(); ch == eof { s.unread() @@ -103,10 +98,10 @@ func (s *scanner) scanSection() Token { s.skipToEndOfLine() return Token{TOK_ERROR, "Second left brace encountered before closing right brace in section"} } else { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } } - + return Token{TOK_SECTION, buf.String()} } @@ -127,7 +122,7 @@ func (s *scanner) scanKey() Token { s.skipToEndOfLine() return Token{TOK_ERROR, "Illegal brace character in key"} } else { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } } @@ -142,7 +137,7 @@ func (s *scanner) scanValue() Token { s.unread() break } else if ch == equal { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } else if ch == newline { s.unread() break @@ -150,7 +145,7 @@ func (s *scanner) scanValue() Token { s.skipToEndOfLine() return Token{TOK_ERROR, "Illegal brace character in key"} } else { - _,_ = buf.WriteRune(ch) + _, _ = buf.WriteRune(ch) } } @@ -164,11 +159,11 @@ func (s *scanner) scan() Token { if isWhitespace(char) { s.skipWhitespace() - } - + } + if char == l_brace { return s.scanSection() - } else if isText(char) { + } else if isText(char) { s.unread() return s.scanKey() } else if char == equal { @@ -184,7 +179,6 @@ func (s *scanner) scan() Token { return Token{TOK_ERROR, fmt.Sprintf("Error on character %q", char)} } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ diff --git a/config/parser.go b/config/parser.go index 9d759dc..831d0c3 100644 --- a/config/parser.go +++ b/config/parser.go @@ -1,38 +1,36 @@ package config import ( - "io" "fmt" + "io" "strings" - "bombadillo/gopher" + "tildegit.org/sloum/bombadillo/gopher" ) - //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ type Parser struct { - s *scanner - row int - buffer struct { - token Token - size int + s *scanner + row int + buffer struct { + token Token + size int } } type Config struct { - Bookmarks gopher.Bookmarks - Colors []KeyValue - Settings []KeyValue + Bookmarks gopher.Bookmarks + Colors []KeyValue + Settings []KeyValue } type KeyValue struct { - Key string - Value string + Key string + Value string } - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ @@ -45,7 +43,7 @@ func (p *Parser) scan() (current Token) { current = p.s.scan() p.buffer.token = current - return + return } func (p *Parser) parseKeyValue() (KeyValue, error) { @@ -68,7 +66,6 @@ func (p *Parser) parseKeyValue() (KeyValue, error) { func (p *Parser) unscan() { p.buffer.size = 1 } - func (p *Parser) Parse() (Config, error) { p.row = 1 section := "" @@ -88,12 +85,12 @@ func (p *Parser) Parse() (Config, error) { return Config{}, err } switch section { - case "BOOKMARKS": - c.Bookmarks.Add([]string{keyval.Value, keyval.Key}) - case "COLORS": - c.Colors = append(c.Colors, keyval) - case "SETTINGS": - c.Settings = append(c.Settings, keyval) + case "BOOKMARKS": + c.Bookmarks.Add([]string{keyval.Value, keyval.Key}) + case "COLORS": + c.Colors = append(c.Colors, keyval) + case "SETTINGS": + c.Settings = append(c.Settings, keyval) } } else if t.kind == TOK_ERROR { return Config{}, fmt.Errorf("Error on row %d: %s", p.row, t.val) @@ -103,7 +100,6 @@ func (p *Parser) Parse() (Config, error) { return c, nil } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ diff --git a/cui/cui.go b/cui/cui.go index 278cb3b..d8685f8 100644 --- a/cui/cui.go +++ b/cui/cui.go @@ -1,30 +1,29 @@ package cui import ( - "strings" + "bufio" "bytes" "fmt" - "bufio" "os" "os/exec" + "strings" ) var shapes = map[string]string{ - "wall": "╵", - "ceiling": "╴", - "tl": "┌", - "tr": "┐", - "bl": "└", - "br": "┘", - "awall": "║", + "wall": "╵", + "ceiling": "╴", + "tl": "┌", + "tr": "┐", + "bl": "└", + "br": "┘", + "awall": "║", "aceiling": "═", - "atl": "╔", - "atr": "╗", - "abl": "╚", - "abr": "╝", + "atl": "╔", + "atr": "╗", + "abl": "╚", + "abr": "╝", } - func drawShape(shape string) { if val, ok := shapes[shape]; ok { fmt.Printf("%s", val) @@ -44,9 +43,9 @@ func MoveCursorTo(row, col int) { func moveCursorToward(dir string, amount int) { directions := map[string]string{ - "up": "A", - "down": "B", - "left": "D", + "up": "A", + "down": "B", + "left": "D", "right": "C", } @@ -66,11 +65,11 @@ func Exit() { func Clear(dir string) { directions := map[string]string{ - "up": "\033[1J", - "down": "\033[0J", - "left": "\033[1K", - "right": "\033[0K", - "line": "\033[2K", + "up": "\033[1J", + "down": "\033[0J", + "left": "\033[1K", + "right": "\033[0K", + "line": "\033[2K", "screen": "\033[2J", } @@ -90,22 +89,22 @@ func WrapLines(s []string, length int) []string { var subout bytes.Buffer for i, wd := range words { sublen := subout.Len() - if sublen + len(wd) + 1 <= length { + if sublen+len(wd)+1 <= length { if sublen > 0 { subout.WriteString(" ") } - subout.WriteString(wd) - if i == len(words) - 1 { + subout.WriteString(wd) + if i == len(words)-1 { out = append(out, subout.String()) } } else { + out = append(out, subout.String()) + subout.Reset() + subout.WriteString(wd) + if i == len(words)-1 { out = append(out, subout.String()) subout.Reset() - subout.WriteString(wd) - if i == len(words) - 1 { - out = append(out, subout.String()) - subout.Reset() - } + } } } } diff --git a/cui/msgbar.go b/cui/msgbar.go index c4f18c5..7524780 100644 --- a/cui/msgbar.go +++ b/cui/msgbar.go @@ -3,31 +3,30 @@ package cui // MsgBar is a struct to represent a single row horizontal // bar on the screen. type MsgBar struct { - row int - title string - message string - showTitle bool + row int + title string + message string + showTitle bool } - // SetTitle sets the title for the MsgBar in question -func (m *MsgBar) SetTitle(s string) { - m.title = s +func (m *MsgBar) SetTitle(s string) { + m.title = s } // SetMessage sets the message for the MsgBar in question -func (m *MsgBar) SetMessage(s string) { - m.message = s +func (m *MsgBar) SetMessage(s string) { + m.message = s } // ClearAll clears all text from the message bar (title and message) -func (m MsgBar) ClearAll() { +func (m MsgBar) ClearAll() { MoveCursorTo(m.row, 1) Clear("line") } // ClearMessage clears all message text while leaving the title in place func (m *MsgBar) ClearMessage() { - MoveCursorTo(m.row, len(m.title) + 1) + MoveCursorTo(m.row, len(m.title)+1) Clear("right") } diff --git a/cui/screen.go b/cui/screen.go index bd1f7fc..73ed3db 100644 --- a/cui/screen.go +++ b/cui/screen.go @@ -1,11 +1,11 @@ package cui import ( - "strings" + "bytes" "fmt" "os" "os/exec" - "bytes" + "strings" ) // screenInit records whether or not the screen has been initialized @@ -17,14 +17,13 @@ var screenInit bool = false // holds the various Windows and MsgBars for the application as well // as a record of which window is active for control purposes. type Screen struct { - Height int - Width int - Windows []*Window - Activewindow int - Bars []*MsgBar + Height int + Width int + Windows []*Window + Activewindow int + Bars []*MsgBar } - // AddWindow adds a new window to the Screen struct in question func (s *Screen) AddWindow(r1, c1, r2, c2 int, scroll, border, show bool) { w := Window{box{r1, c1, r2, c2}, scroll, 0, []string{}, border, false, show} @@ -46,7 +45,7 @@ func (s Screen) DrawAllWindows() { w.DrawWindow() } } - MoveCursorTo(s.Height - 1, 1) + MoveCursorTo(s.Height-1, 1) } // Clear removes all content from the interior of the screen @@ -57,7 +56,6 @@ func (s Screen) Clear() { } } - // ReflashScreen checks for a screen resize and resizes windows if // needed then redraws the screen. It takes a bool to decide whether // to redraw the full screen or just the content. On a resize @@ -108,12 +106,12 @@ func (s *Screen) DrawMsgBars() { title := bar.title fmt.Print(title) if len(bar.title) > s.Width { - title = string(bar.title[:s.Width - 3]) + "..." + title = string(bar.title[:s.Width-3]) + "..." } _, _ = buf.WriteString(title) msg := bar.message - if len(bar.message) > s.Width - len(title) { - msg = string(bar.message[:s.Width - len(title) - 3]) + "..." + if len(bar.message) > s.Width-len(title) { + msg = string(bar.message[:s.Width-len(title)-3]) + "..." } _, _ = buf.WriteString(msg) @@ -124,24 +122,22 @@ func (s *Screen) DrawMsgBars() { } } - // GetSize retrieves the terminal size and sets the Screen // width and height to that size func (s *Screen) GetSize() { - cmd := exec.Command("stty", "size") - cmd.Stdin = os.Stdin - out, err := cmd.Output() - if err != nil { + cmd := exec.Command("stty", "size") + cmd.Stdin = os.Stdin + out, err := cmd.Output() + if err != nil { fmt.Println("Fatal error: Unable to retrieve terminal size") os.Exit(1) - } + } var h, w int fmt.Sscan(string(out), &h, &w) s.Height = h s.Width = w } - // - - - - - - - - - - - - - - - - - - - - - - - - - - // NewScreen is a constructor function that returns a pointer diff --git a/cui/window.go b/cui/window.go index 6cd774c..49deeef 100644 --- a/cui/window.go +++ b/cui/window.go @@ -5,23 +5,22 @@ import ( "strings" ) - type box struct { - row1 int - col1 int - row2 int - col2 int + row1 int + col1 int + row2 int + col2 int } // TODO add coloring type Window struct { - Box box - Scrollbar bool - Scrollposition int - Content []string - drawBox bool - Active bool - Show bool + Box box + Scrollbar bool + Scrollposition int + Content []string + drawBox bool + Active bool + Show bool } func (w *Window) DrawWindow() { @@ -32,42 +31,42 @@ func (w *Window) DrawWindow() { } } -func (w *Window) DrawBox(){ +func (w *Window) DrawBox() { lead := "" if w.Active { lead = "a" } - moveThenDrawShape(w.Box.row1, w.Box.col1, lead + "tl") - moveThenDrawShape(w.Box.row1, w.Box.col2, lead + "tr") - moveThenDrawShape(w.Box.row2, w.Box.col1, lead + "bl") - moveThenDrawShape(w.Box.row2, w.Box.col2, lead + "br") + moveThenDrawShape(w.Box.row1, w.Box.col1, lead+"tl") + moveThenDrawShape(w.Box.row1, w.Box.col2, lead+"tr") + moveThenDrawShape(w.Box.row2, w.Box.col1, lead+"bl") + moveThenDrawShape(w.Box.row2, w.Box.col2, lead+"br") for i := w.Box.col1 + 1; i < w.Box.col2; i++ { - moveThenDrawShape(w.Box.row1, i, lead + "ceiling") - moveThenDrawShape(w.Box.row2, i, lead + "ceiling") + moveThenDrawShape(w.Box.row1, i, lead+"ceiling") + moveThenDrawShape(w.Box.row2, i, lead+"ceiling") } - for i:= w.Box.row1 + 1; i < w.Box.row2; i++ { - moveThenDrawShape(i, w.Box.col1, lead + "wall") - moveThenDrawShape(i, w.Box.col2, lead + "wall") + for i := w.Box.row1 + 1; i < w.Box.row2; i++ { + moveThenDrawShape(i, w.Box.col1, lead+"wall") + moveThenDrawShape(i, w.Box.col2, lead+"wall") } } -func (w *Window) DrawContent(){ - var maxlines, border_thickness, contenth int +func (w *Window) DrawContent() { + var maxlines, borderThickness, contenth int var short_content bool = false if w.drawBox { - border_thickness, contenth = -1, 1 + borderThickness, contenth = -1, 1 } else { - border_thickness, contenth = 1, 0 + borderThickness, contenth = 1, 0 } - height := w.Box.row2 - w.Box.row1 + border_thickness - width := w.Box.col2 - w.Box.col1 + border_thickness + height := w.Box.row2 - w.Box.row1 + borderThickness + width := w.Box.col2 - w.Box.col1 + borderThickness content := WrapLines(w.Content, width) - if len(content) < w.Scrollposition + height { + if len(content) < w.Scrollposition+height { maxlines = len(content) short_content = true } else { @@ -75,30 +74,30 @@ func (w *Window) DrawContent(){ } for i := w.Scrollposition; i < maxlines; i++ { - MoveCursorTo(w.Box.row1 + contenth + i - w.Scrollposition, w.Box.col1 + contenth) - fmt.Print( strings.Repeat(" ", width) ) - MoveCursorTo(w.Box.row1 + contenth + i - w.Scrollposition, w.Box.col1 + contenth) + MoveCursorTo(w.Box.row1+contenth+i-w.Scrollposition, w.Box.col1+contenth) + fmt.Print(strings.Repeat(" ", width)) + MoveCursorTo(w.Box.row1+contenth+i-w.Scrollposition, w.Box.col1+contenth) fmt.Print(content[i]) } if short_content { for i := len(content); i <= height; i++ { - MoveCursorTo(w.Box.row1 + contenth + i - w.Scrollposition, w.Box.col1 + contenth) - fmt.Print( strings.Repeat(" ", width) ) + MoveCursorTo(w.Box.row1+contenth+i-w.Scrollposition, w.Box.col1+contenth) + fmt.Print(strings.Repeat(" ", width)) } } } func (w *Window) ScrollDown() { - var border_thickness int + var borderThickness int if w.drawBox { - border_thickness = -1 + borderThickness = -1 } else { - border_thickness = 1 + borderThickness = 1 } - height := w.Box.row2 - w.Box.row1 + border_thickness + height := w.Box.row2 - w.Box.row1 + borderThickness contentLength := len(w.Content) - if w.Scrollposition < contentLength - height { + if w.Scrollposition < contentLength-height { w.Scrollposition++ } else { fmt.Print("\a") @@ -112,4 +111,3 @@ func (w *Window) ScrollUp() { fmt.Print("\a") } } - diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..143f7b1 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module tildegit.org/sloum/bombadillo + +go 1.10 diff --git a/gopher/bookmark.go b/gopher/bookmark.go index 8051178..88d39ba 100644 --- a/gopher/bookmark.go +++ b/gopher/bookmark.go @@ -9,24 +9,19 @@ import ( // + + + T Y P E S + + + \\ //--------------------------------------------------\\ - //Bookmarks is a holder for titles and links that //can be retrieved by index type Bookmarks struct { - Titles []string - Links []string + Titles []string + Links []string } - - - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ - // Add adds a new title and link combination to the bookmarks -// struct. It takes as input a string slice in which the first +// struct. It takes as input a string slice in which the first // element represents the link and all following items represent // the title of the bookmark (they will be joined with spaces). func (b *Bookmarks) Add(v []string) error { @@ -40,8 +35,8 @@ func (b *Bookmarks) Add(v []string) error { func (b *Bookmarks) Del(i int) error { if i < len(b.Titles) && i < len(b.Links) { - b.Titles = append(b.Titles[:i], b.Titles[i + 1:]...) - b.Links = append(b.Links[:i], b.Links[i + 1:]...) + b.Titles = append(b.Titles[:i], b.Titles[i+1:]...) + b.Links = append(b.Links[:i], b.Links[i+1:]...) return nil } return fmt.Errorf("Bookmark %d does not exist", i) @@ -55,7 +50,6 @@ func (b Bookmarks) List() []string { return out } - func (b Bookmarks) IniDump() string { if len(b.Titles) < 0 { return "" @@ -70,7 +64,6 @@ func (b Bookmarks) IniDump() string { return out } - func MakeBookmarks() Bookmarks { return Bookmarks{[]string{}, []string{}} } diff --git a/gopher/gopher.go b/gopher/gopher.go index 4d3e185..de8535e 100644 --- a/gopher/gopher.go +++ b/gopher/gopher.go @@ -4,17 +4,16 @@ package gopher import ( - "strings" "errors" - "net" + "fmt" "io/ioutil" - "time" + "net" "os/exec" "runtime" - "fmt" + "strings" + "time" ) - //------------------------------------------------\\ // + + + V A R I A B L E S + + + \\ //--------------------------------------------------\\ @@ -37,25 +36,22 @@ var types = map[string]string{ "p": "PNG", } - - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ - // Retrieve makes a request to a Url and resturns // the response as []byte/error. This function is // available to use directly, but in most implementations // using the "Visit" receiver of the History struct will // be better. func Retrieve(u Url) ([]byte, error) { - nullRes := make([]byte, 0) + nullRes := make([]byte, 0) timeOut := time.Duration(5) * time.Second - if u.Host == "" || u.Port == "" { + if u.Host == "" || u.Port == "" { return nullRes, errors.New("Incomplete request url") - } + } addr := u.Host + ":" + u.Port @@ -82,7 +78,6 @@ func Retrieve(u Url) ([]byte, error) { return result, err } - // Visit is a high level combination of a few different // types that makes it easy to create a Url, make a request // to that Url, and add the response and Url to a View. @@ -121,7 +116,7 @@ func Visit(addr, openhttp string) (View, error) { func GetType(t string) string { if val, ok := types[t]; ok { return val - } + } return "???" } diff --git a/gopher/history.go b/gopher/history.go index 2f34d21..5fdc439 100644 --- a/gopher/history.go +++ b/gopher/history.go @@ -1,8 +1,8 @@ package gopher import ( - "fmt" "errors" + "fmt" ) //------------------------------------------------\\ @@ -17,12 +17,11 @@ import ( // each page in the current history. In general usage this // struct should be initialized via the MakeHistory function. type History struct { - Position int - Length int - Collection [20]View + Position int + Length int + Collection [20]View } - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ @@ -34,11 +33,11 @@ type History struct { // history length if something is added in the middle. func (h *History) Add(v View) { v.ParseMap() - if h.Position == h.Length - 1 && h.Length < len(h.Collection) { + if h.Position == h.Length-1 && h.Length < len(h.Collection) { h.Collection[h.Length] = v h.Length++ h.Position++ - } else if h.Position == h.Length - 1 && h.Length == 20 { + } else if h.Position == h.Length-1 && h.Length == 20 { for x := 1; x < len(h.Collection); x++ { h.Collection[x-1] = h.Collection[x] } @@ -76,13 +75,12 @@ func (h *History) GoBack() bool { return false } - // The "GoForward" receiver is called by a history struct. // When called it increments the current position and // displays the content for the View in that position. // If history is at position len - 1, no action is taken. func (h *History) GoForward() bool { - if h.Position + 1 < h.Length { + if h.Position+1 < h.Length { h.Position++ return true } @@ -100,12 +98,10 @@ func (h *History) DisplayCurrentView() { h.Collection[h.Position].Display() } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ - // Constructor function for History struct. // This is used to initialize history position // as -1, which is needed. Returns a copy of diff --git a/gopher/url.go b/gopher/url.go index 993ab46..2bfb743 100644 --- a/gopher/url.go +++ b/gopher/url.go @@ -1,34 +1,32 @@ package gopher import ( - "regexp" "errors" + "regexp" ) //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ - // The url struct represents a URL for the rest of the system. // It includes component parts as well as a full URL string. type Url struct { - Scheme string - Host string - Port string - Gophertype string - Resource string - Full string - IsBinary bool + Scheme string + Host string + Port string + Gophertype string + Resource string + Full string + IsBinary bool } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ -// MakeUrl is a Url constructor that takes in a string -// representation of a url and returns a Url struct and +// MakeUrl is a Url constructor that takes in a string +// representation of a url and returns a Url struct and // an error (or nil). func MakeUrl(u string) (Url, error) { var out Url @@ -41,16 +39,16 @@ func MakeUrl(u string) (Url, error) { for i, name := range re.SubexpNames() { switch name { - case "scheme": - out.Scheme = match[i] - case "host": - out.Host = match[i] - case "port": - out.Port = match[i] - case "type": - out.Gophertype = match[i] - case "resource": - out.Resource = match[i] + case "scheme": + out.Scheme = match[i] + case "host": + out.Host = match[i] + case "port": + out.Port = match[i] + case "type": + out.Gophertype = match[i] + case "resource": + out.Resource = match[i] } } @@ -70,13 +68,13 @@ func MakeUrl(u string) (Url, error) { if out.Gophertype == "" && (out.Resource == "" || out.Resource == "/") { out.Gophertype = "1" - } + } switch out.Gophertype { - case "1", "0", "h", "7": - out.IsBinary = false - default: - out.IsBinary = true + case "1", "0", "h", "7": + out.IsBinary = false + default: + out.IsBinary = true } if out.Scheme == "gopher" && out.Gophertype == "" { @@ -87,4 +85,3 @@ func MakeUrl(u string) (Url, error) { return out, nil } - diff --git a/gopher/view.go b/gopher/view.go index 127ea17..90ee256 100644 --- a/gopher/view.go +++ b/gopher/view.go @@ -1,33 +1,28 @@ package gopher import ( - "strings" "fmt" + "strings" ) - - //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ - // View is a struct representing a gopher page. It contains // the page content as a string slice, a list of link URLs // as string slices, and the Url struct representing the page. type View struct { - Content []string - Links []string - Address Url + Content []string + Links []string + Address Url } - //------------------------------------------------\\ // + + + R E C E I V E R S + + + \\ //--------------------------------------------------\\ - -// ParseMap is called by a view struct to parse a gophermap. +// ParseMap is called by a view struct to parse a gophermap. // It checks if the view is for a gophermap. If not,it does // nothing. If so, it parses the gophermap into comment lines // and link lines. For link lines it adds a link to the links @@ -44,7 +39,7 @@ func (v *View) ParseMap() { continue } - line := strings.Split(e,"\t") + line := strings.Split(e, "\t") var title string if len(line[0]) > 1 { title = line[0][1:] @@ -61,7 +56,7 @@ func (v *View) ParseMap() { v.Content[i] = linktext } } - } + } } // Display is called on a view struct to print the contents of the view. @@ -73,12 +68,10 @@ func (v View) Display() { } } - //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ - // MakeView creates and returns a new View struct from // a Url and a string splice of content. This is used to // initialize a View with a Url struct, links, and content. @@ -89,5 +82,3 @@ func MakeView(url Url, content []string) View { v.ParseMap() return v } - - diff --git a/bombadillo.go b/main.go similarity index 54% rename from bombadillo.go rename to main.go index 69a0606..a438e0e 100644 --- a/bombadillo.go +++ b/main.go @@ -1,38 +1,38 @@ package main import ( - "bombadillo/gopher" - "bombadillo/cmdparse" - "bombadillo/config" - "bombadillo/cui" - "os/user" + "fmt" "io/ioutil" "os" - "fmt" - "strings" + "os/user" "regexp" "strconv" + "strings" + "tildegit.org/sloum/bombadillo/cmdparse" + "tildegit.org/sloum/bombadillo/config" + "tildegit.org/sloum/bombadillo/cui" + "tildegit.org/sloum/bombadillo/gopher" ) -var helplocation string ="gopher://colorfield.space:70/1/bombadillo-info" +var helplocation string = "gopher://colorfield.space:70/1/bombadillo-info" var history gopher.History = gopher.MakeHistory() var screen *cui.Screen var userinfo, _ = user.Current() var settings config.Config var options = map[string]string{ - "homeurl": "gopher://colorfield.space:70/1/bombadillo-info", + "homeurl": "gopher://colorfield.space:70/1/bombadillo-info", "savelocation": userinfo.HomeDir + "/Downloads/", "searchengine": "gopher://gopher.floodgap.com:70/7/v2/vs", - "openhttp": "false", - "httpbrowser": "lynx", + "openhttp": "false", + "httpbrowser": "lynx", } -func err_exit(err string, code int) { +func errExit(err string, code int) { fmt.Println(err) os.Exit(code) } -func save_file(address, name string) error { +func saveFile(address, name string) error { quickMessage("Saving file...", false) defer quickMessage("Saving file...", true) @@ -46,7 +46,7 @@ func save_file(address, name string) error { return err } - err = ioutil.WriteFile(options["savelocation"] + name, data, 0644) + err = ioutil.WriteFile(options["savelocation"]+name, data, 0644) if err != nil { return err } @@ -54,25 +54,25 @@ func save_file(address, name string) error { return fmt.Errorf("Saved file to " + options["savelocation"] + name) } -func save_file_from_data(v gopher.View) error { +func saveFileFromData(v gopher.View) error { urlsplit := strings.Split(v.Address.Full, "/") - filename := urlsplit[len(urlsplit) - 1] - save_msg := fmt.Sprintf("Saved file as %q", options["savelocation"] + filename) - quickMessage(save_msg, false) - defer quickMessage(save_msg, true) - err := ioutil.WriteFile(options["savelocation"] + filename, []byte(strings.Join(v.Content, "")), 0644) + filename := urlsplit[len(urlsplit)-1] + saveMsg := fmt.Sprintf("Saved file as %q", options["savelocation"]+filename) + quickMessage(saveMsg, false) + defer quickMessage(saveMsg, true) + err := ioutil.WriteFile(options["savelocation"]+filename, []byte(strings.Join(v.Content, "")), 0644) if err != nil { return err } - return fmt.Errorf(save_msg) + return fmt.Errorf(saveMsg) } func search(u string) error { - cui.MoveCursorTo(screen.Height - 1, 0) + cui.MoveCursorTo(screen.Height-1, 0) cui.Clear("line") fmt.Print("Enter form input: ") - cui.MoveCursorTo(screen.Height - 1, 17) + cui.MoveCursorTo(screen.Height-1, 17) entry := cui.GetLine() quickMessage("Searching...", false) searchurl := fmt.Sprintf("%s\t%s", u, entry) @@ -89,30 +89,29 @@ func search(u string) error { return nil } - -func route_input(com *cmdparse.Command) error { +func routeInput(com *cmdparse.Command) error { var err error switch com.Type { - case cmdparse.SIMPLE: - err = simple_command(com.Action) - case cmdparse.GOURL: - err = go_to_url(com.Target) - case cmdparse.GOLINK: - err = go_to_link(com.Target) - case cmdparse.DOLINK: - err = do_link_command(com.Action, com.Target) - case cmdparse.DOAS: - err = do_command_as(com.Action, com.Value) - case cmdparse.DOLINKAS: - err = do_link_command_as(com.Action, com.Target, com.Value) - default: - return fmt.Errorf("Unknown command entry!") + case cmdparse.SIMPLE: + err = simpleCommand(com.Action) + case cmdparse.GOURL: + err = goToURL(com.Target) + case cmdparse.GOLINK: + err = goToLink(com.Target) + case cmdparse.DOLINK: + err = doLinkCommand(com.Action, com.Target) + case cmdparse.DOAS: + err = doCommandAs(com.Action, com.Value) + case cmdparse.DOLINKAS: + err = doLinkCommandAs(com.Action, com.Target, com.Value) + default: + return fmt.Errorf("Unknown command entry!") } return err } -func toggle_bookmarks() { +func toggleBookmarks() { bookmarks := screen.Windows[1] main := screen.Windows[0] if bookmarks.Show { @@ -133,27 +132,27 @@ func toggle_bookmarks() { screen.ReflashScreen(false) } -func simple_command(a string) error { +func simpleCommand(a string) error { a = strings.ToUpper(a) switch a { - case "Q", "QUIT": - cui.Exit() - case "H", "HOME": - return go_home() - case "B", "BOOKMARKS": - toggle_bookmarks() - case "SEARCH": - return search(options["searchengine"]) - case "HELP": - return go_to_url(helplocation) + case "Q", "QUIT": + cui.Exit() + case "H", "HOME": + return goHome() + case "B", "BOOKMARKS": + toggleBookmarks() + case "SEARCH": + return search(options["searchengine"]) + case "HELP": + return goToURL(helplocation) - default: - return fmt.Errorf("Unknown action %q", a) + default: + return fmt.Errorf("Unknown action %q", a) } return nil } -func go_to_url(u string) error { +func goToURL(u string) error { quickMessage("Loading...", false) v, err := gopher.Visit(u, options["openhttp"]) if err != nil { @@ -169,7 +168,7 @@ func go_to_url(u string) error { } } else if v.Address.IsBinary { // TO DO: run this into the write to file method - return save_file_from_data(v) + return saveFileFromData(v) } else { history.Add(v) } @@ -179,12 +178,12 @@ func go_to_url(u string) error { return nil } -func go_to_link(l string) error { +func goToLink(l string) error { if num, _ := regexp.MatchString(`^\d+$`, l); num && history.Length > 0 { linkcount := len(history.Collection[history.Position].Links) item, _ := strconv.Atoi(l) if item <= linkcount { - linkurl := history.Collection[history.Position].Links[item - 1] + linkurl := history.Collection[history.Position].Links[item-1] quickMessage("Loading...", false) v, err := gopher.Visit(linkurl, options["openhttp"]) if err != nil { @@ -199,7 +198,7 @@ func go_to_link(l string) error { return err } } else if v.Address.IsBinary { - return save_file_from_data(v) + return saveFileFromData(v) } else { history.Add(v) } @@ -207,7 +206,7 @@ func go_to_link(l string) error { return fmt.Errorf("Invalid link id: %s", l) } } else { - return fmt.Errorf("Invalid link id: %s", l) + return fmt.Errorf("Invalid link id: %s", l) } updateMainContent() screen.Windows[0].Scrollposition = 0 @@ -215,38 +214,38 @@ func go_to_link(l string) error { return nil } -func go_home() error { +func goHome() error { if options["homeurl"] != "unset" { - return go_to_url(options["homeurl"]) + return goToURL(options["homeurl"]) } return fmt.Errorf("No home address has been set") } -func do_link_command(action, target string) error { +func doLinkCommand(action, target string) error { num, err := strconv.Atoi(target) if err != nil { return fmt.Errorf("Expected number, got %q", target) } switch action { - case "DELETE", "D": - err := settings.Bookmarks.Del(num) - screen.Windows[1].Content = settings.Bookmarks.List() - save_config() - screen.ReflashScreen(false) - return err - case "BOOKMARKS", "B": - if num > len(settings.Bookmarks.Links) - 1 { - return fmt.Errorf("There is no bookmark with ID %d", num) - } - err := go_to_url(settings.Bookmarks.Links[num]) - return err + case "DELETE", "D": + err := settings.Bookmarks.Del(num) + screen.Windows[1].Content = settings.Bookmarks.List() + saveConfig() + screen.ReflashScreen(false) + return err + case "BOOKMARKS", "B": + if num > len(settings.Bookmarks.Links)-1 { + return fmt.Errorf("There is no bookmark with ID %d", num) + } + err := goToURL(settings.Bookmarks.Links[num]) + return err } return fmt.Errorf("This method has not been built") } -func do_command_as(action string, values []string) error { +func doCommandAs(action string, values []string) error { if len(values) < 2 { return fmt.Errorf("%q", values) } @@ -256,29 +255,29 @@ func do_command_as(action string, values []string) error { } switch action { - case "ADD", "A": - err := settings.Bookmarks.Add(values) - if err != nil { - return err - } - screen.Windows[1].Content = settings.Bookmarks.List() - save_config() - screen.ReflashScreen(false) + case "ADD", "A": + err := settings.Bookmarks.Add(values) + if err != nil { + return err + } + screen.Windows[1].Content = settings.Bookmarks.List() + saveConfig() + screen.ReflashScreen(false) + return nil + case "WRITE", "W": + return saveFile(values[0], strings.Join(values[1:], " ")) + case "SET", "S": + if _, ok := options[values[0]]; ok { + options[values[0]] = strings.Join(values[1:], " ") + saveConfig() return nil - case "WRITE", "W": - return save_file(values[0], strings.Join(values[1:], " ")) - case "SET", "S": - if _, ok := options[values[0]]; ok { - options[values[0]] = strings.Join(values[1:], " ") - save_config() - return nil - } - return fmt.Errorf("Unable to set %s, it does not exist",values[0]) + } + return fmt.Errorf("Unable to set %s, it does not exist", values[0]) } return fmt.Errorf("Unknown command structure") } -func do_link_command_as(action, target string, values []string) error { +func doLinkCommandAs(action, target string, values []string) error { num, err := strconv.Atoi(target) if err != nil { return fmt.Errorf("Expected number, got %q", target) @@ -290,31 +289,30 @@ func do_link_command_as(action, target string, values []string) error { } switch action { - case "ADD", "A": - newBookmark := append([]string{links[num - 1]}, values...) - err := settings.Bookmarks.Add(newBookmark) - if err != nil { - return err - } - screen.Windows[1].Content = settings.Bookmarks.List() - save_config() - screen.ReflashScreen(false) - return nil - case "WRITE", "W": - return save_file(links[num - 1], strings.Join(values, " ")) + case "ADD", "A": + newBookmark := append([]string{links[num-1]}, values...) + err := settings.Bookmarks.Add(newBookmark) + if err != nil { + return err + } + screen.Windows[1].Content = settings.Bookmarks.List() + saveConfig() + screen.ReflashScreen(false) + return nil + case "WRITE", "W": + return saveFile(links[num-1], strings.Join(values, " ")) } return fmt.Errorf("This method has not been built") } - func updateMainContent() { screen.Windows[0].Content = history.Collection[history.Position].Content screen.Bars[0].SetMessage(history.Collection[history.Position].Address.Full) } func clearInput(incError bool) { - cui.MoveCursorTo(screen.Height - 1, 0) + cui.MoveCursorTo(screen.Height-1, 0) cui.Clear("line") if incError { cui.MoveCursorTo(screen.Height, 0) @@ -323,7 +321,7 @@ func clearInput(incError bool) { } func quickMessage(msg string, clearMsg bool) { - cui.MoveCursorTo(screen.Height, screen.Width - 2 - len(msg)) + cui.MoveCursorTo(screen.Height, screen.Width-2-len(msg)) if clearMsg { cui.Clear("right") } else { @@ -331,8 +329,7 @@ func quickMessage(msg string, clearMsg bool) { } } - -func save_config() { +func saveConfig() { bkmrks := settings.Bookmarks.IniDump() opts := "\n[SETTINGS]\n" for k, v := range options { @@ -341,14 +338,13 @@ func save_config() { opts += v opts += "\n" } - ioutil.WriteFile(userinfo.HomeDir + "/.bombadillo.ini", []byte(bkmrks+opts), 0644) + ioutil.WriteFile(userinfo.HomeDir+"/.bombadillo.ini", []byte(bkmrks+opts), 0644) } - -func load_config() { +func loadConfig() { file, err := os.Open(userinfo.HomeDir + "/.bombadillo.ini") if err != nil { - save_config() + saveConfig() } confparser := config.NewParser(file) settings, _ = confparser.Parse() @@ -362,7 +358,7 @@ func load_config() { } } -func toggleActiveWindow(){ +func toggleActiveWindow() { if screen.Windows[1].Show { if screen.Windows[0].Active { screen.Windows[0].Active = false @@ -377,39 +373,36 @@ func toggleActiveWindow(){ } } - -func display_error(err error) { +func displayError(err error) { cui.MoveCursorTo(screen.Height, 0) fmt.Print("\033[41m\033[37m", err, "\033[0m") } - func initClient() { history.Position = -1 screen = cui.NewScreen() cui.SetCharMode() - screen.AddWindow(2, 1, screen.Height - 2, screen.Width, false, false, true) + screen.AddWindow(2, 1, screen.Height-2, screen.Width, false, false, true) screen.Windows[0].Active = true screen.AddMsgBar(1, " ((( Bombadillo ))) ", " A fun gopher client!", true) bookmarksWidth := 40 if screen.Width < 40 { bookmarksWidth = screen.Width } - screen.AddWindow(2, screen.Width - bookmarksWidth, screen.Height - 2, screen.Width, false, true, false) - load_config() + screen.AddWindow(2, screen.Width-bookmarksWidth, screen.Height-2, screen.Width, false, true, false) + loadConfig() } - func main() { defer cui.Exit() initClient() mainWindow := screen.Windows[0] - first_load := true + firstLoad := true for { - if first_load { - first_load = false - err := go_home() + if firstLoad { + firstLoad = false + err := goHome() if err == nil { updateMainContent() @@ -419,50 +412,50 @@ func main() { c := cui.Getch() switch c { - case 'j', 'J': - screen.Windows[screen.Activewindow].ScrollDown() - screen.ReflashScreen(false) - case 'k', 'K': - screen.Windows[screen.Activewindow].ScrollUp() - screen.ReflashScreen(false) - case 'q', 'Q': - cui.Exit() - case 'b': - success := history.GoBack() - if success { - mainWindow.Scrollposition = 0 - updateMainContent() - screen.ReflashScreen(true) - } - case 'B': - toggle_bookmarks() - case 'f', 'F': - success := history.GoForward() - if success { - mainWindow.Scrollposition = 0 - updateMainContent() - screen.ReflashScreen(true) - } - case '\t': - toggleActiveWindow() - case ':',' ': - cui.MoveCursorTo(screen.Height - 1, 0) - entry := cui.GetLine() - // Clear entry line and error line - clearInput(true) - if entry == "" { - continue - } - parser := cmdparse.NewParser(strings.NewReader(entry)) - p, err := parser.Parse() + case 'j', 'J': + screen.Windows[screen.Activewindow].ScrollDown() + screen.ReflashScreen(false) + case 'k', 'K': + screen.Windows[screen.Activewindow].ScrollUp() + screen.ReflashScreen(false) + case 'q', 'Q': + cui.Exit() + case 'b': + success := history.GoBack() + if success { + mainWindow.Scrollposition = 0 + updateMainContent() + screen.ReflashScreen(true) + } + case 'B': + toggleBookmarks() + case 'f', 'F': + success := history.GoForward() + if success { + mainWindow.Scrollposition = 0 + updateMainContent() + screen.ReflashScreen(true) + } + case '\t': + toggleActiveWindow() + case ':', ' ': + cui.MoveCursorTo(screen.Height-1, 0) + entry := cui.GetLine() + // Clear entry line and error line + clearInput(true) + if entry == "" { + continue + } + parser := cmdparse.NewParser(strings.NewReader(entry)) + p, err := parser.Parse() + if err != nil { + displayError(err) + } else { + err := routeInput(p) if err != nil { - display_error(err) - } else { - err := route_input(p) - if err != nil { - display_error(err) - } + displayError(err) } + } } } }