M gemini/gemtext.go => gemini/gemtext.go +3 -2
@@ 53,8 53,9 @@ func ToANSI(data string, availableWidth int, baseURL neturl.URL) (
if furl.Scheme != "gemini" {
extra = fmt.Sprintf(" (%s)", furl.Scheme)
}
- fmt.Fprintf(&s, "> %s%s\n", text.Color(l.Name, text.Clink), extra)
- links.Add(ypos, furl.String(), l.Name)
+ count := links.Count() + 1
+ links.Add(ypos, count, furl.String(), l.Name)
+ fmt.Fprintf(&s, "%d> %s %s\n", count, text.Color(l.Name, text.Clink), extra)
ypos++
continue
}
M gopher/gopher.go => gopher/gopher.go +3 -2
@@ 46,8 46,9 @@ func ToANSI(data []byte, typ byte) (s string, links text.Links) {
} else {
url = fmt.Sprintf("gopher://%s:%s/%c%s", f[2], f[3], line[0], f[1])
}
- links.Add(ypos, url, f[0])
- fmt.Fprintf(&buf, "%s", text.Color(f[0], text.Clink))
+ count := links.Count() + 1
+ links.Add(ypos, count, url, f[0])
+ fmt.Fprintf(&buf, "%d> %s", count, text.Color(f[0], text.Clink))
switch {
case external:
fmt.Fprintf(&buf, " (%s)\n", strings.Split(url, "://")[0])
M text/links.go => text/links.go +16 -2
@@ 2,17 2,18 @@ package text
type Link struct {
URL, Name string
+ index int
}
type Links struct {
links map[int]Link
}
-func (l *Links) Add(ypos int, url, name string) {
+func (l *Links) Add(ypos, index int, url, name string) {
if l.links == nil {
l.links = make(map[int]Link)
}
- l.links[ypos] = Link{url, name}
+ l.links[ypos] = Link{url, name, index}
}
func (l Links) LinkAt(y int) *Link {
@@ 21,3 22,16 @@ func (l Links) LinkAt(y int) *Link {
}
return nil
}
+
+func (l Links) Number(n int) *Link {
+ for _, l := range l.links {
+ if l.index == n {
+ return &l
+ }
+ }
+ return nil
+}
+
+func (l *Links) Count() int {
+ return len(l.links)
+}
M viewport.go => viewport.go +32 -4
@@ 4,6 4,7 @@ import (
"fmt"
"log"
neturl "net/url"
+ "strconv"
"strings"
"git.sr.ht/~rafael/gembro/gemini"
@@ 38,6 39,7 @@ type Viewport struct {
links text.Links
lastEvent tea.MouseEventType
history *history.History
+ digits string
}
func NewViewport(startURL string, h *history.History) Viewport {
@@ 122,21 124,44 @@ func (v Viewport) Update(msg tea.Msg) (Viewport, tea.Cmd) {
v, cmd = v.handleMouse(msg)
cmds = append(cmds, cmd)
case tea.KeyMsg:
- switch msg.String() {
+ switch key := msg.String(); key {
case "q":
return v, v.handleButtonClick(buttonCloseTab)
case "g":
return v, v.handleButtonClick(buttonGoto)
case "d":
return v, v.handleButtonClick(buttonDownload)
- case "h":
+ case "H":
return v, v.handleButtonClick(buttonHome)
case "b":
return v, v.handleButtonClick(buttonBookmark)
- case "left":
+ case "left", "h":
return v, v.handleButtonClick(buttonBack)
- case "right":
+ case "right", "l":
return v, v.handleButtonClick(buttonFwd)
+ case "esc":
+ v.digits = ""
+ return v, nil
+ case "backspace":
+ if len(v.digits) > 0 {
+ v.digits = v.digits[0 : len(v.digits)-1]
+ return v, nil
+ }
+ case "enter", "t":
+ num, _ := strconv.Atoi(v.digits)
+ link := v.links.Number(num)
+ if link != nil {
+ v.digits = ""
+ if key == "t" {
+ return v, fireEvent(OpenNewTabEvent{URL: link.URL, Switch: true})
+ }
+ return v, fireEvent(LoadURLEvent{URL: link.URL, AddHistory: true})
+ }
+ default:
+ if "0" <= key && key <= "9" {
+ v.digits += key
+ return v, nil
+ }
}
case ButtonClickEvent:
return v, v.handleButtonClick(msg.Button)
@@ 192,6 217,9 @@ func (v Viewport) View() string {
if v.loading {
headerTail = fmt.Sprintf(" :: %s", v.spinner.View())
}
+ if v.digits != "" {
+ headerTail = fmt.Sprintf("%s :: %s", headerTail, v.digits)
+ }
header := fmt.Sprintf("%s%s ", v.URL, headerTail)
gapSize := v.viewport.Width - text.RuneCount(header)
header += strings.Repeat("─", gapSize)