diff --git a/bombadillo.go b/bombadillo.go index 57ffc81..f18b21c 100644 --- a/bombadillo.go +++ b/bombadillo.go @@ -45,12 +45,26 @@ func save_file(address, name string) error { return err } - err = ioutil.WriteFile(userinfo.HomeDir + "/" + name, data, 0644) + err = ioutil.WriteFile(options["savelocation"] + name, data, 0644) if err != nil { return err } - return nil + return fmt.Errorf("Saved file to " + options["savelocation"] + name) +} + +func save_file_from_data(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) + if err != nil { + return err + } + + return fmt.Errorf(save_msg) } func search(u string) error { @@ -138,7 +152,7 @@ func go_to_url(u string) error { } } else if v.Address.IsBinary { // TO DO: run this into the write to file method - return fmt.Errorf("Not built yet") + return save_file_from_data(v) } else { history.Add(v) } @@ -165,7 +179,7 @@ func go_to_link(l string) error { return err } } else if v.Address.IsBinary { - // TO DO: run this into the write to file method + return save_file_from_data(v) } else { history.Add(v) } @@ -322,7 +336,7 @@ func display_error(err error, redraw *bool) { func initClient() { history.Position = -1 screen = cui.NewScreen() - screen.SetCharMode() + cui.SetCharMode() screen.AddWindow(2, 1, screen.Height - 2, screen.Width, false, false, true) screen.AddMsgBar(1, " ((( Bombadillo ))) ", " A fun gopher client!", true) bookmarksWidth := 40 diff --git a/cui/msgbar.go b/cui/msgbar.go index 21dcb1e..c4f18c5 100644 --- a/cui/msgbar.go +++ b/cui/msgbar.go @@ -1,10 +1,7 @@ package cui -import ( - -) - - +// MsgBar is a struct to represent a single row horizontal +// bar on the screen. type MsgBar struct { row int title string @@ -12,19 +9,24 @@ type MsgBar struct { showTitle bool } + +// SetTitle sets the title for the MsgBar in question 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 } +// ClearAll clears all text from the message bar (title and message) 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) Clear("right") diff --git a/cui/screen.go b/cui/screen.go index ea47b99..85bfc12 100644 --- a/cui/screen.go +++ b/cui/screen.go @@ -8,9 +8,14 @@ import ( "bytes" ) - +// screenInit records whether or not the screen has been initialized +// this is used to prevent more than one screen from being used var screenInit bool = false +// Screen represent the top level abstraction for a cui application. +// It takes up the full width and height of the terminal window and +// 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 @@ -20,16 +25,20 @@ type Screen struct { } +// 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} s.Windows = append(s.Windows, &w) } +// AddMsgBar adds a new MsgBar to the Screen struct in question func (s *Screen) AddMsgBar(row int, title, msg string, showTitle bool) { b := MsgBar{row, title, msg, showTitle} s.Bars = append(s.Bars, &b) } +// DrawAllWindows loops over every window in the Screen struct and +// draws it to screen in index order (smallest to largest) func (s Screen) DrawAllWindows() { s.Clear() for _, w := range s.Windows { @@ -40,6 +49,7 @@ func (s Screen) DrawAllWindows() { MoveCursorTo(s.Height - 1, 1) } +// Clear removes all content from the interior of the screen func (s Screen) Clear() { fill := strings.Repeat(" ", s.Width) for i := 0; i <= s.Height; i++ { @@ -48,14 +58,9 @@ func (s Screen) Clear() { } } -func (s Screen) SetCharMode() { - exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run() - exec.Command("stty", "-F", "/dev/tty", "-echo").Run() - fmt.Print("\033[?25l") -} -// Checks for a screen resize and resizes windows if needed -// Then redraws the screen. Takes a bool to decide whether +// 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 // event, the full screen will always be redrawn. func (s *Screen) ReflashScreen(clearScreen bool) { @@ -91,6 +96,8 @@ func (s *Screen) ReflashScreen(clearScreen bool) { } } +// DrawMsgBars draws all MsgBars present in the Screen struct. +// All MsgBars are looped over and drawn in index order (sm - lg). func (s *Screen) DrawMsgBars() { for _, bar := range s.Bars { MoveCursorTo(bar.row, 1) @@ -118,6 +125,9 @@ 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 @@ -135,7 +145,8 @@ func (s *Screen) GetSize() { // - - - - - - - - - - - - - - - - - - - - - - - - - - - +// NewScreen is a constructor function that returns a pointer +// to a Screen struct func NewScreen() *Screen { if screenInit { fmt.Println("Fatal error: Cannot create multiple screens") diff --git a/gopher/bookmark.go b/gopher/bookmark.go index f8e1273..8051178 100644 --- a/gopher/bookmark.go +++ b/gopher/bookmark.go @@ -5,11 +5,30 @@ import ( "strings" ) +//------------------------------------------------\\ +// + + + 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 } + + + +//------------------------------------------------\\ +// + + + 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 +// 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 { if len(v) < 2 { return fmt.Errorf("Received %d arguments, expected 2 or more", len(v)) diff --git a/gopher/gopher.go b/gopher/gopher.go index 8a0543b..e644130 100644 --- a/gopher/gopher.go +++ b/gopher/gopher.go @@ -1,6 +1,6 @@ -// Contains the building blocks of a gopher client: history and view. +// Contains the building blocks of a gopher client: history, url, and view. // History handles the browsing session and view represents individual -// text based resources. +// text based resources, the url represents a parsed url. package gopher import ( @@ -16,7 +16,7 @@ import ( // + + + V A R I A B L E S + + + \\ //--------------------------------------------------\\ -// Types is a map of gophertypes to a string representing their +// types is a map of gophertypes to a string representing their // type, to be used when displaying gophermaps var types = map[string]string{ "0": "TXT", @@ -80,10 +80,10 @@ func Retrieve(u Url) ([]byte, error) { } -// The "Visit" function 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. Returns a copy of the view and an error (or nil). +// 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. +// Returns a copy of the view and an error (or nil). func Visit(addr string) (View, error) { u, err := MakeUrl(addr) if err != nil { diff --git a/gopher/url.go b/gopher/url.go index f029e0b..fa13e08 100644 --- a/gopher/url.go +++ b/gopher/url.go @@ -72,10 +72,11 @@ func MakeUrl(u string) (Url, error) { out.Gophertype = "1" } - if out.Gophertype == "1" || out.Gophertype == "0" { - out.IsBinary = false - } else { - out.IsBinary = true + switch out.Gophertype { + case "1", "0", "h", "7": + out.IsBinary = false + default: + out.IsBinary = true } if out.Scheme == "gopher" && out.Gophertype == "" { diff --git a/gopher/view.go b/gopher/view.go index a38abd5..b0146a3 100644 --- a/gopher/view.go +++ b/gopher/view.go @@ -12,7 +12,7 @@ import ( //--------------------------------------------------\\ -// The view struct represents a gopher page. It contains +// 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 { @@ -27,8 +27,8 @@ type View struct { //--------------------------------------------------\\ -// The "ParseMap" receiver is called by a view struct. It -// checks if the view is for a gophermap. If not,it does +// 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 // slice and changes the content value to just the printable @@ -60,8 +60,7 @@ func (v *View) ParseMap() { } } -// The "Display" receiver is called on a view struct. -// It prints the content, line by line, of the View. +// Display is called on a view struct to print the contents of the view. // This receiver does not return anything. func (v View) Display() { fmt.Println() @@ -76,10 +75,10 @@ func (v View) Display() { //--------------------------------------------------\\ -// Constructor function for View struct. -// This is used to initialize a View with -// a Url struct, links, and content. It takes -// a Url struct and a content []string and returns +// 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. +// It takes a Url struct and a content []string and returns // a View (NOT a pointer to a View). func MakeView(url Url, content []string) View { v := View{content, make([]string, 0), url} diff --git a/notes.md b/notes.md index 728ea0f..fb1a32c 100644 --- a/notes.md +++ b/notes.md @@ -2,7 +2,6 @@ TODO - Add built in help system: SIMPLE :help, DO :help action - Add styles/color support - Add comments/documentation for all items -- Finish out binary download support - Make sure html links using the URL convention work correctly - Add "Search" command. ":search thing1 thing2" that uses search as set in config - Verify that all gophertypes work correctly