From 677bb0c1ad7e472d841c00ab0086f42a3124ad58 Mon Sep 17 00:00:00 2001 From: drew Date: Mon, 28 Jul 2025 21:08:28 +0400 Subject: [PATCH 1/3] fix: return to all emails (#6) --- main.go | 18 +++++++++++++----- tui/inbox.go | 18 ++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/main.go b/main.go index a8cc2284213ec80fc79533019f77cbcc438f83a1..4686db5fce1101c00b6d7bd53783daaaf39c0ee3 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ type mainModel struct { current tea.Model config *config.Config emails []fetcher.Email + inbox *tui.Inbox width int height int err error @@ -58,9 +59,13 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.String() == "ctrl+c" { return m, tea.Quit } - // Allow ESC to go back to the main menu + // Allow ESC to go back if msg.String() == "esc" { - if _, ok := m.current.(*tui.Choice); !ok { + switch m.current.(type) { + case *tui.EmailView: + m.current = m.inbox + return m, nil + case *tui.Inbox, *tui.Composer: m.current = tui.NewChoice() return m, m.current.Init() } @@ -89,18 +94,21 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tui.EmailsFetchedMsg: m.emails = msg.Emails - m.current = tui.NewInbox(m.emails) + m.inbox = tui.NewInbox(m.emails) + m.current = m.inbox // Manually set the size of the new view m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height}) cmds = append(cmds, m.current.Init()) case tui.GoToSendMsg: - m.current = tui.NewComposer(m.config.Email) + composer := tui.NewComposer(m.config.Email) + m.current = &composer m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height}) cmds = append(cmds, m.current.Init()) case tui.ViewEmailMsg: - m.current = tui.NewEmailView(m.emails[msg.Index], m.width, m.height) + emailView := tui.NewEmailView(m.emails[msg.Index], m.width, m.height) + m.current = emailView cmds = append(cmds, m.current.Init()) case tui.SendEmailMsg: diff --git a/tui/inbox.go b/tui/inbox.go index 09ba116cae8cf78241271003b2772a7ef311a2f0..78456c691418cee49f938227e313598d5cc9b82d 100644 --- a/tui/inbox.go +++ b/tui/inbox.go @@ -11,8 +11,8 @@ import ( ) var ( - paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) - inboxHelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + inboxHelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) ) type item struct { @@ -50,7 +50,7 @@ type Inbox struct { list list.Model } -func NewInbox(emails []fetcher.Email) Inbox { +func NewInbox(emails []fetcher.Email) *Inbox { items := make([]list.Item, len(emails)) for i, email := range emails { items[i] = item{ @@ -67,14 +67,14 @@ func NewInbox(emails []fetcher.Email) Inbox { l.Styles.PaginationStyle = paginationStyle l.Styles.HelpStyle = inboxHelpStyle - return Inbox{list: l} + return &Inbox{list: l} } -func (m Inbox) Init() tea.Cmd { +func (m *Inbox) Init() tea.Cmd { return nil } -func (m Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m *Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: if msg.String() == "enter" { @@ -92,10 +92,12 @@ func (m Inbox) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } var cmd tea.Cmd - m.list, cmd = m.list.Update(msg) + var newModel list.Model + newModel, cmd = m.list.Update(msg) + m.list = newModel return m, cmd } -func (m Inbox) View() string { +func (m *Inbox) View() string { return "\n" + m.list.View() } \ No newline at end of file From a6c08bab26a0b4d4b7e6ceecd076ad25ed554912 Mon Sep 17 00:00:00 2001 From: drew Date: Mon, 28 Jul 2025 21:11:27 +0400 Subject: [PATCH 2/3] fix: return to the main menu in composer --- main.go | 9 +++++---- tui/composer.go | 31 ++++++++++++++++--------------- tui/composer_test.go | 16 ++++++++-------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/main.go b/main.go index 4686db5fce1101c00b6d7bd53783daaaf39c0ee3..cb94f1c1d6f3878650de34c6cb91c41e0e420f9c 100644 --- a/main.go +++ b/main.go @@ -61,12 +61,13 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // Allow ESC to go back if msg.String() == "esc" { + // Check the type of the current view to decide where to go. switch m.current.(type) { case *tui.EmailView: - m.current = m.inbox + m.current = m.inbox // Go back to the cached inbox return m, nil case *tui.Inbox, *tui.Composer: - m.current = tui.NewChoice() + m.current = tui.NewChoice() // Go back to the main menu return m, m.current.Init() } } @@ -101,8 +102,8 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, m.current.Init()) case tui.GoToSendMsg: - composer := tui.NewComposer(m.config.Email) - m.current = &composer + // NewComposer now returns *Composer, so we assign it directly. + m.current = tui.NewComposer(m.config.Email) m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height}) cmds = append(cmds, m.current.Init()) diff --git a/tui/composer.go b/tui/composer.go index de3b5c27fa861a8563c30b073f2cff31e72ab66b..b9b1810abcd1081ce58b26a016dfa53903275744 100644 --- a/tui/composer.go +++ b/tui/composer.go @@ -20,16 +20,16 @@ var ( // Composer model holds the state of the email composition UI. type Composer struct { - focusIndex int - toInput textinput.Model + focusIndex int + toInput textinput.Model subjectInput textinput.Model - bodyInput textarea.Model - fromAddr string + bodyInput textarea.Model + fromAddr string } // NewComposer initializes a new composer model. -func NewComposer(from string) Composer { - m := Composer{fromAddr: from} +func NewComposer(from string) *Composer { + m := &Composer{fromAddr: from} m.toInput = textinput.New() m.toInput.Cursor.Style = cursorStyle @@ -54,18 +54,19 @@ func NewComposer(from string) Composer { return m } -func (m Composer) Init() tea.Cmd { +func (m *Composer) Init() tea.Cmd { return textinput.Blink } -func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m *Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd var cmd tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: switch msg.Type { - case tea.KeyCtrlC, tea.KeyEsc: + // IMPORTANT: Removed tea.KeyEsc from this case + case tea.KeyCtrlC: return m, tea.Quit // Handle Tab and Shift+Tab to cycle focus between inputs. @@ -82,7 +83,7 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } else if m.focusIndex < 0 { m.focusIndex = 3 } - + // Blur all inputs m.toInput.Blur() m.subjectInput.Blur() @@ -91,11 +92,11 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Focus the correct input switch m.focusIndex { case 0: - m.toInput.Focus() + cmds = append(cmds, m.toInput.Focus()) case 1: - m.subjectInput.Focus() + cmds = append(cmds, m.subjectInput.Focus()) case 2: - m.bodyInput.Focus() + cmds = append(cmds, m.bodyInput.Focus()) } return m, tea.Batch(cmds...) @@ -131,7 +132,7 @@ func (m Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // View renders the UI. -func (m Composer) View() string { +func (m *Composer) View() string { button := &blurredButton if m.focusIndex == 3 { button = &focusedButton @@ -144,6 +145,6 @@ func (m Composer) View() string { m.subjectInput.View(), m.bodyInput.View(), *button, - helpStyle.Render("tab: next field • esc: quit"), + helpStyle.Render("tab: next field • esc: back to menu"), ) } \ No newline at end of file diff --git a/tui/composer_test.go b/tui/composer_test.go index d6db5f8bbc4d6ac8cb8a5312efe829619ade78fb..007051959f0739be395e91cb6644e8155683fb5f 100644 --- a/tui/composer_test.go +++ b/tui/composer_test.go @@ -19,29 +19,29 @@ func TestComposerUpdate(t *testing.T) { } // Simulate pressing Tab to move to the 'Subject' field. - model, _ := composer.Update(tea.KeyMsg{Type: tea.KeyTab}) - composer = model.(Composer) + model, _ := composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model + composer = model.(*Composer) // Cast to *Composer if composer.focusIndex != 1 { t.Errorf("After one Tab, focusIndex should be 1, got %d", composer.focusIndex) } // Simulate pressing Tab again to move to the 'Body' field. - model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) - composer = model.(Composer) + model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model + composer = model.(*Composer) // Cast to *Composer if composer.focusIndex != 2 { t.Errorf("After two Tabs, focusIndex should be 2, got %d", composer.focusIndex) } // Simulate pressing Tab again to move to the 'Send' button. - model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) - composer = model.(Composer) + model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model + composer = model.(*Composer) // Cast to *Composer if composer.focusIndex != 3 { t.Errorf("After three Tabs, focusIndex should be 3 (Send), got %d", composer.focusIndex) } // Simulate one more Tab to wrap around to the 'To' field. - model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) - composer = model.(Composer) + model, _ = composer.Update(tea.KeyMsg{Type: tea.KeyTab}) // model is tea.Model + composer = model.(*Composer) // Cast to *Composer if composer.focusIndex != 0 { t.Errorf("After four Tabs, focusIndex should wrap to 0, got %d", composer.focusIndex) } From 5ef3f1d98feb86b61f86048cb8487186c4c33dab Mon Sep 17 00:00:00 2001 From: drew Date: Mon, 28 Jul 2025 21:14:12 +0400 Subject: [PATCH 3/3] fix: remove css and script from email view (#5) --- view/html.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/view/html.go b/view/html.go index 2192b70a36ba8c89ec2c92973db9d774ac16fd5f..37487482377f91d08d33b6c63bcb64f8e924593f 100644 --- a/view/html.go +++ b/view/html.go @@ -40,6 +40,9 @@ func ProcessBody(rawBody string) (string, error) { return "", fmt.Errorf("could not parse email body: %w", err) } + // Remove style and script tags to clean up the view + doc.Find("style, script").Remove() + // Add newlines after block elements for better spacing doc.Find("p, div, h1, h2, h3, h4, h5, h6").Each(func(i int, s *goquery.Selection) { s.After("\n\n")