summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Chabowski <kevin@kch42.de>2014-05-01 14:22:15 +0200
committerKevin Chabowski <kevin@kch42.de>2014-05-01 14:33:15 +0200
commit500af457c12a8c11c4b32301f6ab324248c4ccaa (patch)
treefdb4c474e6cc0e8717cee4edac875faefdb0f1f6
parentac3aafafeef06bc38d1b980807786e2558edb2cb (diff)
downloadstartpage-500af457c12a8c11c4b32301f6ab324248c4ccaa.tar.gz
startpage-500af457c12a8c11c4b32301f6ab324248c4ccaa.tar.bz2
startpage-500af457c12a8c11c4b32301f6ab324248c4ccaa.zip
Introduced new config file format
-rw-r--r--README.markdown24
-rw-r--r--conflang.go160
-rw-r--r--links.go26
-rw-r--r--main.go19
-rw-r--r--yr_no.go24
5 files changed, 208 insertions, 45 deletions
diff --git a/README.markdown b/README.markdown
index 346d386..ccf2d1c 100644
--- a/README.markdown
+++ b/README.markdown
@@ -9,22 +9,26 @@ A simple start page with a background image from [/r/EarthPorn](http://www.reddi
## Configuration
-startpage uses two files in your home directory for configuration:
+The startpage configuration is located in the file ~/.startpagerc. It is a list of commands. A command has a name and can optionally have parameters separated by spaces or tabs. A backspace `\\` will interpret the next charcter literally (can be used to escape whitespace, linebreaks and backspaces). Commands are separated by newlines.
-### ~/.startpage-urls
+These commands are implemented:
-This describes the hyperlinks that are displayed on the startpage. A list of key-value-pairs. Each line is such a pair. Key and value are separated with `->`. The key is the title of the link, the value the URL.
+### `set-weather-place`
-Example:
+Takes one argument, the place used for weather info. startpage uses [yr.no](http://www.yr.no) to get weather data. Use the search box on that page to search for your place. You will then be redirected to an URL like this: `http://www.yr.no/place/<myplace>`. Put the `<myplace>` part after the `set-weather-place` command like this:
+
+ set-weather-place <myplace>
- github -> http://www.github.com
- reddit -> http://www.reddit.com
- go -> http://www.golang.org
- example -> http://www.example.org
+### `add-link`
-### ~/.startpage-weather
+Add a link that is displayed on the startpage. First argument is the title, second one the URL.
+
+Example:
-The place for the weather is stored here. startpage uses [yr.no](http://www.yr.no) to get weather data. Use the search box on that page to search for your place. You will then be redirected to an URL like this: `http://www.yr.no/place/<myplace>`. Put the `<myplace>` part into the `.startpage-weather` file.
+ add-link github http://www.github.com
+ add-link reddit http://www.reddit.com
+ add-link go http://www.golang.org
+ add-link another\ example http://www.example.org
## Running
diff --git a/conflang.go b/conflang.go
new file mode 100644
index 0000000..0b4a856
--- /dev/null
+++ b/conflang.go
@@ -0,0 +1,160 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+)
+
+type toktype int
+
+const (
+ tText toktype = iota
+ tNextCmd
+)
+
+type token struct {
+ Type toktype
+ Data string
+ Line int
+}
+
+func scan(r io.Reader, tokens chan<- token, errch chan<- error) {
+ emit := func(t toktype, d []byte, line int) {
+ if t == tText && len(d) == 0 {
+ return
+ }
+ tokens <- token{t, string(d), line}
+ }
+
+ err := func() error {
+ br := bufio.NewReader(r)
+
+ escaped := false
+ data := []byte{}
+ line := 1
+
+ for {
+ b, err := br.ReadByte()
+
+ switch err {
+ case nil:
+ case io.EOF:
+ return nil
+ default:
+ return ErrorAtLine{line, err}
+ }
+
+ if b == '\n' {
+ line++
+ }
+
+ if escaped {
+ data = append(data, b)
+ escaped = false
+ continue
+ }
+
+ switch b {
+ case '\\':
+ escaped = true
+ case ' ', '\t':
+ emit(tText, data, line)
+ data = data[:0]
+ case '\n':
+ emit(tText, data, line)
+ data = data[:0]
+ emit(tNextCmd, nil, line)
+ default:
+ data = append(data, b)
+ }
+ }
+
+ emit(tText, data, line)
+ emit(tNextCmd, nil, line)
+ return nil
+ }()
+
+ close(tokens)
+ errch <- err
+}
+
+type command struct {
+ Name string
+ Params []string
+ Line int
+}
+
+func parse(tokens <-chan token, cmds chan<- command) {
+ defer close(cmds)
+
+ startcmd := true
+ cmd := command{"", make([]string, 0), 0}
+
+ for tok := range tokens {
+ switch tok.Type {
+ case tText:
+ if startcmd {
+ cmd.Name = tok.Data
+ cmd.Line = tok.Line
+ startcmd = false
+ } else {
+ cmd.Params = append(cmd.Params, tok.Data)
+ }
+ case tNextCmd:
+ if !startcmd {
+ cmds <- cmd
+ cmd.Name = ""
+ cmd.Params = make([]string, 0)
+ startcmd = true
+ }
+ }
+ }
+}
+
+type cmdfunc func(params []string) error
+
+var commands = map[string]cmdfunc{
+ "nop": func(_ []string) error { return nil },
+}
+
+func RegisterCommand(name string, f cmdfunc) {
+ commands[name] = f
+}
+
+type ErrorAtLine struct {
+ Line int
+ Err error
+}
+
+func (err ErrorAtLine) Error() string {
+ return fmt.Sprintf("%s (at line %d)", err.Err, err.Line)
+}
+
+type CommandNotFound string
+
+func (c CommandNotFound) Error() string {
+ return fmt.Sprintf("Command \"%s\" not found", c)
+}
+
+func RunCommands(r io.Reader) error {
+ errch := make(chan error)
+ tokens := make(chan token)
+ cmds := make(chan command)
+
+ go scan(r, tokens, errch)
+ go parse(tokens, cmds)
+
+ for cmd := range cmds {
+ f, ok := commands[cmd.Name]
+ if !ok {
+ return ErrorAtLine{cmd.Line, CommandNotFound(cmd.Name)}
+ }
+
+ if err := f(cmd.Params); err != nil {
+ return ErrorAtLine{cmd.Line, err}
+ }
+ }
+
+ return <-errch
+}
diff --git a/links.go b/links.go
index f7bda76..bd7b624 100644
--- a/links.go
+++ b/links.go
@@ -1,11 +1,8 @@
package main
import (
- "bufio"
+ "errors"
"html/template"
- "log"
- "os"
- "strings"
)
type Link struct {
@@ -13,22 +10,13 @@ type Link struct {
URL template.URL
}
-func GetLinks() (links []Link) {
- fh, err := os.Open(os.ExpandEnv("$HOME/.startpage-urls"))
- if err != nil {
- log.Printf("Couldn't read links: %s", err)
- return
- }
- defer fh.Close()
+var links = []Link{}
- scanner := bufio.NewScanner(fh)
- for scanner.Scan() {
- parts := strings.SplitN(scanner.Text(), "->", 2)
- links = append(links, Link{
- strings.TrimSpace(parts[0]),
- template.URL(strings.TrimSpace(parts[1])),
- })
+func addLinkCmd(params []string) error {
+ if len(params) != 2 {
+ return errors.New("add-link needs 2 parameters: title url")
}
- return
+ links = append(links, Link{params[0], template.URL(params[1])})
+ return nil
}
diff --git a/main.go b/main.go
index edfe037..7f31327 100644
--- a/main.go
+++ b/main.go
@@ -90,11 +90,30 @@ func loadTemplate() {
panic(errors.New("could not find template in $GOPATH/src/github.com/kch42/startpage"))
}
+func initCmds() {
+ RegisterCommand("add-link", addLinkCmd)
+ RegisterCommand("set-weather-place", setPlaceCmd)
+}
+
+func runConf() {
+ f, err := os.Open(os.ExpandEnv("$HOME/.startpagerc"))
+ if err != nil {
+ log.Fatalf("Could not open startpagerc: %s", err)
+ }
+ defer f.Close()
+
+ if err := RunCommands(f); err != nil {
+ log.Fatal(err)
+ }
+}
+
func main() {
laddr := flag.String("laddr", ":25145", "Listen on this port")
flag.Parse()
loadTemplate()
+ initCmds()
+ runConf()
pornch := make(chan bool)
weatherch := make(chan bool)
diff --git a/yr_no.go b/yr_no.go
index 38ec8eb..bb9c747 100644
--- a/yr_no.go
+++ b/yr_no.go
@@ -1,13 +1,10 @@
package main
import (
- "bytes"
"encoding/xml"
+ "errors"
"fmt"
- "io"
"net/http"
- "os"
- "strings"
"time"
)
@@ -61,21 +58,16 @@ type weatherdata struct {
Forecast []*Weather `xml:"forecast>tabular>time"`
}
-func getPlace() string {
- fh, err := os.Open(os.ExpandEnv("$HOME/.startpage-weather"))
- if err != nil {
- panic(err)
- }
- defer fh.Close()
+var place = ""
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, fh); err != nil {
- panic(err)
+func setPlaceCmd(params []string) error {
+ if len(params) != 1 {
+ return errors.New("set-weather-place needs one parameter")
}
- return strings.TrimSpace(string(buf.Bytes()))
-}
-var place = getPlace()
+ place = params[0]
+ return nil
+}
func CurrentWeather() (Weather, Sun, error) {
url := "http://www.yr.no/place/" + place + "/forecast_hour_by_hour.xml"