Skip to content

Commit 0342d95

Browse files
committed
link opening up to 100 links
1 parent 75e9d31 commit 0342d95

5 files changed

Lines changed: 46 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
# 2026-04-14
4+
- **CC/BCC display in reader** — the email reader now shows CC and BCC headers when viewing sent emails; both fields appear conditionally (only when present) between To and Subject in the header display; particularly useful for confirming auto_bcc was applied when replying; note that BCC visibility depends on IMAP provider behavior (some providers strip BCC headers from Sent folder, others preserve them)
5+
- **Extended link support (99 links)** — link opener now supports up to 99 links per email (previously limited to 10); `space+1-0` opens links 1-10, `space+l11-99` opens links 11-99 using intuitive numeric shortcuts (e.g. `space+l26` for link [26]); status line provides progressive feedback during multi-key input; footer help and `?` overlay updated
6+
- **Fix: link extraction with brackets in text** — markdown link regex now correctly matches links with brackets inside the link text (e.g. `[[Watch the studio tour here]](url)`); changed from `[^\]]+` (anything except `]`) to non-greedy `.+?` to handle nested brackets; fixes newsletter links from Beehiiv and similar services
7+
38
# 2026-04-13
49
- **Emoji reactions (`ctrl+e`)** — fast, keyboard-driven emoji reactions from inbox or reader; press `ctrl+e` to open emoji picker overlay, select with `1`-`8` for instant send or navigate with `j`/`k` and press `enter`; sends minimal reaction email (emoji + italic footer + quoted original message) with proper threading headers; available reactions: 👍 ❤️ 😂 🎉 🙏 💯 👀 ✅; original email marked with `\Answered` flag; reaction saved to Sent folder; auto-selects From address matching recipient (same logic as regular replies)
510
- **Email threading headers** — all replies (regular `r`/`R` and emoji reactions `ctrl+e`) now include proper `In-Reply-To` and `References` headers for conversation threading; ensures replies appear correctly grouped in Gmail, Outlook, and Apple Mail conversation views; `References` header extracted from IMAP message body and preserved in reply chain

docs/content/docs/keybindings.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ To update both the help overlay and this document at once, edit that file and ru
132132
| `e (pre-send)` | re-open editor to edit body |
133133
| `enter (pre-send)` | confirm and send |
134134
| `1-9 (reader)` | download attachment N to ~/Downloads and open with xdg-open |
135-
| `space+1-9 (reader)` | open link N in $BROWSER (0 = 10th link) |
135+
| `space+1-0 (reader)` | open link 1-10 in $BROWSER (0 = 10th link) |
136+
| `space+l11-99 (reader)` | open link 11-99 in $BROWSER (e.g. space+l26 for [26]) |
136137
| `e (reader)` | open in $EDITOR read-only — search, copy, vim motions |
137138
| `E (reader)` | continue draft — re-open as editable compose (Drafts folder) |
138139
| `o (reader)` | open in w3m (terminal browser) |

internal/ui/keys.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ var HelpSections = []HelpSection{
9999
{"e (pre-send)", "re-open editor to edit body"},
100100
{"enter (pre-send)", "confirm and send"},
101101
{"1-9 (reader)", "download attachment N to ~/Downloads and open with xdg-open"},
102-
{"space+1-9 (reader)", "open link N in $BROWSER (0 = 10th link)"},
102+
{"space+1-0 (reader)", "open link 1-10 in $BROWSER (0 = 10th link)"},
103+
{"space+l11-99 (reader)", "open link 11-99 in $BROWSER (e.g. space+l26 for [26])"},
103104
{"e (reader)", "open in $EDITOR read-only — search, copy, vim motions"},
104105
{"E (reader)", "continue draft — re-open as editable compose (Drafts folder)"},
105106
{"o (reader)", "open in w3m (terminal browser)"},

internal/ui/model.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,7 +2749,7 @@ func (m Model) updateReader(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
27492749
pending := m.readerPending
27502750
m.readerPending = ""
27512751
switch pending {
2752-
case " ": // space + digit opens link
2752+
case " ": // space + digit opens link (1-10)
27532753
if len(key) == 1 && key >= "0" && key <= "9" {
27542754
var idx int
27552755
if key == "0" {
@@ -2763,12 +2763,40 @@ func (m Model) updateReader(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
27632763
m.status = fmt.Sprintf("No link [%s].", key)
27642764
return m, nil
27652765
}
2766+
// space + l = prefix for links 11-99 (two digits)
2767+
if key == "l" {
2768+
m.readerPending = "l"
2769+
m.status = "link number (11-99): l__"
2770+
return m, nil
2771+
}
2772+
// Not a digit or 'l' — fall through
2773+
case "l": // l + first digit (waiting for second digit)
2774+
if len(key) == 1 && key >= "0" && key <= "9" {
2775+
m.readerPending = "l" + key
2776+
m.status = fmt.Sprintf("link number: l%s_", key)
2777+
return m, nil
2778+
}
27662779
// Not a digit — fall through
27672780
case "g": // gg = top of email
27682781
if key == "g" {
27692782
m.reader.GotoTop()
27702783
return m, nil
27712784
}
2785+
default:
2786+
// Handle "l[0-9]" pattern (first digit entered, waiting for second)
2787+
if len(pending) == 2 && pending[0] == 'l' && pending[1] >= '0' && pending[1] <= '9' {
2788+
if len(key) == 1 && key >= "0" && key <= "9" {
2789+
// Parse two-digit number
2790+
numStr := string(pending[1]) + key
2791+
num, _ := strconv.Atoi(numStr)
2792+
idx := num - 1 // convert to 0-based index
2793+
if idx >= 0 && idx < len(m.openLinks) {
2794+
return m, m.openLinkCmd(m.openLinks[idx].URL)
2795+
}
2796+
m.status = fmt.Sprintf("No link [%d].", num)
2797+
return m, nil
2798+
}
2799+
}
27722800
}
27732801
}
27742802

@@ -2821,7 +2849,11 @@ func (m Model) updateReader(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
28212849
case " ":
28222850
if len(m.openLinks) > 0 {
28232851
m.readerPending = " "
2824-
m.status = "open link: space+1-9 (0=10th)"
2852+
if len(m.openLinks) > 10 {
2853+
m.status = "open link: 1-0 (links 1-10), l11-99 (links 11+)"
2854+
} else {
2855+
m.status = "open link: 1-0"
2856+
}
28252857
return m, nil
28262858
}
28272859
case "g":

internal/ui/reader.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ func extractLinks(markdown string) []emailLink {
4040
}
4141
links = append(links, emailLink{Text: text, URL: url})
4242
}
43-
if len(links) > 10 {
44-
links = links[:10]
43+
if len(links) > 99 {
44+
links = links[:99]
4545
}
4646
return links
4747
}
@@ -141,7 +141,7 @@ func readerHelp(isDraft bool, hasLinks bool) string {
141141
}
142142
keys = append(keys, "o w3m", "O browser", "ctrl+o web", "1-9 attach")
143143
if hasLinks {
144-
keys = append(keys, "space+1-9 links")
144+
keys = append(keys, "space+1-0 links", "space+l11-99 links 11+")
145145
}
146146
keys = append(keys, "? help")
147147
return styleHelp.Render(" " + strings.Join(keys, " · "))

0 commit comments

Comments
 (0)