forked from sloum/bombadillo
Functional browser added notes
This commit is contained in:
parent
0398caf9e3
commit
a28fc00550
|
@ -0,0 +1,314 @@
|
|||
package cui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"bufio"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var shapes = map[string]string{
|
||||
"wall": "│",
|
||||
"ceiling": "─",
|
||||
"tl": "┌",
|
||||
"tr": "┐",
|
||||
"bl": "└",
|
||||
"br": "┘",
|
||||
"scroll-thumb": "▉",
|
||||
"scroll-track": "░",
|
||||
}
|
||||
|
||||
var screenInit bool = false
|
||||
|
||||
type Screen struct {
|
||||
Height int
|
||||
Width int
|
||||
Windows []*Window
|
||||
Activewindow int
|
||||
}
|
||||
|
||||
type box struct {
|
||||
row1 int
|
||||
col1 int
|
||||
row2 int
|
||||
col2 int
|
||||
}
|
||||
|
||||
type Window struct {
|
||||
Box box
|
||||
Scrollbar bool
|
||||
Scrollposition int
|
||||
Content []string
|
||||
drawBox bool
|
||||
Active bool
|
||||
}
|
||||
|
||||
func (s *Screen) AddWindow(r1, c1, r2, c2 int, scroll, border bool) {
|
||||
w := Window{box{r1, c1, r2, c2}, scroll, 0, []string{}, border, false}
|
||||
s.Windows = append(s.Windows, &w)
|
||||
}
|
||||
|
||||
func (s Screen) DrawFullScreen() {
|
||||
s.Clear()
|
||||
// w := s.Windows[s.Activewindow]
|
||||
for _, w := range s.Windows {
|
||||
if w.drawBox {
|
||||
w.DrawBox()
|
||||
}
|
||||
|
||||
w.DrawContent()
|
||||
}
|
||||
MoveCursorTo(s.Height - 1, 1)
|
||||
}
|
||||
|
||||
func (s Screen) Clear() {
|
||||
fill := strings.Repeat(" ", s.Width)
|
||||
for i := 0; i <= s.Height; i++ {
|
||||
MoveCursorTo(i, 0)
|
||||
fmt.Print(fill)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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) {
|
||||
oldh, oldw := s.Height, s.Width
|
||||
s.GetSize()
|
||||
if s.Height != oldh || s.Width != oldw {
|
||||
for _, w := range s.Windows {
|
||||
w.Box.row2 = s.Height - 2
|
||||
w.Box.col2 = s.Width
|
||||
}
|
||||
s.DrawFullScreen()
|
||||
} else if clearScreen {
|
||||
s.DrawFullScreen()
|
||||
} else {
|
||||
s.Windows[s.Activewindow].DrawContent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (s *Screen) GetSize() {
|
||||
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
|
||||
}
|
||||
|
||||
func (w *Window) DrawBox(){
|
||||
moveThenDrawShape(w.Box.row1, w.Box.col1, "tl")
|
||||
moveThenDrawShape(w.Box.row1, w.Box.col2, "tr")
|
||||
moveThenDrawShape(w.Box.row2, w.Box.col1, "bl")
|
||||
moveThenDrawShape(w.Box.row2, w.Box.col2, "br")
|
||||
for i := w.Box.col1 + 1; i < w.Box.col2; i++ {
|
||||
moveThenDrawShape(w.Box.row1, i, "ceiling")
|
||||
moveThenDrawShape(w.Box.row2, i, "ceiling")
|
||||
}
|
||||
|
||||
for i:= w.Box.row1 + 1; i < w.Box.row2; i++ {
|
||||
moveThenDrawShape(i, w.Box.col1, "wall")
|
||||
moveThenDrawShape(i, w.Box.col2, "wall")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Window) DrawContent(){
|
||||
var maxlines, borderw, contenth int
|
||||
if w.drawBox {
|
||||
borderw, contenth = -1, 1
|
||||
} else {
|
||||
borderw, contenth = 1, 0
|
||||
}
|
||||
height, width := w.Box.row2 - w.Box.row1 + borderw, w.Box.col2 - w.Box.col1 + borderw
|
||||
content := WrapLines(w.Content, width)
|
||||
if len(content) < w.Scrollposition + height {
|
||||
maxlines = len(content)
|
||||
} else {
|
||||
maxlines = w.Scrollposition + height
|
||||
}
|
||||
|
||||
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)
|
||||
fmt.Print(content[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Window) ScrollDown() {
|
||||
height := w.Box.row2 - w.Box.row1 - 1
|
||||
contentLength := len(w.Content)
|
||||
if w.Scrollposition < contentLength - height {
|
||||
w.Scrollposition++
|
||||
} else {
|
||||
fmt.Print("\a")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Window) ScrollUp() {
|
||||
if w.Scrollposition > 0 {
|
||||
w.Scrollposition--
|
||||
} else {
|
||||
fmt.Print("\a")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------//
|
||||
// //
|
||||
// F U N C T I O N S //
|
||||
// //
|
||||
//--------------------------------------------------------------------------//
|
||||
|
||||
|
||||
func drawShape(shape string) {
|
||||
if val, ok := shapes[shape]; ok {
|
||||
fmt.Printf("%s", val)
|
||||
} else {
|
||||
fmt.Print("x")
|
||||
}
|
||||
}
|
||||
|
||||
func moveThenDrawShape(r, c int, s string) {
|
||||
MoveCursorTo(r, c)
|
||||
drawShape(s)
|
||||
}
|
||||
|
||||
func MoveCursorTo(row, col int) {
|
||||
fmt.Printf("\033[%d;%dH", row, col)
|
||||
}
|
||||
|
||||
func moveCursorToward(dir string, amount int) {
|
||||
directions := map[string]string{
|
||||
"up": "A",
|
||||
"down": "B",
|
||||
"left": "D",
|
||||
"right": "C",
|
||||
}
|
||||
|
||||
if val, ok := directions[dir]; ok {
|
||||
fmt.Printf("\033[%d%s", amount, val)
|
||||
}
|
||||
}
|
||||
|
||||
func Exit() {
|
||||
moveCursorToward("down", 500)
|
||||
moveCursorToward("right", 500)
|
||||
SetLineMode()
|
||||
fmt.Print("\n")
|
||||
fmt.Print("\033[?25h")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func Clear(dir string) {
|
||||
directions := map[string]string{
|
||||
"up": "\033[1J",
|
||||
"down": "\033[0J",
|
||||
"left": "\033[1K",
|
||||
"right": "\033[0K",
|
||||
"line": "\033[2K",
|
||||
"screen": "\033[2J",
|
||||
}
|
||||
|
||||
if val, ok := directions[dir]; ok {
|
||||
fmt.Print(val)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WrapLines(s []string, length int) []string {
|
||||
out := []string{}
|
||||
for _, ln := range s {
|
||||
if len(ln) <= length {
|
||||
out = append(out, ln)
|
||||
} else {
|
||||
words := strings.Split(ln, " ")
|
||||
var subout bytes.Buffer
|
||||
for i, wd := range words {
|
||||
sublen := subout.Len()
|
||||
if sublen + len(wd) + 1 <= length {
|
||||
if sublen > 0 {
|
||||
subout.WriteString(" ")
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
func NewScreen() *Screen {
|
||||
if screenInit {
|
||||
fmt.Println("Fatal error: Cannot create multiple screens")
|
||||
os.Exit(1)
|
||||
}
|
||||
var s Screen
|
||||
s.GetSize()
|
||||
for i := 0; i < s.Height; i++ {
|
||||
fmt.Println()
|
||||
}
|
||||
SetCharMode()
|
||||
Clear("screen")
|
||||
screenInit = true
|
||||
return &s
|
||||
}
|
||||
|
||||
func Getch() rune {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
char, _, err := reader.ReadRune()
|
||||
if err != nil {
|
||||
return '@'
|
||||
}
|
||||
return char
|
||||
}
|
||||
|
||||
func GetLine() string {
|
||||
SetLineMode()
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print(": ")
|
||||
text, _ := reader.ReadString('\n')
|
||||
SetCharMode()
|
||||
return text[:len(text)-1]
|
||||
}
|
||||
|
||||
func SetCharMode() {
|
||||
exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()
|
||||
exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
|
||||
fmt.Print("\033[?25l")
|
||||
}
|
||||
|
||||
func SetLineMode() {
|
||||
exec.Command("stty", "-F", "/dev/tty", "-cbreak").Run()
|
||||
exec.Command("stty", "-F", "/dev/tty", "echo").Run()
|
||||
}
|
148
gclient.go
148
gclient.go
|
@ -4,92 +4,146 @@ import (
|
|||
"fmt"
|
||||
"gsock/gopher"
|
||||
"os"
|
||||
"bufio"
|
||||
"os/user"
|
||||
"regexp"
|
||||
"strings"
|
||||
"strconv"
|
||||
"gsock/cui"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var history gopher.History = gopher.MakeHistory()
|
||||
var screen *cui.Screen
|
||||
var userinfo, _ = user.Current()
|
||||
|
||||
func err_exit(err string, code int) {
|
||||
fmt.Println(err)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func getln() string {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print(": ")
|
||||
text, _ := reader.ReadString('\n')
|
||||
return text[:len(text)-1]
|
||||
func save_file() {
|
||||
//TODO add a way to save a file...
|
||||
//eg. :save 5 test.txt
|
||||
}
|
||||
|
||||
func search(u string) error {
|
||||
cui.MoveCursorTo(screen.Height - 1, 0)
|
||||
cui.Clear("line")
|
||||
fmt.Print("Enter form input: ")
|
||||
cui.MoveCursorTo(screen.Height - 1, 17)
|
||||
entry := cui.GetLine()
|
||||
searchurl := fmt.Sprintf("%s\t%s", u, entry[:len(entry) - 1])
|
||||
sv, err := gopher.Visit(searchurl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
history.Add(sv)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func route_input(s string) {
|
||||
sl := strings.ToLower(s)
|
||||
if sl == "quit" || sl == "exit" || sl == "q" {
|
||||
err_exit("Quitting...", 0)
|
||||
} else if num, _ := regexp.MatchString(`^\d+$`, s); num && history.Length > 0 {
|
||||
func route_input(s string) error {
|
||||
if num, _ := regexp.MatchString(`^\d+$`, s); num && history.Length > 0 {
|
||||
linkcount := len(history.Collection[history.Position].Links)
|
||||
item, _ := strconv.Atoi(s)
|
||||
if item <= linkcount {
|
||||
linkurl := history.Collection[history.Position].Links[item - 1]
|
||||
|
||||
v, err := history.Visit(linkurl)
|
||||
v, err := gopher.Visit(linkurl)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
if v.Address.IsBinary {
|
||||
// Query for download here
|
||||
fmt.Println("Would you like to download this file?")
|
||||
|
||||
if v.Address.Gophertype == "7" {
|
||||
err := search(linkurl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if v.Address.IsBinary {
|
||||
// TODO add download querying here
|
||||
} else {
|
||||
history.Add(v)
|
||||
history.DisplayCurrentView()
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Invalid link id")
|
||||
errname := fmt.Sprintf("Invalid link id: %s", s)
|
||||
return errors.New(errname)
|
||||
}
|
||||
} else if sl == "back" || sl == "b" {
|
||||
history.GoBack()
|
||||
} else if sl == "forward" || sl == "f" {
|
||||
history.GoForward()
|
||||
} else {
|
||||
v, err := history.Visit(s)
|
||||
v, err := gopher.Visit(s)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
if v.Address.IsBinary {
|
||||
// Query for download here
|
||||
fmt.Println("Would you like to download this file?")
|
||||
if v.Address.Gophertype == "7" {
|
||||
err := search(v.Address.Full)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if v.Address.IsBinary {
|
||||
// TODO add download querying here
|
||||
} else {
|
||||
history.Add(v)
|
||||
history.DisplayCurrentView()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func make_request(s string) ([]string, gopher.Url, error) {
|
||||
u, _ := gopher.MakeUrl(s)
|
||||
text, err := gopher.Retrieve(u)
|
||||
if err != nil {
|
||||
return []string{}, u, err
|
||||
}
|
||||
return strings.Split(string(text), "\n"), u, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// fmt.Println(userinfo.HomeDir)
|
||||
history.Position = -1
|
||||
var inp string
|
||||
if len(os.Args) >= 2 {
|
||||
inp = os.Args[1]
|
||||
route_input(inp)
|
||||
}
|
||||
screen = cui.NewScreen()
|
||||
screen.SetCharMode()
|
||||
defer cui.Exit()
|
||||
screen.AddWindow(1, 1, screen.Height - 2, screen.Width, false, false)
|
||||
mainWindow := screen.Windows[0]
|
||||
redrawScreen := true
|
||||
|
||||
for {
|
||||
inp = getln()
|
||||
if inp == "" {
|
||||
continue
|
||||
screen.ReflashScreen(redrawScreen)
|
||||
|
||||
redrawScreen = false
|
||||
|
||||
c := cui.Getch()
|
||||
switch c {
|
||||
case 'j', 'J':
|
||||
mainWindow.ScrollDown()
|
||||
case 'k', 'K':
|
||||
mainWindow.ScrollUp()
|
||||
case 'q', 'Q':
|
||||
cui.Exit()
|
||||
case 'b', 'B':
|
||||
history.GoBack()
|
||||
mainWindow.Scrollposition = 0
|
||||
redrawScreen = true
|
||||
case 'f', 'F':
|
||||
history.GoForward()
|
||||
mainWindow.Scrollposition = 0
|
||||
redrawScreen = true
|
||||
case ':':
|
||||
redrawScreen = true
|
||||
cui.MoveCursorTo(screen.Height - 1, 0)
|
||||
entry := cui.GetLine()
|
||||
// Clear entry line
|
||||
cui.MoveCursorTo(screen.Height - 1, 0)
|
||||
cui.Clear("line")
|
||||
if entry == "" {
|
||||
cui.MoveCursorTo(screen.Height - 1, 0)
|
||||
fmt.Print(" ")
|
||||
continue
|
||||
}
|
||||
err := route_input(entry)
|
||||
if err != nil {
|
||||
// Display error
|
||||
cui.MoveCursorTo(screen.Height, 0)
|
||||
fmt.Print("\033[41m\033[37m", err, "\033[0m")
|
||||
// Set screen to not reflash
|
||||
redrawScreen = false
|
||||
} else {
|
||||
mainWindow.Scrollposition = 0
|
||||
// screen.Clear()
|
||||
}
|
||||
}
|
||||
if history.Position >= 0 {
|
||||
mainWindow.Content = history.Collection[history.Position].Content
|
||||
}
|
||||
route_input(inp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ type Url struct {
|
|||
|
||||
// Types is a map of gophertypes to a string representing their
|
||||
// type, to be used when displaying gophermaps
|
||||
var Types = map[string]string{
|
||||
var types = map[string]string{
|
||||
"0": "TXT",
|
||||
"1": "MAP",
|
||||
"h": "HTM",
|
||||
|
@ -123,7 +123,8 @@ func (h History) Get() (*View, error) {
|
|||
func (h *History) GoBack() {
|
||||
if h.Position > 0 {
|
||||
h.Position--
|
||||
h.DisplayCurrentView()
|
||||
} else {
|
||||
fmt.Print("\a")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +137,8 @@ func (h *History) GoForward() {
|
|||
if h.Position + 1 < h.Length {
|
||||
h.Position++
|
||||
h.DisplayCurrentView()
|
||||
} else {
|
||||
fmt.Print("\a")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,33 +151,6 @@ func (h *History) DisplayCurrentView() {
|
|||
h.Collection[h.Position].Display()
|
||||
}
|
||||
|
||||
// The "Visit" receiver is a high level combination of a few
|
||||
// different receivers that makes it easy to create a Url,
|
||||
// make a request to that Url, and add the response and Url
|
||||
// to a View. That View then gets added to the History struct
|
||||
// that the Visit receiver was called on. Returns a boolean
|
||||
// value indicating whether or not the content is binary or
|
||||
// textual data.
|
||||
func (h *History) Visit(addr string) (View, error) {
|
||||
u, err := MakeUrl(addr)
|
||||
if err != nil {
|
||||
return View{}, err
|
||||
}
|
||||
|
||||
text, err := Retrieve(u)
|
||||
if err != nil {
|
||||
return View{}, err
|
||||
}
|
||||
|
||||
var pageContent []string
|
||||
if u.IsBinary {
|
||||
pageContent = []string{string(text)}
|
||||
} else {
|
||||
pageContent = strings.Split(string(text), "\n")
|
||||
}
|
||||
|
||||
return MakeView(u, pageContent), nil
|
||||
}
|
||||
|
||||
// The "ParseMap" receiver is called by a view struct. It
|
||||
// checks if the view is for a gophermap. If not,it does
|
||||
|
@ -185,19 +161,25 @@ func (h *History) Visit(addr string) (View, error) {
|
|||
// relates to the link position in the links slice. This
|
||||
// receiver does not return anything.
|
||||
func (v *View) ParseMap() {
|
||||
if v.Address.Gophertype == "1" {
|
||||
if v.Address.Gophertype == "1" || v.Address.Gophertype == "7" {
|
||||
for i, e := range v.Content {
|
||||
e = strings.Trim(e, "\r\n")
|
||||
line := strings.Split(e,"\t")
|
||||
var title string
|
||||
if len(line[0]) > 1 {
|
||||
title = line[0][1:]
|
||||
} else {
|
||||
title = ""
|
||||
}
|
||||
if len(line[0]) > 0 && string(line[0][0]) == "i" {
|
||||
v.Content[i] = " " + string(line[0][1:])
|
||||
v.Content[i] = " " + string(title)
|
||||
continue
|
||||
} else if len(line) >= 4 {
|
||||
fulllink := fmt.Sprintf("%s:%s/%s%s", line[2], line[3], string(line[0][0]), line[1])
|
||||
v.Links = append(v.Links, fulllink)
|
||||
linktext := fmt.Sprintf("(%s) %2d %s", Types[string(line[0][0])], len(v.Links), string(line[0][1:]))
|
||||
linktext := fmt.Sprintf("(%s) %2d %s", GetType(string(line[0][0])), len(v.Links), title)
|
||||
v.Content[i] = linktext
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,9 +190,7 @@ func (v *View) ParseMap() {
|
|||
func (v View) Display() {
|
||||
fmt.Println()
|
||||
for _, el := range v.Content {
|
||||
if el != "." {
|
||||
fmt.Println(el)
|
||||
}
|
||||
fmt.Println(el)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,3 +321,36 @@ 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).
|
||||
func Visit(addr string) (View, error) {
|
||||
u, err := MakeUrl(addr)
|
||||
if err != nil {
|
||||
return View{}, err
|
||||
}
|
||||
|
||||
text, err := Retrieve(u)
|
||||
if err != nil {
|
||||
return View{}, err
|
||||
}
|
||||
|
||||
var pageContent []string
|
||||
if u.IsBinary && u.Gophertype != "7" {
|
||||
pageContent = []string{string(text)}
|
||||
} else {
|
||||
pageContent = strings.Split(string(text), "\n")
|
||||
}
|
||||
|
||||
return MakeView(u, pageContent), nil
|
||||
}
|
||||
|
||||
func GetType(t string) string {
|
||||
if val, ok := types[t]; ok {
|
||||
return val
|
||||
}
|
||||
return "???"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
Control keys/input:
|
||||
|
||||
q quit
|
||||
j scrolldown
|
||||
k scrollup
|
||||
f toggle showing favorites as subwindow
|
||||
r refresh current page data (re-request)
|
||||
|
||||
:# go to link num
|
||||
:url go to url
|
||||
|
||||
:w # name write linknum to file
|
||||
:w url name write url to file
|
||||
:w name write current to file
|
||||
|
||||
:q quit
|
||||
|
||||
:f add #__ name add link num as favorite
|
||||
:f add url name add link url as favorite
|
||||
:f add name add current page as favorite
|
||||
:f del # delete favorite with num
|
||||
:f del url delete favorite with url
|
||||
:f del name delete favorite with name
|
||||
:f # visit favorite with num
|
||||
|
||||
:s ...kywds search assigned engine with keywords
|
||||
|
||||
:home # set homepage to link num
|
||||
:home url set homepage to url
|
||||
:home visit home
|
||||
|
||||
- - - - - - - - - - - - - - - - - -
|
||||
|
||||
Config format:
|
||||
|
||||
[favorites]
|
||||
colorfield.space ++ gopher://colorfield.space:70/
|
||||
My phlog ++ gopher://circumlunar.space/1/~sloum/
|
||||
|
||||
[options]
|
||||
homepage ++ gopher://sdf.org
|
||||
searchengine ++ gopher://floodgap.place/v2/veronicasomething
|
||||
savelocation ++ ~/Downloads/
|
||||
httpbrowser ++ lynx
|
||||
openhttp ++ true
|
|
@ -1,48 +0,0 @@
|
|||
package socket
|
||||
|
||||
import (
|
||||
"net"
|
||||
"io/ioutil"
|
||||
"gsock/gopher"
|
||||
"errors"
|
||||
)
|
||||
|
||||
|
||||
|
||||
func Retrieve(u gopher.Url) ([]byte, error) {
|
||||
nullRes := make([]byte, 0)
|
||||
if u.Host == "" || u.Port == "" {
|
||||
return nullRes, errors.New("Incomplete request url")
|
||||
}
|
||||
|
||||
addr := u.Host + ":" + u.Port
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||
if err != nil {
|
||||
errortext := "Could not find host: " + u.Full
|
||||
return nullRes, errors.New(errortext)
|
||||
}
|
||||
|
||||
conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
||||
if err != nil {
|
||||
return nullRes, err
|
||||
}
|
||||
|
||||
send := u.Resource + "\n"
|
||||
if u.Scheme == "http" || u.Scheme == "https" {
|
||||
send = u.Gophertype
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(send))
|
||||
if err != nil {
|
||||
return nullRes, err
|
||||
}
|
||||
|
||||
result, err := ioutil.ReadAll(conn)
|
||||
if err != nil {
|
||||
return nullRes, err
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue