~adnano/astronaut

72ba913688a9d2dafb0bfdf11a5cee16685ce98a — Adnan Maolood 2 months ago c2cbc6b
Use scfg to configure settings
4 files changed, 72 insertions(+), 32 deletions(-)

M browser.go
M command.go
M main.go
M settings.go
M browser.go => browser.go +2 -7
@@ 55,13 55,14 @@ type Browser struct {
}

// NewBrowser returns a new browser.
func NewBrowser(view *ui.View) *Browser {
func NewBrowser(view *ui.View, settings *Settings) *Browser {
	b := &Browser{
		view:       view,
		tablist:    view.SubView(),
		tabView:    view.SubView(),
		statusView: view.SubView(),
		inputView:  view.SubView(),
		settings:   settings,
	}

	b.status.SetView(b.statusView)


@@ 69,12 70,6 @@ func NewBrowser(view *ui.View) *Browser {

	// TODO: Handle errors here better

	// Load settings
	settingsPath := filepath.Join(xdg.ConfigHome(), "astronaut", "settings.json")
	os.MkdirAll(filepath.Dir(settingsPath), 0755)
	b.settings = &Settings{}
	b.settings.Load(settingsPath)

	// Load known hosts
	knownHostsPath := filepath.Join(xdg.DataHome(), "astronaut", "known_hosts")
	os.MkdirAll(filepath.Dir(knownHostsPath), 0700)

M command.go => command.go +8 -7
@@ 60,14 60,15 @@ var commands = map[string]Command{
		b.makeTabVisible()
	},
	"search": func(b *Browser, args ...string) {
		if len(args) >= 1 {
			b.tabs[b.tab].GetURL(&url.URL{
				Scheme:   "gemini",
				Host:     "geminispace.info",
				Path:     "/search",
				RawQuery: gemini.QueryEscape(strings.Join(args, " ")),
			})
		if len(args) == 0 {
			return
		}
		b.settings.RLock()
		defer b.settings.RUnlock()
		u := b.settings.SearchURL.ResolveReference(&url.URL{
			RawQuery: gemini.QueryEscape(strings.Join(args, " ")),
		})
		b.tabs[b.tab].GetURL(u)
	},
	"back": func(b *Browser, args ...string) {
		b.tabs[b.tab].Back()

M main.go => main.go +15 -1
@@ 41,6 41,7 @@ func main() {
			styles.Parse(block)
		}
	}

	bindsConf := filepath.Join(xdg.ConfigHome(), "astronaut", "binds.conf")
	f, err = os.Open(bindsConf)
	if err == nil {


@@ 53,13 54,26 @@ func main() {
		}
	}

	settings := &Settings{}
	astronautConf := filepath.Join(xdg.ConfigHome(), "astronaut", "astronaut.conf")
	f, err = os.Open(astronautConf)
	if err == nil {
		defer f.Close()
		block, err := scfg.Read(f)
		if err != nil {
			log.Print(err)
		} else {
			settings.Parse(block)
		}
	}

	ui, err := ui.New()
	if err != nil {
		log.Fatal(err)
	}
	defer ui.Close()

	browser := NewBrowser(ui.View())
	browser := NewBrowser(ui.View(), settings)

	for !ui.Exiting() {
		browser.Update()

M settings.go => settings.go +47 -17
@@ 1,42 1,72 @@
package main

import (
	"encoding/json"
	"io"
	"os"
	"net/url"
	"strconv"
	"sync"

	"git.sr.ht/~emersion/go-scfg"
)

type Settings struct {
	sync.RWMutex
	path    string
	Display struct {
		Graphics bool `json:"graphics"`
		AltText  bool `json:"alt-text"`
	} `json:"display"`
	SearchURL *url.URL
}

// Default applies the default settings.
func (s *Settings) Default() {
	s.Display.Graphics = true
	s.Display.AltText = false
	s.SearchURL = &url.URL{
		Scheme: "gemini",
		Host:   "geminispace.info",
		Path:   "/search",
	}
}

// Load loads the settings from the provided path.
func (s *Settings) Load(path string) error {
	s.path = path
	f, err := os.OpenFile(path, os.O_RDWR, 0644)
	if err != nil {
		// Try to create the settings file
		s.Default()
		return s.Save()
func (s *Settings) Parse(block scfg.Block) {
	s.Default()
	for _, d := range block {
		switch d.Name {
		case "display":
			s.parseDisplay(d.Children)
		case "search":
			s.parseSearch(d)
		}
	}
	b, err := io.ReadAll(f)
	if err != nil {
		return err
}

func (s *Settings) parseDisplay(block scfg.Block) {
	for _, d := range block {
		switch d.Name {
		case "graphics":
			var enabled string
			d.ParseParams(&enabled)
			b, err := strconv.ParseBool(enabled)
			if err == nil {
				s.Display.Graphics = b
			}
		case "alt-text":
			var enabled string
			d.ParseParams(&enabled)
			b, err := strconv.ParseBool(enabled)
			if err == nil {
				s.Display.AltText = b
			}
		}
	}
	if err := json.Unmarshal(b, s); err != nil {
		return err
}

func (s *Settings) parseSearch(d *scfg.Directive) {
	var searchURL string
	d.ParseParams(&searchURL)
	u, err := url.Parse(searchURL)
	if err == nil {
		s.SearchURL = u
	}
	return nil
}