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