Prompt for filename when saving a message

Replace the immediate save-to-~/ID.eml with a filename prompt (default
ID.eml) consistent with the part-save UX. Enter confirms, Esc cancels.
Removes the now-unused saveMessage/saveCmd helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nemunaire 2026-03-29 19:33:31 +07:00
commit 70b0eedb9c
3 changed files with 30 additions and 16 deletions

View file

@ -410,15 +410,3 @@ func renderHTML(html string) string {
return string(out) return string(out)
} }
// saveMessage writes the raw EML content to ~/QUEUEID.eml.
func saveMessage(id, content string) (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("could not determine home directory: %w", err)
}
path := filepath.Join(home, id+".eml")
if err := os.WriteFile(path, []byte(content), 0600); err != nil {
return "", fmt.Errorf("write %s: %w", path, err)
}
return path, nil
}

View file

@ -42,6 +42,7 @@ type Model struct {
saveNotice string saveNotice string
width int width int
height int height int
messageSaving bool
// stateParts fields // stateParts fields
parts []MessagePart parts []MessagePart
partsCursor int partsCursor int
@ -215,6 +216,24 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
case stateMessage: case stateMessage:
if m.messageSaving {
switch msg.String() {
case "esc":
m.messageSaving = false
m.partsSaveInput.Blur()
return m, nil
case "enter":
name := strings.TrimSpace(m.partsSaveInput.Value())
content := m.currentRaw
m.messageSaving = false
m.partsSaveInput.Blur()
return m, saveMessageAsCmd(content, name)
default:
var cmd tea.Cmd
m.partsSaveInput, cmd = m.partsSaveInput.Update(msg)
return m, cmd
}
}
switch msg.String() { switch msg.String() {
case "q": case "q":
m.state = stateList m.state = stateList
@ -223,7 +242,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "ctrl+c": case "ctrl+c":
return m, tea.Quit return m, tea.Quit
case "s": case "s":
return m, saveCmd(m.currentID, m.currentRaw) m.messageSaving = true
m.saveNotice = ""
m.partsSaveInput.SetValue(m.currentID + ".eml")
m.partsSaveInput.CursorEnd()
m.partsSaveInput.Focus()
return m, textinput.Blink
case "H": case "H":
m.showFullHeaders = !m.showFullHeaders m.showFullHeaders = !m.showFullHeaders
m.refreshViewport() m.refreshViewport()
@ -352,7 +376,9 @@ func (m Model) View() string {
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 │ v: parts │ %s │ q: back │ %d%% ", headersHint, scrollPct),
) )
notice := "" notice := ""
if m.saveNotice != "" { if m.messageSaving {
notice = "\n Save as: " + m.partsSaveInput.View()
} else if m.saveNotice != "" {
notice = "\n" + saveNoticeStyle.Render(m.saveNotice) notice = "\n" + saveNoticeStyle.Render(m.saveNotice)
} }
return header + "\n" + m.viewport.View() + "\n" + status + notice return header + "\n" + m.viewport.View() + "\n" + status + notice

View file

@ -54,9 +54,9 @@ func loadMessageCmd(id string) tea.Cmd {
} }
} }
func saveCmd(id, content string) tea.Cmd { func saveMessageAsCmd(content, name string) tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
path, err := saveMessage(id, content) path, err := savePart([]byte(content), name)
if err != nil { if err != nil {
return saveErrMsg{err} return saveErrMsg{err}
} }