fix: split pane html conv and table fix (#1246)

Drew Smirnoff created

## What?

Fixes split pane HTML conversion, according to #1213 

Also changes in `view/html.go`:
- Extracted element loop into `renderHTMLToText` helper.
- `processBody` now: if `mimeType == text/html` and direct render is
whitespace-only, retry through `markdownToHTML` pre-pass

## Why?

Certain emails are not displayed correctly, as pointed by @EmilyxFox.
Also, split pane was displaying emails incorrectly not as per #1213 fix.

Signed-off-by: drew <me@andrinoff.com>

Change summary

tui/folder_inbox.go |  1 +
view/html.go        | 30 +++++++++++++++++++++++++-----
2 files changed, 26 insertions(+), 5 deletions(-)

Detailed changes

tui/folder_inbox.go 🔗

@@ -353,6 +353,7 @@ func (m *FolderInbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		}
 		// Update email with body
 		email.Body = msg.Body
+		email.BodyMIMEType = msg.BodyMIMEType
 		email.Attachments = msg.Attachments
 		// Create preview pane with column offset for image rendering
 		previewWidth := m.calculatePreviewWidth()

view/html.go 🔗

@@ -703,13 +703,36 @@ func processBody(rawBody, mimeType string, inline map[string]string, h1Style, h2
 	// HTML bodies skip the markdown pre-pass — md4c can mangle attribute-heavy
 	// or indented HTML (#602-style raw-tag bleed-through). Empty mimeType keeps
 	// legacy behavior for cached/legacy callers that don't supply one.
+	directHTML := mimeType == BodyMIMETypeHTML
 	var htmlBody []byte
-	if mimeType == BodyMIMETypeHTML {
+	if directHTML {
 		htmlBody = []byte(decodedBody)
 	} else {
 		htmlBody = markdownToHTML([]byte(decodedBody))
 	}
 
+	result, placements, err := renderHTMLToText(htmlBody, inline, h1Style, h2Style, disableImages)
+	if err != nil {
+		return "", nil, err
+	}
+
+	// Some real-world HTML emails (newsletters with table-only layouts and no
+	// <th>, AWeber-shape bodies) emit no visible content from htmlconv. Pre-
+	// c11de45, every body went through markdownToHTML first, which happened to
+	// keep these alive. Retry through the markdown pre-pass when the direct
+	// HTML path produces nothing.
+	if directHTML && strings.TrimSpace(result) == "" {
+		result, placements, err = renderHTMLToText(markdownToHTML([]byte(decodedBody)), inline, h1Style, h2Style, disableImages)
+		if err != nil {
+			return "", nil, err
+		}
+	}
+
+	result = styleQuotedReplies(result)
+	return bodyStyle.Render(result), placements, nil
+}
+
+func renderHTMLToText(htmlBody []byte, inline map[string]string, h1Style, h2Style lipgloss.Style, disableImages bool) (string, []ImagePlacement, error) {
 	// Parse HTML into structured elements using C parser.
 	elements, ok := clib.HTMLToElements(string(htmlBody))
 	if !ok {
@@ -849,10 +872,7 @@ func processBody(rawBody, mimeType string, inline map[string]string, h1Style, h2
 		result = imgMarkerRegex.ReplaceAllString(result, "")
 	}
 
-	// Style quoted reply sections (for plain text > quotes)
-	result = styleQuotedReplies(result)
-
-	return bodyStyle.Render(result), placements, nil
+	return result, placements, nil
 }
 
 func tableHeaderStyle() lipgloss.Style {