~rafael/gembro

586763753de37a8f9f55ed6d84f78338c2fa3d49 — RafaĆ«l L. Bekkema 3 years ago fd529d1
Add help button
2 files changed, 61 insertions(+), 9 deletions(-)

M tab.go
M viewport.go
M tab.go => tab.go +49 -4
@@ 35,6 35,11 @@ const (

type tabID uint64

const (
	homeURL = "home://"
	helpURL = "help://"
)

type Tab struct {
	id           tabID
	mode         mode


@@ 46,6 51,7 @@ type Tab struct {
	history      *history.History
	bookmarks    *bookmark.Store
	lastResponse ServerResponse
	specialPages map[string]func(Tab) string
}

func NewTab(client *gemini.Client, startURL string, bs *bookmark.Store, h *history.History, id tabID) Tab {


@@ 65,6 71,10 @@ func NewTab(client *gemini.Client, startURL string, bs *bookmark.Store, h *histo
		viewport:  NewViewport(startURL, h),
		message:   Message{},
		bookmarks: bs,
		specialPages: map[string]func(Tab) string{
			homeURL: homeContent,
			helpURL: helpContent,
		},
	}
}



@@ 190,7 200,7 @@ func (tab Tab) showInput(msg, val, payload string, typ int) (Tab, tea.Cmd) {
	return tab, textinput.Blink
}

func (tab Tab) homeContent() string {
func homeContent(tab Tab) string {
	var buf strings.Builder
	fmt.Fprint(&buf, "# Home\n\n")
	for _, bookmark := range builtinBookmarks {


@@ 204,6 214,40 @@ func (tab Tab) homeContent() string {
	return buf.String()
}

func helpContent(tab Tab) string {
	s := `
# Keys

Go back		h
Go forward		l
Open link		type number + enter
Open link in tab	type number + t
Quit			ctrl+c
Next tab		tab
Previous tab		shift+tab
Goto tab		alt+#
Close tab		q
Goto URL		g
Download page		d
Home			H
Bookmark		b
Scroll up		k
Scroll download	j
Scroll up (page)	Page up
Scroll down (page)	Page down


# Mouse

Open link		Left click
Open link in tab	Middle click
Close tab		Middle click (on tab)
Go back		Right click
Scroll		Mouse wheel
`
	return s
}

type LoadError struct {
	err     error
	message string


@@ 305,7 349,8 @@ func (tab Tab) loadURL(url string, addHist bool, level int, skipVerify bool) (Ta
	if !strings.Contains(url, "://") {
		url = fmt.Sprintf("gemini://%s", url)
	}
	if url != "home://" && !strings.HasPrefix(url, "gemini://") && !strings.HasPrefix(url, "gopher://") {
	specialF, isSpecial := tab.specialPages[url]
	if !isSpecial && !strings.HasPrefix(url, "gemini://") && !strings.HasPrefix(url, "gopher://") {
		tab.viewport.loading = false
		return tab.showMessage(fmt.Sprintf("Open %q externally?", url), url, messageLoadExternal, true)
	}


@@ 319,11 364,11 @@ func (tab Tab) loadURL(url string, addHist bool, level int, skipVerify bool) (Ta
	cmd := func() tea.Msg {
		defer cancel()

		if url == "home://" {
		if isSpecial {
			if addHist {
				tab.history.Add(url)
			}
			return GeminiResponse{Response: &gemini.Response{Body: []byte(tab.homeContent()),
			return GeminiResponse{Response: &gemini.Response{Body: []byte(specialF(tab)),
				URL: url, Header: gemini.Header{Status: 2, Meta: "text/gemini"}}, level: level, tab: tab.id}
		}


M viewport.go => viewport.go +12 -5
@@ 25,6 25,7 @@ const (
	buttonGoto     = "Goto"
	buttonCloseTab = "Close Tab"
	buttonQuit     = "Quit"
	buttonHelp     = "Help"
)

type Viewport struct {


@@ 50,7 51,7 @@ func NewViewport(startURL string, h *history.History) Viewport {
		URL:     startURL,
		spinner: s,
		history: h,
		footer:  NewFooter(buttonBack, buttonFwd, buttonHome, buttonBookmark, buttonDownload, buttonQuit),
		footer:  NewFooter(buttonBack, buttonFwd, buttonHome, buttonBookmark, buttonDownload, buttonHelp, buttonQuit),
	}
}



@@ 104,7 105,6 @@ func (v Viewport) Update(msg tea.Msg) (Viewport, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		verticalMargins := headerHeight + footerHeight

		if !v.ready {
			v.viewport = viewport.Model{Width: msg.Width, Height: msg.Height - verticalMargins}
			v.viewport.YPosition = headerHeight


@@ 113,7 113,7 @@ func (v Viewport) Update(msg tea.Msg) (Viewport, tea.Cmd) {
			v.ready = true
			startURL := v.URL
			if startURL == "" {
				startURL = "home://"
				startURL = homeURL
			}
			return v, fireEvent(LoadURLEvent{URL: startURL, AddHistory: v.history.Current() != startURL})
		} else {


@@ 135,6 135,8 @@ func (v Viewport) Update(msg tea.Msg) (Viewport, tea.Cmd) {
			return v, v.handleButtonClick(buttonHome)
		case "b":
			return v, v.handleButtonClick(buttonBookmark)
		case "?":
			return v, v.handleButtonClick(buttonHelp)
		case "left", "h":
			return v, v.handleButtonClick(buttonBack)
		case "right", "l":


@@ 186,7 188,12 @@ func (v Viewport) handleButtonClick(btn string) tea.Cmd {
	case buttonFwd:
		return fireEvent(GoForwardEvent{})
	case buttonHome:
		return fireEvent(LoadURLEvent{URL: "home://", AddHistory: true})
		return fireEvent(LoadURLEvent{URL: homeURL, AddHistory: true})
	case buttonHelp:
		if v.URL == helpURL {
			return fireEvent(GoBackEvent{})
		}
		return fireEvent(LoadURLEvent{URL: helpURL, AddHistory: true})
	case buttonBookmark:
		return fireEvent(ToggleBookmarkEvent{URL: v.URL, Title: v.title})
	case buttonDownload:


@@ 195,7 202,7 @@ func (v Viewport) handleButtonClick(btn string) tea.Cmd {
			Type:  inputDownloadSrc})
	case buttonGoto:
		var val string
		if cur := v.history.Current(); cur != "home://" {
		if cur := v.history.Current(); cur != homeURL && cur != helpURL {
			val = cur
		}
		return fireEvent(ShowInputEvent{Message: "Go to", Type: inputNav, Payload: "", Value: val})