fix: save drafts on quit (#1424)
Drew Smirnoff
created 1 month ago
## What?
Checks if the composer has contents at the moment of interrupt signal
(`ctrl+c`). If so, it saves the draft before quitting
## Why?
It is easy to accidentally quit, and it was unforgiving, without saving
anything. Especially including that the default quit keybind is the same
as "copy" on linux and windows (`ctrl+c`)
Signed-off-by: drew <me@andrinoff.com>
Change summary
main.go | 7 +++++++
tui/composer.go | 9 +++++++++
2 files changed, 16 insertions(+)
Detailed changes
@@ -340,6 +340,13 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { //nolint:gocyclo
switch msg := msg.(type) {
case tea.KeyPressMsg:
if msg.String() == "ctrl+c" {
+ // Persist an in-progress draft so quitting the composer
+ // doesn't discard the user's work.
+ if composer, ok := m.current.(*tui.Composer); ok && composer.HasContent() {
+ if err := config.SaveDraft(composer.ToDraft()); err != nil {
+ log.Printf("Error saving draft on quit: %v", err)
+ }
+ }
m.idleWatcher.StopAll()
if m.service != nil {
m.service.Close() //nolint:errcheck,gosec
@@ -1528,6 +1528,15 @@ func (m *Composer) HidePluginPrompt() {
m.showPluginPrompt = false
}
+// HasContent reports whether the composer holds anything worth persisting.
+// It is used to avoid saving empty drafts when the user quits the composer.
+func (m *Composer) HasContent() bool {
+ return m.hasAnyRecipient() ||
+ strings.TrimSpace(m.subjectInput.Value()) != "" ||
+ strings.TrimSpace(m.bodyInput.Value()) != "" ||
+ len(m.attachmentPaths) > 0
+}
+
// ToDraft converts the composer state to a Draft for saving.
func (m *Composer) ToDraft() config.Draft {
return config.Draft{