Updated notes, added auto-download for binary files, and added comments

This commit is contained in:
sloumdrone 2019-03-20 22:29:09 -07:00
parent 44f6c461d5
commit 26f80dafbc
8 changed files with 85 additions and 40 deletions

View File

@ -45,12 +45,26 @@ func save_file(address, name string) error {
return err return err
} }
err = ioutil.WriteFile(userinfo.HomeDir + "/" + name, data, 0644) err = ioutil.WriteFile(options["savelocation"] + name, data, 0644)
if err != nil { if err != nil {
return err 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 { func search(u string) error {
@ -138,7 +152,7 @@ func go_to_url(u string) error {
} }
} else if v.Address.IsBinary { } else if v.Address.IsBinary {
// TO DO: run this into the write to file method // TO DO: run this into the write to file method
return fmt.Errorf("Not built yet") return save_file_from_data(v)
} else { } else {
history.Add(v) history.Add(v)
} }
@ -165,7 +179,7 @@ func go_to_link(l string) error {
return err return err
} }
} else if v.Address.IsBinary { } else if v.Address.IsBinary {
// TO DO: run this into the write to file method return save_file_from_data(v)
} else { } else {
history.Add(v) history.Add(v)
} }
@ -322,7 +336,7 @@ func display_error(err error, redraw *bool) {
func initClient() { func initClient() {
history.Position = -1 history.Position = -1
screen = cui.NewScreen() screen = cui.NewScreen()
screen.SetCharMode() 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.AddMsgBar(1, " ((( Bombadillo ))) ", " A fun gopher client!", true) screen.AddMsgBar(1, " ((( Bombadillo ))) ", " A fun gopher client!", true)
bookmarksWidth := 40 bookmarksWidth := 40

View File

@ -1,10 +1,7 @@
package cui package cui
import ( // MsgBar is a struct to represent a single row horizontal
// bar on the screen.
)
type MsgBar struct { type MsgBar struct {
row int row int
title string title string
@ -12,19 +9,24 @@ type MsgBar struct {
showTitle bool showTitle bool
} }
// SetTitle sets the title for the MsgBar in question
func (m *MsgBar) SetTitle(s string) { func (m *MsgBar) SetTitle(s string) {
m.title = s m.title = s
} }
// SetMessage sets the message for the MsgBar in question
func (m *MsgBar) SetMessage(s string) { func (m *MsgBar) SetMessage(s string) {
m.message = s 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) MoveCursorTo(m.row, 1)
Clear("line") Clear("line")
} }
// ClearMessage clears all message text while leaving the title in place
func (m *MsgBar) ClearMessage() { func (m *MsgBar) ClearMessage() {
MoveCursorTo(m.row, len(m.title) + 1) MoveCursorTo(m.row, len(m.title) + 1)
Clear("right") Clear("right")

View File

@ -8,9 +8,14 @@ import (
"bytes" "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 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 { type Screen struct {
Height int Height int
Width 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) { 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} w := Window{box{r1, c1, r2, c2}, scroll, 0, []string{}, border, false, show}
s.Windows = append(s.Windows, &w) 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) { func (s *Screen) AddMsgBar(row int, title, msg string, showTitle bool) {
b := MsgBar{row, title, msg, showTitle} b := MsgBar{row, title, msg, showTitle}
s.Bars = append(s.Bars, &b) 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() { func (s Screen) DrawAllWindows() {
s.Clear() s.Clear()
for _, w := range s.Windows { for _, w := range s.Windows {
@ -40,6 +49,7 @@ func (s Screen) DrawAllWindows() {
MoveCursorTo(s.Height - 1, 1) MoveCursorTo(s.Height - 1, 1)
} }
// Clear removes all content from the interior of the screen
func (s Screen) Clear() { func (s Screen) Clear() {
fill := strings.Repeat(" ", s.Width) fill := strings.Repeat(" ", s.Width)
for i := 0; i <= s.Height; i++ { 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 // ReflashScreen checks for a screen resize and resizes windows if
// Then redraws the screen. Takes a bool to decide whether // needed then redraws the screen. It takes a bool to decide whether
// to redraw the full screen or just the content. On a resize // to redraw the full screen or just the content. On a resize
// event, the full screen will always be redrawn. // event, the full screen will always be redrawn.
func (s *Screen) ReflashScreen(clearScreen bool) { 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() { func (s *Screen) DrawMsgBars() {
for _, bar := range s.Bars { for _, bar := range s.Bars {
MoveCursorTo(bar.row, 1) 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() { func (s *Screen) GetSize() {
cmd := exec.Command("stty", "size") cmd := exec.Command("stty", "size")
cmd.Stdin = os.Stdin 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 { func NewScreen() *Screen {
if screenInit { if screenInit {
fmt.Println("Fatal error: Cannot create multiple screens") fmt.Println("Fatal error: Cannot create multiple screens")

View File

@ -5,11 +5,30 @@ import (
"strings" "strings"
) )
//------------------------------------------------\\
// + + + T Y P E S + + + \\
//--------------------------------------------------\\
//Bookmarks is a holder for titles and links that
//can be retrieved by index
type Bookmarks struct { type Bookmarks struct {
Titles []string Titles []string
Links []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 { func (b *Bookmarks) Add(v []string) error {
if len(v) < 2 { if len(v) < 2 {
return fmt.Errorf("Received %d arguments, expected 2 or more", len(v)) return fmt.Errorf("Received %d arguments, expected 2 or more", len(v))

View File

@ -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 // History handles the browsing session and view represents individual
// text based resources. // text based resources, the url represents a parsed url.
package gopher package gopher
import ( import (
@ -16,7 +16,7 @@ import (
// + + + V A R I A B L E S + + + \\ // + + + 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 // type, to be used when displaying gophermaps
var types = map[string]string{ var types = map[string]string{
"0": "TXT", "0": "TXT",
@ -80,10 +80,10 @@ func Retrieve(u Url) ([]byte, error) {
} }
// The "Visit" function is a high level combination of a few // Visit is a high level combination of a few different
// different types that makes it easy to create a Url, // types that makes it easy to create a Url, make a request
// make a request to that Url, and add the response and Url // to that Url, and add the response and Url to a View.
// to a View. Returns a copy of the view and an error (or nil). // Returns a copy of the view and an error (or nil).
func Visit(addr string) (View, error) { func Visit(addr string) (View, error) {
u, err := MakeUrl(addr) u, err := MakeUrl(addr)
if err != nil { if err != nil {

View File

@ -72,10 +72,11 @@ func MakeUrl(u string) (Url, error) {
out.Gophertype = "1" out.Gophertype = "1"
} }
if out.Gophertype == "1" || out.Gophertype == "0" { switch out.Gophertype {
out.IsBinary = false case "1", "0", "h", "7":
} else { out.IsBinary = false
out.IsBinary = true default:
out.IsBinary = true
} }
if out.Scheme == "gopher" && out.Gophertype == "" { if out.Scheme == "gopher" && out.Gophertype == "" {

View File

@ -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 // the page content as a string slice, a list of link URLs
// as string slices, and the Url struct representing the page. // as string slices, and the Url struct representing the page.
type View struct { type View struct {
@ -27,8 +27,8 @@ type View struct {
//--------------------------------------------------\\ //--------------------------------------------------\\
// The "ParseMap" receiver is called by a view struct. It // ParseMap is called by a view struct to parse a gophermap.
// checks if the view is for a gophermap. If not,it does // It checks if the view is for a gophermap. If not,it does
// nothing. If so, it parses the gophermap into comment lines // nothing. If so, it parses the gophermap into comment lines
// and link lines. For link lines it adds a link to the links // and link lines. For link lines it adds a link to the links
// slice and changes the content value to just the printable // 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. // Display is called on a view struct to print the contents of the view.
// It prints the content, line by line, of the View.
// This receiver does not return anything. // This receiver does not return anything.
func (v View) Display() { func (v View) Display() {
fmt.Println() fmt.Println()
@ -76,10 +75,10 @@ func (v View) Display() {
//--------------------------------------------------\\ //--------------------------------------------------\\
// Constructor function for View struct. // MakeView creates and returns a new View struct from
// This is used to initialize a View with // a Url and a string splice of content. This is used to
// a Url struct, links, and content. It takes // initialize a View with a Url struct, links, and content.
// a Url struct and a content []string and returns // It takes a Url struct and a content []string and returns
// a View (NOT a pointer to a View). // a View (NOT a pointer to a View).
func MakeView(url Url, content []string) View { func MakeView(url Url, content []string) View {
v := View{content, make([]string, 0), url} v := View{content, make([]string, 0), url}

View File

@ -2,7 +2,6 @@ TODO
- Add built in help system: SIMPLE :help, DO :help action - Add built in help system: SIMPLE :help, DO :help action
- Add styles/color support - Add styles/color support
- Add comments/documentation for all items - Add comments/documentation for all items
- Finish out binary download support
- Make sure html links using the URL convention work correctly - Make sure html links using the URL convention work correctly
- Add "Search" command. ":search thing1 thing2" that uses search as set in config - Add "Search" command. ":search thing1 thing2" that uses search as set in config
- Verify that all gophertypes work correctly - Verify that all gophertypes work correctly