~adnano/astronaut

af652f72dae65ea71588f3623d8a6202f7e2edcb — Adnan Maolood 29 days ago c5414cc
browser: Implement save mode
3 files changed, 54 insertions(+), 28 deletions(-)

M browser.go
M command.go
M tab.go
M browser.go => browser.go +47 -1
@@ 3,7 3,9 @@ package main
import (
	"astronaut/styles"
	"astronaut/ui"
	"bufio"
	"fmt"
	"io"
	"log"
	"math"
	"math/rand"


@@ 28,6 30,7 @@ const (
	ModeNormal Mode = iota
	ModeCommand
	ModeInput
	ModeSave
	ModeFollow
)



@@ 56,6 59,10 @@ type Browser struct {

	input ui.Input

	// save mode
	data io.ReadCloser

	// follow mode
	hint    string
	hints   []Hint
	hintMap map[string]Hint


@@ 183,7 190,7 @@ func (b *Browser) Draw() {
			b.statusView.DrawText(0, 0, b.message.text, style)
		}

	case ModeCommand, ModeInput:
	case ModeCommand, ModeInput, ModeSave:
		b.input.Draw()

	case ModeFollow:


@@ 263,6 270,32 @@ func (b *Browser) Event(event tcell.Event) {
		tab.Back()
		tab.DoBackground(req)

	case ModeSave:
		name, ok := b.input.Event(event)
		if !ok {
			return
		}
		b.mode = ModeNormal
		data := b.data
		defer data.Close()
		b.data = nil
		if name == "" {
			return
		}
		// TODO: Avoid overwriting files
		// TODO: Download directory?
		f, err := os.Create(name)
		if err != nil {
			tab.Error(err)
			return
		}
		defer f.Close()
		_, err = io.Copy(bufio.NewWriter(f), data)
		if err != nil {
			tab.Error(err)
			return
		}

	case ModeFollow:
		text := tab.Text()
		if text == nil {


@@ 616,6 649,19 @@ func (b *Browser) InputMode(prompt string, sensitive bool) {
	b.input.Sensitive(sensitive)
}

func (b *Browser) SaveMode(data io.ReadCloser, name string) {
	b.mu.Lock()
	defer b.mu.Unlock()
	b.saveMode(data, name)
}

func (b *Browser) saveMode(data io.ReadCloser, name string) {
	b.mode = ModeSave
	b.data = data
	b.input.Prompt("Save as ")
	b.input.SetInput(name)
}

func (b *Browser) FollowMode() error {
	text := b.tabs[b.tab].Text()
	if text == nil {

M command.go => command.go +3 -10
@@ 4,7 4,7 @@ import (
	"errors"
	"io"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"



@@ 139,16 139,9 @@ var commands = map[string]Command{
		return nil
	},
	"save": func(b *Browser, args ...string) error {
		if len(args) == 0 {
			return errors.New("usage: save <path>")
		}
		tab := b.tabs[b.tab]
		f, err := os.Create(args[0])
		if err != nil {
			return err
		}
		defer f.Close()
		io.Copy(f, &tab.buf)
		name := path.Base(tab.URL())
		b.saveMode(io.NopCloser(&tab.buf), name)
		return nil
	},
	"bookmark": func(b *Browser, args ...string) error {

M tab.go => tab.go +4 -17
@@ 628,7 628,6 @@ func (t *Tab) newPage() {
}

func (t *Tab) handle(req *gemini.Request, resp *gemini.Response) error {
	defer resp.Body.Close()

	mediatype, params, err := mime.ParseMediaType(resp.Meta)
	if err != nil {


@@ 637,6 636,7 @@ func (t *Tab) handle(req *gemini.Request, resp *gemini.Response) error {

	t.setMediaType(mediatype)
	if strings.HasPrefix(mediatype, "text/") {
		defer resp.Body.Close()
		return t.handleText(resp, mediatype, params)
	}
	return t.handleDownload(req, resp, mediatype)


@@ 703,29 703,16 @@ func (t *Tab) handleDownload(req *gemini.Request, resp *gemini.Response, mediaty
	case choice := <-ch:
		switch choice {
		case save:
			return t.saveResponse(resp, filename)
			t.browser.SaveMode(resp.Body, filename)
			return nil
		case open:
			defer resp.Body.Close()
			return t.openResponse(resp, filename)
		}
	}
	return nil
}

func (t *Tab) saveResponse(resp *gemini.Response, filename string) error {
	// TODO: Avoid overwriting files
	// TODO: Download directory?
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(bufio.NewWriter(f), resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func (t *Tab) openResponse(resp *gemini.Response, filename string) error {
	f, err := os.CreateTemp("", "astronaut-*-"+filename)
	if err != nil {