v0.4.1 #4, #20, #19, #17

drew created

Change summary

tui/inbox.go |  9 +++++++++
view/html.go | 47 ++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 53 insertions(+), 3 deletions(-)

Detailed changes

tui/inbox.go 🔗

@@ -136,6 +136,15 @@ func (m *Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		})
 	}
 
+	// New logic to fetch more emails when filtering is active
+	if m.list.FilterState() == list.Filtering && !m.isFetching {
+		m.isFetching = true
+		m.list.Title = "Fetching more emails..."
+		cmds = append(cmds, func() tea.Msg {
+			return FetchMoreEmailsMsg{Offset: uint32(m.emailsCount)}
+		})
+	}
+
 	var cmd tea.Cmd
 	var newModel list.Model
 	newModel, cmd = m.list.Update(msg)

view/html.go 🔗

@@ -1,12 +1,16 @@
 package view
 
 import (
+	"bytes"
 	"fmt"
 	"io"
 	"mime/quotedprintable"
+	"regexp"
 	"strings"
 
 	"github.com/PuerkitoBio/goquery"
+	"github.com/yuin/goldmark"
+	"github.com/yuin/goldmark/renderer/html"
 )
 
 // hyperlink formats a string as a terminal-clickable hyperlink.
@@ -26,6 +30,20 @@ func decodeQuotedPrintable(s string) (string, error) {
 	return string(body), nil
 }
 
+// markdownToHTML converts a Markdown string to an HTML string.
+func markdownToHTML(md []byte) []byte {
+	var buf bytes.Buffer
+	p := goldmark.New(
+		goldmark.WithRendererOptions(
+			html.WithUnsafe(), // Allow raw HTML in email.
+		),
+	)
+	if err := p.Convert(md, &buf); err != nil {
+		return md // Fallback to original markdown.
+	}
+	return buf.Bytes()
+}
+
 // ProcessBody takes a raw email body, decodes it, and formats it as plain
 // text with terminal hyperlinks.
 func ProcessBody(rawBody string) (string, error) {
@@ -35,7 +53,10 @@ func ProcessBody(rawBody string) (string, error) {
 		decodedBody = rawBody
 	}
 
-	doc, err := goquery.NewDocumentFromReader(strings.NewReader(decodedBody))
+	// Convert markdown to HTML before processing
+	htmlBody := markdownToHTML([]byte(decodedBody))
+
+	doc, err := goquery.NewDocumentFromReader(bytes.NewReader(htmlBody))
 	if err != nil {
 		return "", fmt.Errorf("could not parse email body: %w", err)
 	}
@@ -62,6 +83,26 @@ func ProcessBody(rawBody string) (string, error) {
 		s.ReplaceWithHtml(hyperlink(href, s.Text()))
 	})
 
-	// Return the document's text content, which now includes our formatting
-	return doc.Text(), nil
+	// Format images into terminal hyperlinks
+	doc.Find("img").Each(func(i int, s *goquery.Selection) {
+		src, exists := s.Attr("src")
+		if !exists {
+			return
+		}
+		alt, _ := s.Attr("alt")
+
+		if alt == "" {
+			alt = "Does not contain alt text"
+		}
+		s.ReplaceWithHtml(hyperlink(src, fmt.Sprintf("\n [Click here to view image: %s] \n", alt)))
+	})
+
+	// Get the document's text content, which now includes our formatting
+	text := doc.Text()
+
+	// Collapse more than 2 consecutive newlines into 2
+	re := regexp.MustCompile(`\n{3,}`)
+	text = re.ReplaceAllString(text, "\n\n")
+
+	return text, nil
 }