diff --git a/README.md b/README.md index c192799..ef1b97f 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ go install github.com/nemunaire/mqv@latest | `↑` / `↓` | Navigate messages | | `Enter` | Open message | | `r` | Refresh queue | +| `F` | Flush queue (`postqueue -f`) | | `q` | Quit | Subjects are fetched lazily in parallel via `postcat` as the list loads; a progress bar tracks completion. @@ -59,6 +60,7 @@ Subjects are fetched lazily in parallel via `postcat` as the list loads; a progr | `↑↓` / `Space` / `PgUp` / `PgDn` | Scroll | | `H` | Toggle full headers / short headers | | `s` | Save raw EML to `~/QUEUEID.eml` | +| `F` | Requeue message (`postsuper -r`) | | `v` | Browse MIME parts | | `q` | Back to queue list | diff --git a/model.go b/model.go index 197b432..1b32c28 100644 --- a/model.go +++ b/model.go @@ -210,6 +210,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.list.SetItems(nil) _ = m.progress.SetPercent(0) return m, loadQueueCmd() + case "F": + m.entries = nil + m.entryIndex = nil + m.loadingTotal = 0 + m.loadingDone = 0 + m.list.SetItems(nil) + _ = m.progress.SetPercent(0) + return m, flushQueueCmd() case "enter": if item, ok := m.list.SelectedItem().(queueItem); ok { return m, loadMessageCmd(item.entry.ID) @@ -254,6 +262,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.refreshViewport() m.viewport.GotoTop() return m, nil + case "F": + return m, requeueMessageCmd(m.currentID) case "v": m.parts = extractParts(m.currentRaw) m.partsCursor = 0 @@ -384,7 +394,7 @@ func (m Model) View() string { headersHint = "H: short headers" } status := statusBarStyle.Render( - fmt.Sprintf(" ↑↓/SPC/PgUp/Dn: scroll │ s: save EML │ v: parts │ %s │ q: back │ %d%% ", headersHint, scrollPct), + fmt.Sprintf(" ↑↓/SPC/PgUp/Dn: scroll │ s: save EML │ F: requeue │ v: parts │ %s │ q: back │ %d%% ", headersHint, scrollPct), ) notice := "" if m.messageSaving { @@ -464,7 +474,7 @@ func (m Model) renderBottom() string { return dimStyle.Render(label) + "\n " + m.progress.View() } status := statusBarStyle.Render( - fmt.Sprintf(" %d message(s) │ Enter: open │ r: refresh │ q: quit ", len(m.list.Items())), + fmt.Sprintf(" %d message(s) │ Enter: open │ r: refresh │ F: flush │ q: quit ", len(m.list.Items())), ) if item, ok := m.list.SelectedItem().(queueItem); ok { if reason := item.entry.Reason; reason != "" { diff --git a/msgs.go b/msgs.go index 9bf3bb9..00ef356 100644 --- a/msgs.go +++ b/msgs.go @@ -1,6 +1,8 @@ package main import ( + "os/exec" + tea "github.com/charmbracelet/bubbletea" ) @@ -34,6 +36,24 @@ func loadQueueCmd() tea.Cmd { } } +func flushQueueCmd() tea.Cmd { + return func() tea.Msg { + exec.Command("postqueue", "-f").Run() + entries, err := loadQueue() + if err != nil { + return queueErrMsg{err} + } + return queueParsedMsg{entries} + } +} + +func requeueMessageCmd(id string) tea.Cmd { + return func() tea.Msg { + exec.Command("postsuper", "-r", id).Run() + return nil + } +} + func fetchSubjectCmd(id string) tea.Cmd { return func() tea.Msg { raw, err := fetchHeaders(id)