diff options
author | Jason Cox <me@jasoncarloscox.com> | 2024-01-25 08:25:51 -0500 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-01-26 21:36:15 +0100 |
commit | 11b035f120969758d1b08dddd761f9375504de55 (patch) | |
tree | bf028d7155ceb45deba3461cb73ed74413f3d965 | |
parent | 0aab8ac318f6dee479afba13d09a5d1d1c0baa91 (diff) | |
download | aerc-11b035f120969758d1b08dddd761f9375504de55.tar.gz |
flags: add support for draft flag
Support the draft flag wherever flags are used. Automatically set it
when postponing a message, and allow recalling a message without the -f
flag if it has the draft flag set, regardless of what folder it's in.
Notmuch doesn't seem to pick up on the draft flag when indexing even
though the flag is set on the maildir file. Explicitly set all tags
corresponding to set flags when appending a message in notmuch.
Changelog-added: Support the `draft` flag.
Signed-off-by: Jason Cox <me@jasoncarloscox.com>
Acked-by: Robin Jarry <robin@jarry.cc>
-rw-r--r-- | commands/account/search.go | 1 | ||||
-rw-r--r-- | commands/completion_helpers.go | 2 | ||||
-rw-r--r-- | commands/compose/postpone.go | 2 | ||||
-rw-r--r-- | commands/msg/read.go | 5 | ||||
-rw-r--r-- | commands/msg/recall.go | 12 | ||||
-rw-r--r-- | config/templates.go | 1 | ||||
-rw-r--r-- | config/ui.go | 3 | ||||
-rw-r--r-- | doc/aerc-config.5.scd | 7 | ||||
-rw-r--r-- | doc/aerc-search.1.scd | 2 | ||||
-rw-r--r-- | doc/aerc-templates.7.scd | 3 | ||||
-rw-r--r-- | doc/aerc.1.scd | 2 | ||||
-rw-r--r-- | lib/state/templates.go | 10 | ||||
-rw-r--r-- | models/models.go | 3 | ||||
-rw-r--r-- | models/templates.go | 1 | ||||
-rw-r--r-- | worker/imap/imap.go | 2 | ||||
-rw-r--r-- | worker/jmap/jmap.go | 5 | ||||
-rw-r--r-- | worker/lib/maildir.go | 4 | ||||
-rw-r--r-- | worker/notmuch/notmuch.go | 3 | ||||
-rw-r--r-- | worker/notmuch/worker.go | 27 |
19 files changed, 82 insertions, 13 deletions
diff --git a/commands/account/search.go b/commands/account/search.go index be3b125f..0246a9eb 100644 --- a/commands/account/search.go +++ b/commands/account/search.go @@ -73,6 +73,7 @@ var flagValues = map[string]models.Flags{ "seen": models.SeenFlag, "answered": models.AnsweredFlag, "flagged": models.FlaggedFlag, + "draft": models.DraftFlag, } func (s *SearchFilter) ParseFlag(arg string) error { diff --git a/commands/completion_helpers.go b/commands/completion_helpers.go index e4556594..b7ba6780 100644 --- a/commands/completion_helpers.go +++ b/commands/completion_helpers.go @@ -45,7 +45,7 @@ func GetAddress(search string) []string { // GetFlagList returns a list of available flags for completion func GetFlagList() []string { - return []string{"Seen", "Answered", "Flagged"} + return []string{"Seen", "Answered", "Flagged", "Draft"} } // GetDateList returns a list of date terms for completion diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go index a869417b..3c23eda3 100644 --- a/commands/compose/postpone.go +++ b/commands/compose/postpone.go @@ -108,7 +108,7 @@ func (p Postpone) Execute(args []string) error { } store.Append( targetFolder, - models.SeenFlag, + models.SeenFlag|models.DraftFlag, time.Now(), buf, buf.Len(), diff --git a/commands/msg/read.go b/commands/msg/read.go index b487d8a8..5b4bd073 100644 --- a/commands/msg/read.go +++ b/commands/msg/read.go @@ -41,13 +41,16 @@ func (f *FlagMsg) ParseFlag(arg string) error { case "flagged": f.Flag = models.FlaggedFlag f.FlagName = "flagged" + case "draft": + f.Flag = models.DraftFlag + f.FlagName = "draft" default: return fmt.Errorf("Unknown flag %q", arg) } return nil } -var validFlags = []string{"seen", "answered", "flagged"} +var validFlags = []string{"seen", "answered", "flagged", "draft"} func (*FlagMsg) CompleteFlag(arg string) []string { return commands.FilterList(validFlags, arg, nil) diff --git a/commands/msg/recall.go b/commands/msg/recall.go index 059fe558..e5cd2ed1 100644 --- a/commands/msg/recall.go +++ b/commands/msg/recall.go @@ -15,6 +15,7 @@ import ( "git.sr.ht/~rjarry/aerc/config" "git.sr.ht/~rjarry/aerc/lib" "git.sr.ht/~rjarry/aerc/log" + "git.sr.ht/~rjarry/aerc/models" "git.sr.ht/~rjarry/aerc/worker/types" ) @@ -44,10 +45,6 @@ func (r Recall) Execute(args []string) error { if acct == nil { return errors.New("No account selected") } - if acct.SelectedDirectory() != acct.AccountConfig().Postpone && !r.Force { - return errors.New("Use -f to recall from outside the " + - acct.AccountConfig().Postpone + " directory.") - } store := widget.Store() if store == nil { return errors.New("Cannot perform action. Messages still loading") @@ -57,6 +54,13 @@ func (r Recall) Execute(args []string) error { if err != nil { return errors.Wrap(err, "Recall failed") } + + if acct.SelectedDirectory() != acct.AccountConfig().Postpone && + !msgInfo.Flags.Has(models.DraftFlag) && !r.Force { + return errors.New("Use -f to recall non-draft messages from outside the " + + acct.AccountConfig().Postpone + " directory.") + } + log.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId) addTab := func(composer *app.Composer) { diff --git a/config/templates.go b/config/templates.go index c5d11478..61c411fb 100644 --- a/config/templates.go +++ b/config/templates.go @@ -94,6 +94,7 @@ func (d *dummyData) HasAttachment() bool { return true } func (d *dummyData) IsRecent() bool { return false } func (d *dummyData) IsUnread() bool { return false } func (d *dummyData) IsFlagged() bool { return false } +func (d *dummyData) IsDraft() bool { return false } func (d *dummyData) IsMarked() bool { return false } func (d *dummyData) MessageId() string { return "123456789@foo.org" } func (d *dummyData) Size() int { return 420 } diff --git a/config/ui.go b/config/ui.go index ed0b4a33..83b45230 100644 --- a/config/ui.go +++ b/config/ui.go @@ -55,9 +55,10 @@ type UIConfig struct { IconReplied string `ini:"icon-replied" default:"r"` IconNew string `ini:"icon-new" default:"N"` IconOld string `ini:"icon-old" default:"O"` + IconDraft string `ini:"icon-draft" default:"d"` IconFlagged string `ini:"icon-flagged" default:"!"` IconMarked string `ini:"icon-marked" default:"*"` - IconDeleted string `ini:"icon-deleted" default:"D"` + IconDeleted string `ini:"icon-deleted" default:"X"` DirListDelay time.Duration `ini:"dirlist-delay" default:"200ms"` DirListTree bool `ini:"dirlist-tree"` DirListCollapse int `ini:"dirlist-collapse"` diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd index 043b738a..1aa9da5f 100644 --- a/doc/aerc-config.5.scd +++ b/doc/aerc-config.5.scd @@ -405,10 +405,15 @@ These options are configured in the *[ui]* section of _aerc.conf_. Default: _\*_ +*icon-draft* = _<string>_ + The icon to display in *column-flags* when the message is a draft. + + Default: _d_ + *icon-deleted* = _<string>_ The icon to display in *column-flags* when the message has been deleted. - Default: _D_ + Default: _X_ *fuzzy-complete* = _true_|_false_ When typing a command or option, the popover will now show not only the diff --git a/doc/aerc-search.1.scd b/doc/aerc-search.1.scd index 161a632f..fa630c1d 100644 --- a/doc/aerc-search.1.scd +++ b/doc/aerc-search.1.scd @@ -34,6 +34,8 @@ This syntax is common to all backends. Replied messages _Flagged_ Flagged messages + _Draft_ + Draft messages *-H*: Search in the headers of the messages, for a specific header Syntax: _Header: Value_ diff --git a/doc/aerc-templates.7.scd b/doc/aerc-templates.7.scd index 160fb77f..6e87c616 100644 --- a/doc/aerc-templates.7.scd +++ b/doc/aerc-templates.7.scd @@ -116,7 +116,8 @@ available always. {{.Flags | join ""}} ``` -*IsReplied*, *HasAttachment*, *IsFlagged*, *IsRecent*, *IsUnread*, *IsMarked* +*IsReplied*, *HasAttachment*, *IsFlagged*, *IsRecent*, *IsUnread*, *IsMarked*, +*IsDraft* Individual boolean flags. not available when composing, replying nor forwarding. diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd index d77bbf03..1ee61060 100644 --- a/doc/aerc.1.scd +++ b/doc/aerc.1.scd @@ -418,6 +418,8 @@ message list, the message in the message viewer, etc). Message has been answered _Flagged_ Message is flagged for urgent/special attention + _Draft_ + Message is a draft *:unflag* [*-t*] _<flag>_ Operates exactly like *:flag*, defaulting to unsetting (disabling) flags. diff --git a/lib/state/templates.go b/lib/state/templates.go index ac701e9f..d039f1b6 100644 --- a/lib/state/templates.go +++ b/lib/state/templates.go @@ -393,6 +393,9 @@ func (d *templateData) Flags() []string { default: flags = append(flags, d.ui().IconOld) // message is unread and old } + if d.info.Flags.Has(models.DraftFlag) { + flags = append(flags, d.ui().IconDraft) + } if d.info.Flags.Has(models.DeletedFlag) { flags = append(flags, d.ui().IconDeleted) } @@ -452,6 +455,13 @@ func (d *templateData) IsFlagged() bool { return false } +func (d *templateData) IsDraft() bool { + if d.info != nil && d.info.Flags.Has(models.DraftFlag) { + return true + } + return false +} + func (d *templateData) IsMarked() bool { return d.marked } diff --git a/models/models.go b/models/models.go index 55dd2347..80bc0db1 100644 --- a/models/models.go +++ b/models/models.go @@ -30,6 +30,9 @@ const ( // FlaggedFlag marks a message with a user flag FlaggedFlag + + // DraftFlag marks a message as a draft + DraftFlag ) func (f Flags) Has(flags Flags) bool { diff --git a/models/templates.go b/models/templates.go index a6a85371..5caed158 100644 --- a/models/templates.go +++ b/models/templates.go @@ -38,6 +38,7 @@ type TemplateData interface { IsRecent() bool IsUnread() bool IsMarked() bool + IsDraft() bool MessageId() string Role() string Size() int diff --git a/worker/imap/imap.go b/worker/imap/imap.go index 82ee2e2e..fbdcb2b9 100644 --- a/worker/imap/imap.go +++ b/worker/imap/imap.go @@ -85,6 +85,7 @@ var imapToFlag = map[string]models.Flags{ imap.AnsweredFlag: models.AnsweredFlag, imap.DeletedFlag: models.DeletedFlag, imap.FlaggedFlag: models.FlaggedFlag, + imap.DraftFlag: models.DraftFlag, } var flagToImap = map[models.Flags]string{ @@ -93,6 +94,7 @@ var flagToImap = map[models.Flags]string{ models.AnsweredFlag: imap.AnsweredFlag, models.DeletedFlag: imap.DeletedFlag, models.FlaggedFlag: imap.FlaggedFlag, + models.DraftFlag: imap.DraftFlag, } func translateImapFlags(imapFlags []string) models.Flags { diff --git a/worker/jmap/jmap.go b/worker/jmap/jmap.go index 8012b6e4..bb0f75f9 100644 --- a/worker/jmap/jmap.go +++ b/worker/jmap/jmap.go @@ -67,6 +67,9 @@ func flagsToKeywords(flags models.Flags) map[string]bool { if flags.Has(models.FlaggedFlag) { kw["$flagged"] = true } + if flags.Has(models.DraftFlag) { + kw["$draft"] = true + } return kw } @@ -81,6 +84,8 @@ func keywordsToFlags(kw map[string]bool) models.Flags { f |= models.AnsweredFlag case "$flagged": f |= models.FlaggedFlag + case "$draft": + f |= models.DraftFlag } } } diff --git a/worker/lib/maildir.go b/worker/lib/maildir.go index 43d3b820..a4a0ecd5 100644 --- a/worker/lib/maildir.go +++ b/worker/lib/maildir.go @@ -118,7 +118,7 @@ var MaildirToFlag = map[maildir.Flag]models.Flags{ maildir.FlagSeen: models.SeenFlag, maildir.FlagTrashed: models.DeletedFlag, maildir.FlagFlagged: models.FlaggedFlag, - // maildir.FlagDraft Flag = 'D' + maildir.FlagDraft: models.DraftFlag, // maildir.FlagPassed Flag = 'P' } @@ -127,7 +127,7 @@ var FlagToMaildir = map[models.Flags]maildir.Flag{ models.SeenFlag: maildir.FlagSeen, models.DeletedFlag: maildir.FlagTrashed, models.FlaggedFlag: maildir.FlagFlagged, - // maildir.FlagDraft Flag = 'D' + models.DraftFlag: maildir.FlagDraft, // maildir.FlagPassed Flag = 'P' } diff --git a/worker/notmuch/notmuch.go b/worker/notmuch/notmuch.go index 5610cac0..1d064fd2 100644 --- a/worker/notmuch/notmuch.go +++ b/worker/notmuch/notmuch.go @@ -8,17 +8,20 @@ import "git.sr.ht/~rjarry/aerc/models" var tagToFlag = map[string]models.Flags{ "unread": models.SeenFlag, "replied": models.AnsweredFlag, + "draft": models.DraftFlag, "flagged": models.FlaggedFlag, } var flagToTag = map[models.Flags]string{ models.SeenFlag: "unread", models.AnsweredFlag: "replied", + models.DraftFlag: "draft", models.FlaggedFlag: "flagged", } var flagToInvert = map[models.Flags]bool{ models.SeenFlag: true, models.AnsweredFlag: false, + models.DraftFlag: false, models.FlaggedFlag: false, } diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go index 374a20b7..80a8d720 100644 --- a/worker/notmuch/worker.go +++ b/worker/notmuch/worker.go @@ -894,9 +894,16 @@ func (w *worker) handleAppendMessage(msg *types.AppendMessage) error { return err } writer.Close() - if _, err := w.db.IndexFile(filename); err != nil { + id, err := w.db.IndexFile(filename) + if err != nil { return err } + + err = w.addFlags(id, msg.Flags) + if err != nil { + return err + } + w.w.PostMessage(&types.DirectoryInfo{ Info: w.getDirectoryInfo(w.currentQueryName, w.query), }, nil) @@ -973,3 +980,21 @@ func (w *worker) processNewMaildirFiles(dir string) error { return nil } + +func (w *worker) addFlags(id string, flags models.Flags) error { + addTags := []string{} + removeTags := []string{} + for flag, tag := range flagToTag { + if !flags.Has(flag) { + continue + } + + if flagToInvert[flag] { + removeTags = append(removeTags, tag) + } else { + addTags = append(addTags, tag) + } + } + + return w.db.MsgModifyTags(id, addTags, removeTags) +} |