Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aerc for openSUSE:Factory checked in at 2025-01-27 20:52:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aerc (Old) and /work/SRC/openSUSE:Factory/.aerc.new.2316 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aerc" Mon Jan 27 20:52:48 2025 rev:15 rq:1240313 version:0.20.0 Changes: -------- --- /work/SRC/openSUSE:Factory/aerc/aerc.changes 2025-01-15 17:44:11.087128926 +0100 +++ /work/SRC/openSUSE:Factory/.aerc.new.2316/aerc.changes 2025-01-27 20:53:15.405694383 +0100 @@ -1,0 +2,23 @@ +Sat Jan 25 23:44:42 UTC 2025 - Hannes Braun <apple.han...@gmail.com> - 0.20.0 + +- Update to upstream version 0.20.0 + * copy-to now supports multiple destination folders. + * All commands that involve composing messages (:compose, :reply, :recall, + :unsubscribe and :forward) now have a new -s flag to skip opening the text + editor and go directly to the review screen. Previously, this flag was + restricted to calendar invitations response commands (:accept, + :accept-tentative and :decline). + * copy-to-replied now properly works without having copy-to also set. + * copy-to-replied creates empty messages when copy-to is also set. + * The address-book completion popovers now again appear under the field being + completed. + * The new-message bell is now rung again for threaded directories as well. + * The "default" styleset status line background has been reset to the default + color (light or dark, depending on your terminal color scheme) in order to + make error, warning or success messages more readable. + * Key bindings in the compose review screen are now displayed in the order in + which they are defined in the [compose::review] section of binds.conf. + * It is now possible to explicitly hide key bindings from the compose review + screen by using a special " # -" annotation. + +------------------------------------------------------------------- Old: ---- aerc-0.19.0.tar.gz New: ---- aerc-0.20.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aerc.spec ++++++ --- /var/tmp/diff_new_pack.j2uRwL/_old 2025-01-27 20:53:17.633786216 +0100 +++ /var/tmp/diff_new_pack.j2uRwL/_new 2025-01-27 20:53:17.633786216 +0100 @@ -18,7 +18,7 @@ Name: aerc -Version: 0.19.0 +Version: 0.20.0 Release: 0 Summary: An email client for terminals License: GPL-3.0-or-later ++++++ aerc-0.19.0.tar.gz -> aerc-0.20.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/.builds/alpine-edge.yml new/aerc-0.20.0/.builds/alpine-edge.yml --- old/aerc-0.19.0/.builds/alpine-edge.yml 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/.builds/alpine-edge.yml 2025-01-25 21:55:48.000000000 +0100 @@ -5,6 +5,7 @@ - go - gnupg - notmuch-dev + - py3-codespell - scdoc - valgrind sources: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/.codespellrc new/aerc-0.20.0/.codespellrc --- old/aerc-0.19.0/.codespellrc 1970-01-01 01:00:00.000000000 +0100 +++ new/aerc-0.20.0/.codespellrc 2025-01-25 21:55:48.000000000 +0100 @@ -0,0 +1,27 @@ +# ex: ft=dosini + +[codespell] +quiet-level = 35 +skip = + *.1, + *.5, + *.7, + *log*, + *.log*, + .changelog.md, + .env, + contrib/aerc.desktop, + filters/vectors/*, + tags, +ignore-words-list = + DeVault, + Fo, + THRID, + fo, + fpr, + froms, + localY, + ment, + struc, + te, + thrid, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/.gitignore new/aerc-0.20.0/.gitignore --- old/aerc-0.19.0/.gitignore 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/.gitignore 2025-01-25 21:55:48.000000000 +0100 @@ -1,15 +1,14 @@ -.go -/aerc2 /aerc /aerc.debug /wrap /colorize /linters.so -*.log* -*.1 -*.5 -*.7 +/*log* +/*.log* +/*.1 +/*.5 +/*.7 /.env /.changelog.md -aerc-release-stats.png -tags +/aerc-release-stats.png +/tags diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/CHANGELOG.md new/aerc-0.20.0/CHANGELOG.md --- old/aerc-0.19.0/CHANGELOG.md 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/CHANGELOG.md 2025-01-25 21:55:48.000000000 +0100 @@ -3,6 +3,39 @@ All notable changes to aerc will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [0.20.0](https://git.sr.ht/~rjarry/aerc/refs/0.20.0) - 2025-01-25 + +### Added + +- `copy-to` now supports multiple destination folders. +- All commands that involve composing messages (`:compose`, `:reply`, + `:recall`, `:unsubscribe` and `:forward`) now have a new `-s` flag to skip + opening the text editor and go directly to the review screen. Previously, + this flag was restricted to calendar invitations response commands + (`:accept`, `:accept-tentative` and `:decline`). + +### Fixed + +- `copy-to-replied` now properly works without having `copy-to` also set. +- `copy-to-replied` creates empty messages when `copy-to` is also set. +- The address-book completion popovers now again appear under the field being + completed. +- The new-message bell is now rung again for threaded directories as well. + +### Changed + +- The `default` styleset status line background has been reset to the default + color (light or dark, depending on your terminal color scheme) in order to + make error, warning or success messages more readable. +- Key bindings in the compose review screen are now displayed in the order in + which they are defined in the `[compose::review]` section of `binds.conf`. +- It is now possible to explicitly hide key bindings from the compose review + screen by using a special ` # -` annotation. + +### Closed Tickets + +- [#296: :compose: add flag to go directly to review screen](https://todo.sr.ht/~rjarry/aerc/296) + ## [0.19.0](https://git.sr.ht/~rjarry/aerc/refs/0.19.0) - 2025-01-14 ### Added diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/GNUmakefile new/aerc-0.20.0/GNUmakefile --- old/aerc-0.19.0/GNUmakefile 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/GNUmakefile 2025-01-25 21:55:48.000000000 +0100 @@ -1,6 +1,6 @@ # variables that can be changed by users # -VERSION ?= $(shell git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.19.0) +VERSION ?= $(shell git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.20.0) DATE ?= $(shell date +%Y-%m-%d) PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin @@ -57,6 +57,7 @@ @$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -d . | grep ^ \ && echo The above files need to be formatted, please run make fmt && exit 1 \ || echo all files formatted. + codespell * $(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 run \ $$(echo $(GOFLAGS) | sed s/-tags=/--build-tags=/) $(GO) run $(GOFLAGS) contrib/linters.go ./... @@ -84,7 +85,7 @@ .PHONY: clean clean: - $(RM) $(docs) aerc $(cfilters) linters.so + $(RM) $(docs) aerc $(cfilters) # Dependencies are added dynamically to the "install" rule with macros .PHONY: install diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/README.md new/aerc-0.20.0/README.md --- old/aerc-0.19.0/README.md 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/README.md 2025-01-25 21:55:48.000000000 +0100 @@ -46,6 +46,7 @@ - [aerc-stylesets(7)](https://git.sr.ht/~rjarry/aerc/tree/master/item/doc/aerc-stylesets.7.scd) - [aerc-templates(7)](https://git.sr.ht/~rjarry/aerc/tree/master/item/doc/aerc-templates.7.scd) - [aerc-tutorial(7)](https://git.sr.ht/~rjarry/aerc/tree/master/item/doc/aerc-tutorial.7.scd) +- [carddav-query(1)](https://git.sr.ht/~rjarry/aerc/tree/master/item/doc/carddav-query.1.scd) User contributions and integration with external tools: @@ -63,6 +64,7 @@ - [Fedora](https://packages.fedoraproject.org/pkgs/aerc/aerc/) - [openSUSE](https://build.opensuse.org/package/show/openSUSE:Factory/aerc) - [macOS through Homebrew](https://formulae.brew.sh/formula/aerc) +- [Slackware](https://slackbuilds.org/result/?search=aerc) And likely other platforms. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/app/aerc.go new/aerc-0.20.0/app/aerc.go --- old/aerc-0.19.0/app/aerc.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/app/aerc.go 2025-01-25 21:55:48.000000000 +0100 @@ -836,7 +836,7 @@ acctConf.Default = "INBOX" acctConf.Archive = "Archive" acctConf.Postpone = "Drafts" - acctConf.CopyTo = "Sent" + acctConf.CopyTo = []string{"Sent"} defer ui.Invalidate() @@ -938,7 +938,7 @@ return key.Matches(exKey.Key, exKey.Modifiers) } -// CmdFallbackSearch checks cmds for the first executable availabe in PATH. An error is +// CmdFallbackSearch checks cmds for the first executable available in PATH. An error is // returned if none are found func CmdFallbackSearch(cmds []string, silent bool) (string, error) { var tried []string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/app/compose.go new/aerc-0.20.0/app/compose.go --- old/aerc-0.19.0/app/compose.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/app/compose.go 2025-01-25 21:55:48.000000000 +0100 @@ -9,7 +9,6 @@ "os" "os/exec" "path/filepath" - "sort" "strconv" "strings" "sync" @@ -888,6 +887,30 @@ } else if err != nil { return nil, fmt.Errorf("mail.ReadMessage: %w", err) } + + // merge repeated to, cc, and bcc headers into a single one of each + for _, key := range []string{"To", "Cc", "Bcc"} { + fields := msg.Header.FieldsByKey(key) + if fields.Len() <= 1 { + continue + } + var addrs []*mail.Address + for fields.Next() { + if strings.TrimSpace(fields.Value()) == "" { + continue + } + al, err := mail.ParseAddressList(fields.Value()) + if err != nil { + return nil, fmt.Errorf( + "%s: cannot parse address list: %w", key, err) + } + addrs = append(addrs, al...) + } + msg.Header.SetAddressList(key, addrs) + PushWarning(fmt.Sprintf( + "Multiple %s headers found; merged in a single one.", key)) + } + return &msg.Header, nil } @@ -1651,64 +1674,58 @@ grid *ui.Grid } +var defaultAnnotations = map[string]string{ + ":send<enter>": "Send", + ":edit<enter>": "Edit (body and headers)", + ":attach<space>": "Add attachment", + ":detach<space>": "Remove attachment", + ":postpone<enter>": "Postpone", + ":preview<enter>": "Preview message", + ":abort<enter>": "Abort (discard message, no confirmation)", + ":choose -o d discard abort -o p postpone postpone<enter>": "Abort or postpone", +} + func newReviewMessage(composer *Composer, err error) *reviewMessage { bindings := config.Binds.ComposeReview.ForAccount( composer.acctConfig.Name, ) bindings = bindings.ForFolder(composer.SelectedDirectory()) - const maxInputWidth = 6 type reviewCmd struct { + input string output string annotation string - input string } - reviewCmds := []reviewCmd{ - {":send<enter>", "Send", ""}, - {":edit<enter>", "Edit (body and headers)", ""}, - {":attach<space>", "Add attachment", ""}, - {":detach<space>", "Remove attachment", ""}, - {":postpone<enter>", "Postpone", ""}, - {":preview<enter>", "Preview message", ""}, - {":abort<enter>", "Abort (discard message, no confirmation)", ""}, - {":choose -o d discard abort -o p postpone postpone<enter>", "Abort or postpone", ""}, - } - knownCommands := len(reviewCmds) - var actions []string + var reviewCmds []reviewCmd + for _, binding := range bindings.Bindings { + if binding.Annotation == "-" { + // explicitly hidden by user + continue + } + inputs := config.FormatKeyStrokes(binding.Input) outputs := config.FormatKeyStrokes(binding.Output) - found := false - for i, rcmd := range reviewCmds { - if outputs == rcmd.output { - found = true - if reviewCmds[i].input == "" { - reviewCmds[i].input = inputs - } else { - reviewCmds[i].input += ", " + inputs - } - if binding.Annotation != "" { - // overwrite default description with - // user annotations if present - reviewCmds[i].annotation = binding.Annotation + annotation := binding.Annotation + if annotation == "" { + for i := range reviewCmds { + r := &reviewCmds[i] + if r.output == outputs { + // aliased action with a different binding + r.input += ", " + inputs + goto next } - break } + annotation = defaultAnnotations[outputs] } - if !found { - rcmd := reviewCmd{ - output: outputs, - annotation: binding.Annotation, - input: inputs, - } - reviewCmds = append(reviewCmds, rcmd) - } + reviewCmds = append(reviewCmds, reviewCmd{ + input: inputs, + output: outputs, + annotation: annotation, + }) + next: } - unknownCommands := reviewCmds[knownCommands:] - sort.Slice(unknownCommands, func(i, j int) bool { - return unknownCommands[i].input < unknownCommands[j].input - }) longest := 0 for _, rcmd := range reviewCmds { @@ -1717,17 +1734,17 @@ } } + const maxInputWidth = 6 width := longest if longest < maxInputWidth { width = maxInputWidth } widthstr := strconv.Itoa(width) + var actions []string for _, rcmd := range reviewCmds { - if rcmd.input != "" { - actions = append(actions, fmt.Sprintf(" %-"+widthstr+"s %-40s %s", - rcmd.input, rcmd.annotation, rcmd.output)) - } + actions = append(actions, fmt.Sprintf(" %-"+widthstr+"s %-40s %s", + rcmd.input, rcmd.annotation, rcmd.output)) } spec := []ui.GridSpec{ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/account/compose.go new/aerc-0.20.0/commands/account/compose.go --- old/aerc-0.19.0/commands/account/compose.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/account/compose.go 2025-01-25 21:55:48.000000000 +0100 @@ -16,11 +16,12 @@ ) type Compose struct { - Headers string `opt:"-H" action:"ParseHeader" desc:"Add the specified header to the message."` - Template string `opt:"-T" complete:"CompleteTemplate" desc:"Template name."` - Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` - NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` - Body string `opt:"..." required:"false"` + Headers string `opt:"-H" action:"ParseHeader" desc:"Add the specified header to the message."` + Template string `opt:"-T" complete:"CompleteTemplate" desc:"Template name."` + Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` + NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."` + Body string `opt:"..." required:"false"` } func init() { @@ -87,5 +88,8 @@ return err } composer.Tab = app.NewTab(composer, "New email") + if c.SkipEditor { + composer.Terminal().Close() + } return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/compose/send.go new/aerc-0.20.0/commands/compose/send.go --- old/aerc-0.19.0/commands/compose/send.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/compose/send.go 2025-01-25 21:55:48.000000000 +0100 @@ -25,8 +25,8 @@ ) type Send struct { - Archive string `opt:"-a" action:"ParseArchive" metavar:"flat|year|month" complete:"CompleteArchive" desc:"Archive the message being replied to."` - CopyTo string `opt:"-t" complete:"CompleteFolders" desc:"Override the Copy-To folder."` + Archive string `opt:"-a" action:"ParseArchive" metavar:"flat|year|month" complete:"CompleteArchive" desc:"Archive the message being replied to."` + CopyTo []string `opt:"-t" complete:"CompleteFolders" action:"ParseCopyTo" desc:"Override the Copy-To folders."` CopyToReplied bool `opt:"-r" desc:"Save sent message to current folder."` NoCopyToReplied bool `opt:"-R" desc:"Do not save sent message to current folder."` @@ -66,6 +66,11 @@ return errors.New("unsupported archive type") } +func (o *Send) ParseCopyTo(arg string) error { + o.CopyTo = append(o.CopyTo, strings.Split(arg, ",")...) + return nil +} + func (s Send) Execute(args []string) error { tab := app.SelectedTab() if tab == nil { @@ -80,7 +85,7 @@ config := composer.Config() - if s.CopyTo == "" { + if len(s.CopyTo) == 0 { s.CopyTo = config.CopyTo } copyToReplied := config.CopyToReplied || (s.CopyToReplied && !s.NoCopyToReplied) @@ -173,7 +178,7 @@ } func sendHelper(composer *app.Composer, header *mail.Header, uri *url.URL, domain string, - from *mail.Address, rcpts []*mail.Address, tabName string, copyTo string, + from *mail.Address, rcpts []*mail.Address, tabName string, copyTo []string, archive string, copyToReplied bool, ) { // we don't want to block the UI thread while we are sending @@ -184,7 +189,7 @@ // enter no-quit mode mode.NoQuit() - var shouldCopy bool = copyTo != "" && !strings.HasPrefix(uri.Scheme, "jmap") + var shouldCopy bool = (len(copyTo) > 0 || copyToReplied) && !strings.HasPrefix(uri.Scheme, "jmap") var copyBuf bytes.Buffer failCh := make(chan error) @@ -193,9 +198,7 @@ defer log.PanicHandler() var folders []string - if copyTo != "" { - folders = append(folders, copyTo) - } + folders = append(folders, copyTo...) if copyToReplied && composer.Parent() != nil { folders = append(folders, composer.Parent().Folder) } @@ -234,7 +237,7 @@ return } if shouldCopy { - app.PushStatus("Copying to "+copyTo, 10*time.Second) + app.PushStatus("Copying to copy-to folders", 10*time.Second) errch := copyToSent(copyTo, copyToReplied, copyBuf.Len(), ©Buf, composer) err = <-errch @@ -275,7 +278,7 @@ return rcpts, nil } -func copyToSent(dest string, copyToReplied bool, n int, msg io.Reader, composer *app.Composer) <-chan error { +func copyToSent(dests []string, copyToReplied bool, n int, msg *bytes.Buffer, composer *app.Composer) <-chan error { errCh := make(chan error, 1) acct := composer.Account() if acct == nil { @@ -287,27 +290,29 @@ errCh <- errors.New("No message store selected") return errCh } - store.Append( - dest, - models.SeenFlag, - time.Now(), - msg, - n, - func(msg types.WorkerMessage) { - switch msg := msg.(type) { - case *types.Done: - errCh <- nil - case *types.Error: - errCh <- msg.Error - } - }, - ) + for _, dest := range dests { + store.Append( + dest, + models.SeenFlag, + time.Now(), + bytes.NewReader(msg.Bytes()), + n, + func(msg types.WorkerMessage) { + switch msg := msg.(type) { + case *types.Done: + errCh <- nil + case *types.Error: + errCh <- msg.Error + } + }, + ) + } if copyToReplied && composer.Parent() != nil { store.Append( composer.Parent().Folder, models.SeenFlag, time.Now(), - msg, + bytes.NewReader(msg.Bytes()), n, func(msg types.WorkerMessage) { switch msg := msg.(type) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/msg/forward.go new/aerc-0.20.0/commands/msg/forward.go --- old/aerc-0.19.0/commands/msg/forward.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/msg/forward.go 2025-01-25 21:55:48.000000000 +0100 @@ -30,6 +30,7 @@ Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` Template string `opt:"-T" complete:"CompleteTemplate" desc:"Template name."` + SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."` To []string `opt:"..." required:"false" complete:"CompleteTo" desc:"Recipient from address book."` } @@ -106,9 +107,12 @@ } composer.Tab = app.NewTab(composer, subject) - if !h.Has("to") { + switch { + case f.SkipEditor: + composer.Terminal().Close() + case !h.Has("to"): composer.FocusEditor("to") - } else { + default: composer.FocusTerminal() } return composer, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/msg/invite.go new/aerc-0.20.0/commands/msg/invite.go --- old/aerc-0.19.0/commands/msg/invite.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/msg/invite.go 2025-01-25 21:55:48.000000000 +0100 @@ -141,7 +141,11 @@ if err != nil { return fmt.Errorf("failed to write invitation: %w", err) } - composer.FocusTerminal() + if i.SkipEditor { + composer.Terminal().Close() + } else { + composer.FocusTerminal() + } composer.Tab = app.NewTab(composer, subject) @@ -158,10 +162,6 @@ } }) - if i.SkipEditor { - composer.Terminal().Close() - } - return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/msg/recall.go new/aerc-0.20.0/commands/msg/recall.go --- old/aerc-0.19.0/commands/msg/recall.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/msg/recall.go 2025-01-25 21:55:48.000000000 +0100 @@ -20,9 +20,10 @@ ) type Recall struct { - Force bool `opt:"-f" desc:"Force recall if not in postpone directory."` - Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` - NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + Force bool `opt:"-f" desc:"Force recall if not in postpone directory."` + Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` + NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."` } func init() { @@ -129,7 +130,7 @@ } } - // add attachements if present + // add attachments if present var mu sync.Mutex parts := lib.FindAllNonMultipart(msg.BodyStructure(), nil, nil) for _, p := range parts { @@ -162,8 +163,12 @@ composer.SetRecalledFrom(acct.SelectedDirectory()) } - // focus the terminal since the header fields are likely already done - composer.FocusTerminal() + if r.SkipEditor { + composer.Terminal().Close() + } else { + // focus the terminal since the header fields are likely already done + composer.FocusTerminal() + } addTab(composer) }) }) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/msg/reply.go new/aerc-0.20.0/commands/msg/reply.go --- old/aerc-0.19.0/commands/msg/reply.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/msg/reply.go 2025-01-25 21:55:48.000000000 +0100 @@ -23,14 +23,15 @@ ) type reply struct { - All bool `opt:"-a" desc:"Reply to all recipients."` - Close bool `opt:"-c" desc:"Close the view tab when replying."` - From bool `opt:"-f" desc:"Reply to all addresses in From and Reply-To headers."` - Quote bool `opt:"-q" desc:"Alias of -T quoted-reply."` - Template string `opt:"-T" complete:"CompleteTemplate" desc:"Template name."` - Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` - NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` - Account string `opt:"-A" complete:"CompleteAccount" desc:"Reply with the specified account."` + All bool `opt:"-a" desc:"Reply to all recipients."` + Close bool `opt:"-c" desc:"Close the view tab when replying."` + From bool `opt:"-f" desc:"Reply to all addresses in From and Reply-To headers."` + Quote bool `opt:"-q" desc:"Alias of -T quoted-reply."` + Template string `opt:"-T" complete:"CompleteTemplate" desc:"Template name."` + Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` + NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + Account string `opt:"-A" complete:"CompleteAccount" desc:"Reply with the specified account."` + SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."` } func init() { @@ -181,7 +182,9 @@ app.RemoveTab(mv, true) } - if args[0] == "reply" { + if r.SkipEditor { + composer.Terminal().Close() + } else if args[0] == "reply" { composer.FocusTerminal() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/commands/msg/unsubscribe.go new/aerc-0.20.0/commands/msg/unsubscribe.go --- old/aerc-0.19.0/commands/msg/unsubscribe.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/commands/msg/unsubscribe.go 2025-01-25 21:55:48.000000000 +0100 @@ -19,8 +19,9 @@ // Unsubscribe helps people unsubscribe from mailing lists by way of the // List-Unsubscribe header. type Unsubscribe struct { - Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` - NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."` + NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."` + SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."` } func init() { @@ -68,7 +69,7 @@ var err error switch strings.ToLower(method.Scheme) { case "mailto": - err = unsubscribeMailto(method, editHeaders) + err = unsubscribeMailto(method, editHeaders, u.SkipEditor) case "http", "https": err = unsubscribeHTTP(method) default: @@ -140,7 +141,7 @@ } } -func unsubscribeMailto(u *url.URL, editHeaders bool) error { +func unsubscribeMailto(u *url.URL, editHeaders, skipEditor bool) error { widget := app.SelectedTabContent().(app.ProvidesMessage) acct := widget.SelectedAccount() if acct == nil { @@ -154,7 +155,6 @@ } composer, err := app.NewComposer( - acct, acct.AccountConfig(), acct.Worker(), @@ -168,7 +168,11 @@ return err } composer.Tab = app.NewTab(composer, "unsubscribe") - composer.FocusTerminal() + if skipEditor { + composer.Terminal().Close() + } else { + composer.FocusTerminal() + } return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/accounts.go new/aerc-0.20.0/config/accounts.go --- old/aerc-0.19.0/config/accounts.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/accounts.go 2025-01-25 21:55:48.000000000 +0100 @@ -97,7 +97,7 @@ Params map[string]string Archive string `ini:"archive" default:"Archive"` - CopyTo string `ini:"copy-to"` + CopyTo []string `ini:"copy-to" delim:","` CopyToReplied bool `ini:"copy-to-replied" default:"false"` StripBcc bool `ini:"strip-bcc" default:"true"` Default string `ini:"default" default:"INBOX"` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/aerc.conf new/aerc-0.20.0/config/aerc.conf --- old/aerc-0.19.0/config/aerc.conf 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/aerc.conf 2025-01-25 21:55:48.000000000 +0100 @@ -676,7 +676,7 @@ # Specifies the command to be used to select attachments. Any occurrence of # '%s' in the file-picker-cmd will be replaced with the argument <arg> -# to :attach -m <arg>. Any occurence of '%f' will be replaced by the +# to :attach -m <arg>. Any occurrence of '%f' will be replaced by the # location of a temporary file, from which aerc will read the selected files. # # If '%f' is not present, the command must output the selected files to diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/binds.conf new/aerc-0.20.0/config/binds.conf --- old/aerc-0.19.0/config/binds.conf 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/binds.conf 2025-01-25 21:55:48.000000000 +0100 @@ -167,6 +167,8 @@ # Inline comments are used as descriptions on the review screen y = :send<Enter> # Send n = :abort<Enter> # Abort (discard message, no confirmation) +s = :sign<Enter> # Toggle signing of this message with your PGP key +x = :encrypt<Enter> # Toggle encryption of this message to all recipients v = :preview<Enter> # Preview message p = :postpone<Enter> # Postpone q = :choose -o d discard abort -o p postpone postpone<Enter> # Abort or postpone diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/binds.go new/aerc-0.20.0/config/binds.go --- old/aerc-0.19.0/config/binds.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/binds.go 2025-01-25 21:55:48.000000000 +0100 @@ -130,7 +130,7 @@ // Base Bindings for _, sectionName := range binds.SectionStrings() { - // Handle :: delimeter + // Handle :: delimiter baseSectionName := strings.ReplaceAll(sectionName, "::", "////") sections := strings.Split(baseSectionName, ":") baseOnly := len(sections) == 1 @@ -173,9 +173,9 @@ func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) { bindings := NewKeyBindings() - for key, value := range sec.KeysHash() { - var annotation string - value, annotation, _ = strings.Cut(value, " # ") + for _, k := range sec.Keys() { + key := k.Name() + value, annotation, _ := strings.Cut(k.String(), " # ") value = strings.TrimSpace(value) switch key { case "$ex": @@ -471,18 +471,21 @@ var sb strings.Builder for _, stroke := range keystrokes { + special := false s := "" for name, ks := range keyNames { if (ks.Modifiers == stroke.Modifiers || ks.Modifiers == vaxis.ModifierMask(0)) && ks.Key == stroke.Key { switch name { case "cr": - s = "<enter>" + special = true + s = "enter" case "space": s = " " case "semicolon": s = ";" default: - s = fmt.Sprintf("<%s>", name) + special = true + s = name } // remove any modifiers this named key comes // with so we format properly @@ -490,6 +493,12 @@ break } } + if stroke.Modifiers != vaxis.ModifierMask(0) { + special = true + } + if special { + sb.WriteString("<") + } if stroke.Modifiers&vaxis.ModCtrl > 0 { sb.WriteString("c-") } @@ -503,6 +512,9 @@ s = string(stroke.Key) } sb.WriteString(s) + if special { + sb.WriteString(">") + } } // replace leading & trailing spaces with explicit <space> keystrokes @@ -609,38 +621,9 @@ "f61": {vaxis.ModifierMask(0), vaxis.KeyF61}, "f62": {vaxis.ModifierMask(0), vaxis.KeyF62}, "f63": {vaxis.ModifierMask(0), vaxis.KeyF63}, - "nul": {vaxis.ModCtrl, ' '}, - "soh": {vaxis.ModCtrl, 'a'}, - "stx": {vaxis.ModCtrl, 'b'}, - "etx": {vaxis.ModCtrl, 'c'}, - "eot": {vaxis.ModCtrl, 'd'}, - "enq": {vaxis.ModCtrl, 'e'}, - "ack": {vaxis.ModCtrl, 'f'}, - "bel": {vaxis.ModCtrl, 'g'}, - "bs": {vaxis.ModCtrl, 'h'}, "tab": {vaxis.ModifierMask(0), vaxis.KeyTab}, - "lf": {vaxis.ModCtrl, 'j'}, - "vt": {vaxis.ModCtrl, 'k'}, - "ff": {vaxis.ModCtrl, 'l'}, "cr": {vaxis.ModifierMask(0), vaxis.KeyEnter}, - "so": {vaxis.ModCtrl, 'n'}, - "si": {vaxis.ModCtrl, 'o'}, - "dle": {vaxis.ModCtrl, 'p'}, - "dc1": {vaxis.ModCtrl, 'q'}, - "dc2": {vaxis.ModCtrl, 'r'}, - "dc3": {vaxis.ModCtrl, 's'}, - "dc4": {vaxis.ModCtrl, 't'}, - "nak": {vaxis.ModCtrl, 'u'}, - "syn": {vaxis.ModCtrl, 'v'}, - "etb": {vaxis.ModCtrl, 'w'}, - "can": {vaxis.ModCtrl, 'x'}, - "em": {vaxis.ModCtrl, 'y'}, - "sub": {vaxis.ModCtrl, 'z'}, "esc": {vaxis.ModifierMask(0), vaxis.KeyEsc}, - "fs": {vaxis.ModCtrl, '\\'}, - "gs": {vaxis.ModCtrl, ']'}, - "rs": {vaxis.ModCtrl, '^'}, - "us": {vaxis.ModCtrl, '_'}, "del": {vaxis.ModifierMask(0), vaxis.KeyDelete}, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/binds_test.go new/aerc-0.20.0/config/binds_test.go --- old/aerc-0.19.0/config/binds_test.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/binds_test.go 2025-01-25 21:55:48.000000000 +0100 @@ -92,7 +92,9 @@ formatted string }{ {KeyStroke{vaxis.ModifierMask(0), vaxis.KeyLeft}, "<left>"}, - {KeyStroke{vaxis.ModCtrl, vaxis.KeyLeft}, "c-<left>"}, + {KeyStroke{vaxis.ModCtrl, vaxis.KeyLeft}, "<c-left>"}, + {KeyStroke{vaxis.ModCtrl, 'e'}, "<c-e>"}, + {KeyStroke{vaxis.ModifierMask(0), vaxis.KeySpace}, "<space>"}, } for _, test := range tests { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/style.go new/aerc-0.20.0/config/style.go --- old/aerc-0.19.0/config/style.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/style.go 2025-01-25 21:55:48.000000000 +0100 @@ -327,12 +327,15 @@ *.selected.fg = 15 *.selected.bold = true statusline_*.dim = true -statusline_*.bg = 8 -statusline_*.fg = 15 -*warning.fg = 3 -*success.fg = 2 -*error.fg = 1 +*warning.dim = false +*warning.bold = true +*warning.fg = 11 +*success.dim = false +*success.bold = true +*success.fg = 10 +*error.dim = false *error.bold = true +*error.fg = 9 border.fg = 12 border.bold = true title.bg = 12 @@ -505,8 +508,8 @@ } var ( - styleObjRe = regexp.MustCompile(`^([\w\*\?]+)(?:\.([\w-]+,.+?)+?)?(\.selected)?\.(\w+)$`) - styleHeaderPatternsRe = regexp.MustCompile(`([\w-]+),(.+?)\.`) + styleObjRe = regexp.MustCompile(`^([\w\*\?]+)(\.(?:[\w-]+,.+?)+?)?(\.selected)?\.(\w+)$`) + styleHeaderPatternsRe = regexp.MustCompile(`([\w-]+),(~/(?:.+?)/|(?:.+?))\.`) ) func (ss *StyleSet) parseKey(key *ini.Key, selected bool) error { @@ -577,9 +580,12 @@ for _, p := range headerPatterns { var pattern string - if strings.HasPrefix(p.RawPattern, "~") { + switch { + case strings.HasPrefix(p.RawPattern, "~/"): + pattern = p.RawPattern[2 : len(p.RawPattern)-1] + case strings.HasPrefix(p.RawPattern, "~"): pattern = p.RawPattern[1:] - } else { + default: pattern = "^" + regexp.QuoteMeta(p.RawPattern) + "$" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/config/style_test.go new/aerc-0.20.0/config/style_test.go --- old/aerc-0.19.0/config/style_test.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/config/style_test.go 2025-01-25 21:55:48.000000000 +0100 @@ -11,9 +11,10 @@ msglist_*.fg = salmon msglist_*.From,~^"Bob Foo".fg = khaki msglist_*.From,~^"Bob Foo".selected.fg = palegreen -msglist_*.From,~^"Bob Foo".Subject,~PATCH.fg = coral +msglist_*.Subject,~PATCH.From,~^"Bob Foo".fg = coral msglist_*.From,~^"Bob Foo".Subject,~PATCH.X-Baz,exact.X-Clacks-Overhead,~Pratchett$.fg = plum msglist_*.From,~^"Bob Foo".Subject,~PATCH.X-Clacks-Overhead,~Pratchett$.fg = pink +msglist_*.From,~^"Bob Foo".List-ID,~/lists\.sr\.ht/.fg = pink ` func TestStyleMultiHeaderPattern(t *testing.T) { @@ -85,5 +86,16 @@ if s.Foreground != colorNames["pink"] { t.Errorf("expected:#%x got:#%x", colorNames["pink"], s.Foreground) } + }) + + t.Run("handles uris in regular expressions", func(t *testing.T) { + var h mail.Header + h.SetAddressList("From", []*mail.Address{{"Bob Foo", "b...@foo.org"}}) + h.SetText("List-ID", "List-ID: ~rjarry/aerc-discuss <~rjarry/aerc-discuss.lists.sr.ht>") + + s := ss.Get(STYLE_MSGLIST_DEFAULT, &h) + if s.Foreground != colorNames["pink"] { + t.Errorf("expected:#%x got:#%x", colorNames["pink"], s.Foreground) + } }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/contrib/check-patches new/aerc-0.20.0/contrib/check-patches --- old/aerc-0.19.0/contrib/check-patches 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/contrib/check-patches 2025-01-25 21:55:48.000000000 +0100 @@ -78,6 +78,10 @@ err "body has less than three words, please describe your changes" fi + if ! git log --format='%s%n%b' -1 "$rev" | codespell -; then + err "typos in title and/or body" + fi + if [ "$fail" = true ]; then continue fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-accounts.5.scd new/aerc-0.20.0/doc/aerc-accounts.5.scd --- old/aerc-0.19.0/doc/aerc-accounts.5.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-accounts.5.scd 2025-01-25 21:55:48.000000000 +0100 @@ -50,8 +50,11 @@ Default: _0_ -*copy-to* = _<folder>_ - Specifies a folder to copy sent mails to, usually _Sent_. +*copy-to* = _<folder1,folder2,folder3...>_ + Specifies a comma separated list of folders to copy sent mails to, + usually _Sent_. + + By default, the mail is copied to no folders; *copy-to-replied* = _true_|_false_ In addition of *copy-to*, also copy replies to the folder in which the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-binds.5.scd new/aerc-0.20.0/doc/aerc-binds.5.scd --- old/aerc-0.19.0/doc/aerc-binds.5.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-binds.5.scd 2025-01-25 21:55:48.000000000 +0100 @@ -54,12 +54,19 @@ keybindings for the composer, when reviewing the email before it's sent To customize the description shown on the review screen, add a comment - (" # ") at the end of the keybinding. - - Example: + (_" # "_) at the end of the keybinding. Example: p = :postpone<Enter> # I'll work on it later + The order in which bindings are defined is preserved on the review + screen. If a non-default binding is not annotated it will be displayed + without any description. + + To hide a binding from the review screen, explicitly annotate it with + a _" # -"_ comment. Example: + + <C-e> = :encrypt<Enter> # - + *[terminal]* keybindings for terminal tabs @@ -108,7 +115,7 @@ ``` [compose::review] a = :attach<space> -d = :deatch<space> +d = :detach<space> [compose::review:account=no-attachments] a = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-config.5.scd new/aerc-0.20.0/doc/aerc-config.5.scd --- old/aerc-0.19.0/doc/aerc-config.5.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-config.5.scd 2025-01-25 21:55:48.000000000 +0100 @@ -207,7 +207,7 @@ *message-view-this-week-time-format* = _<timeformat>_ If set, overrides *timestamp-format* in the message view for messages - that were recieved/sent within the last 7 days. + that were received/sent within the last 7 days. *message-view-this-year-time-format* = _<timeformat>_ If set, overrides *timestamp-format* in the message view for messages @@ -910,7 +910,7 @@ *file-picker-cmd* = _<command>_ Specifies the command to be used to select attachments. Any occurrence of _%s_ in the *file-picker-cmd* will be replaced with the argument _<arg>_ - to *:attach -m* _<arg>_. Any occurence of _%f_ will be replaced by the + to *:attach -m* _<arg>_. Any occurrence of _%f_ will be replaced by the location of a temporary file, from which aerc will read the selected files. If _%f_ is not present, the command must output the selected files to diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-patch.7.scd new/aerc-0.20.0/doc/aerc-patch.7.scd --- old/aerc-0.19.0/doc/aerc-patch.7.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-patch.7.scd 2025-01-25 21:55:48.000000000 +0100 @@ -43,7 +43,7 @@ Completions for the _<tag>_ are available based on the subject lines of the selected or marked messages. - *-c* _<cmd>_: Apply patches with the provided _<cmd>_. Any occurence of + *-c* _<cmd>_: Apply patches with the provided _<cmd>_. Any occurrence of '%r' in the command string will be replaced with the root directory of the current project. Note that this approach is not recommended in general and should only be used for very specific purposes, i.e. when diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-stylesets.7.scd new/aerc-0.20.0/doc/aerc-stylesets.7.scd --- old/aerc-0.19.0/doc/aerc-stylesets.7.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-stylesets.7.scd 2025-01-25 21:55:48.000000000 +0100 @@ -313,7 +313,8 @@ *msglist_<name>*._<header>_,_<header_value>_.*<attribute>* = _<attr_value>_ If _<header_value>_ starts with a tilde character _~_, it will be interpreted as -a regular expression. +a regular expression. If you are writing regular expressions that try to match +with _._ or _\._ you need to wrap like this _~/<expression>/_. _<header>,<header_value>_ can be specified multiple times to narrow down matches to more than one email header value. In that case, all given headers must match @@ -328,6 +329,7 @@ "msglist_*.Subject,~^(\\[[\w-]+\]\\s*)?\\[(RFC )?PATCH.fg" = #ffffaf "msglist_*.Subject,~^(\\[[\w-]+\]\\s*)?\\[(RFC )?PATCH.selected.fg" = #ffffaf "msglist_*.From,~^Bob.Subject,~^(\\[[\w-]+\]\\s*)?\\[(RFC )?PATCH.selected.fg" = #ffffaf +"msglist_*.List-ID,~/lists\.sr\.ht/selected.fg" = blue ``` When a dynamic style is matched to an email header, it will be used in priority @@ -378,12 +380,15 @@ *.selected.fg = 15 *.selected.bold = true statusline_*.dim = true -statusline_*.bg = 8 -statusline_*.fg = 15 -*warning.fg = 3 -*success.fg = 2 -*error.fg = 1 +*warning.dim = false +*warning.bold = true +*warning.fg = 11 +*success.dim = false +*success.bold = true +*success.fg = 10 +*error.dim = false *error.bold = true +*error.fg = 9 border.bg = 12 border.fg = 15 title.bg = 12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc-templates.7.scd new/aerc-0.20.0/doc/aerc-templates.7.scd --- old/aerc-0.19.0/doc/aerc-templates.7.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc-templates.7.scd 2025-01-25 21:55:48.000000000 +0100 @@ -159,7 +159,7 @@ {{.Header "x-foo-bar"}} ``` - Any header values of the original forwared or replied message: + Any header values of the original forwarded or replied message: ``` {{.OriginalHeader "x-foo-bar"}} @@ -557,7 +557,7 @@ ``` *switch* - Do swich/case/default control flows. The switch value is compared with + Do switch/case/default control flows. The switch value is compared with regular expressions. If none of the case/default arms match, an empty string is returned. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/doc/aerc.1.scd new/aerc-0.20.0/doc/aerc.1.scd --- old/aerc-0.19.0/doc/aerc.1.scd 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/doc/aerc.1.scd 2025-01-25 21:55:48.000000000 +0100 @@ -175,7 +175,7 @@ Send keystrokes to the currently visible terminal, if any. Can be used to control embedded editors to save drafts or quit in a safe manner. - Here's an example of quiting a Vim-like editor: + Here's an example of quitting a Vim-like editor: *:send-keys* _<Esc>:wq!<Enter>_ @@ -317,7 +317,7 @@ The *-m* option sets the multi-file strategy. See *aerc-notmuch*(5) for more details. -*:accept* [*-e*|*-E*|*-s*] +*:accept* [*-e*|*-E*] [*-s*] Accepts an iCalendar meeting invitation. This opens a compose window with a specially crafted attachment. Sending the email will let the inviter know that you accepted and will likely update their calendar as @@ -331,7 +331,7 @@ *-s*: Skips the editor and goes directly to the review screen. -*:accept-tentative* [*-e*|*-E*] +*:accept-tentative* [*-e*|*-E*] [*-s*] Accepts an iCalendar meeting invitation tentatively. *-e*: Forces *[compose].edit-headers* = _true_ for this message only. @@ -353,7 +353,7 @@ *-m*: Set the multi-file strategy. See *aerc-notmuch*(5) for more details. -*:decline* [*-e*|*-E*] +*:decline* [*-e*|*-E*] [*-s*] Declines an iCalendar meeting invitation. *-e*: Forces *[compose].edit-headers* = _true_ for this message only. @@ -377,7 +377,7 @@ User-defined format specifier requiring two _%s_ for the key and value strings. Default format: _%-20.20s: %s_ -*:recall* [*-f*] [*-e*|*-E*] +*:recall* [*-f*] [*-e*|*-E*] [*-s*] Opens the selected message for re-editing. Messages can only be recalled from the postpone directory. @@ -389,12 +389,14 @@ *-E*: Forces *[compose].edit-headers* = _false_ for this message only. + *-s*: Skips the editor and goes directly to the review screen. + Original recalled messages are deleted if they are sent or postponed again. In both cases you have another copy of the message somewhere. Otherwise the recalled message is left intact. This happens if the recalled message is discarded after editing. It can be deleted with *:rm* if it is not needed. -*:forward* [*-A*|*-F*] [*-T* _<template-file>_] [*-e*|*-E*] [_<address>_...] +*:forward* [*-A*|*-F*] [*-T* _<template-file>_] [*-e*|*-E*] [*-s*] [_<address>_...] Opens the composer to forward the selected message to another recipient. *-A*: Forward the message and all attachments. @@ -411,6 +413,8 @@ *-E*: Forces *[compose].edit-headers* = _false_ for this message only. + *-s*: Skips the editor and goes directly to the review screen. + *:move* [*-p*] [*-a* _<account>_] [*-m* _<strategy>_] _<folder>_++ *:mv* [*-p*] [*-a* _<account>_] [*-m* _<strategy>_] _<folder>_ Moves the selected message(s) to _<folder>_. @@ -452,7 +456,7 @@ _[PATCH X/Y]_), all marked messages will be sorted by subject to ensure that the patches are applied in order. -*:reply* [*-acfq*] [*-T* _<template-file>_] [*-A* _<account>_] [*-e*|*-E*] +*:reply* [*-acfqs*] [*-T* _<template-file>_] [*-A* _<account>_] [*-e*|*-E*] Opens the composer to reply to the selected message. *-a*: Reply all @@ -466,6 +470,8 @@ editor. This defaults to what is set as *quoted-reply* in the *[templates]* section of _aerc.conf_. + *-s*: Skip opening the text editor and go directly to the review screen. + *-T* _<template-file>_ Use the specified template file for creating the initial message body. @@ -521,7 +527,7 @@ *:modify-labels* _+inbox_ _-spam_ _unread_ -*:unsubscribe* [*-e*|*-E*] +*:unsubscribe* [*-e*|*-E*] [*-s*] Attempt to automatically unsubscribe the user from the mailing list through use of the List-Unsubscribe header. If supported, aerc may open a compose window pre-filled with the unsubscribe information or open the unsubscribe @@ -531,6 +537,8 @@ *-E*: Forces *[compose].edit-headers* = _false_ for this message only. + *-s*: Skips the editor and goes directly to the review screen. + ## MESSAGE LIST COMMANDS *:align* _top|center|bottom_ @@ -565,7 +573,7 @@ check-mail-cmd to be set in order for aerc to initiate a check for new mail. Issuing a manual *:check-mail* command will reset the timer for automatic checking. -*:compose* [*-H* _"<header>: <value>"_] [*-T* _<template-file>_] [*-e*|*-E*] [_<body>_] +*:compose* [*-H* _"<header>: <value>"_] [*-T* _<template-file>_] [*-e*|*-E*] [*-s*] [_<body>_] Open the compose window to send a new email. The new email will be sent with the current account's outgoing transport configuration. For details on configuring outgoing mail delivery consult *aerc-accounts*(5). @@ -583,6 +591,8 @@ *-E*: Forces *[compose].edit-headers* = _false_ for this message only. + *-s*: Skips the editor and goes directly to the review screen. + _<body>_: The initial message body. *:bounce* [*-A* _<account>_] _<address>_ [_<address>_...]++ @@ -803,7 +813,7 @@ Subsequent args are passed to that program. - _{}_ will be expanded as the temporary filename to be opened. If it is not encountered in the arguments, the temporary filename will be - appened to the end of the command. + appended to the end of the command. *:open-link* _<url>_ [_<args...>_] Open the specified URL with an external program. The opening logic is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/filters/wrap.c new/aerc-0.20.0/filters/wrap.c --- old/aerc-0.19.0/filters/wrap.c 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/filters/wrap.c 2025-01-25 21:55:48.000000000 +0100 @@ -30,7 +30,7 @@ puts(" -w INT preferred wrap margin (default 80)"); puts(" -r reflow all paragraphs even if no trailing space"); puts(" -l INT minimum percentage of letters in a line to be"); - puts(" considered a paragaph"); + puts(" considered a paragraph"); puts(" -f FILE read from filename (default stdin)"); } @@ -383,7 +383,7 @@ /* * BUFSIZ has different values depending on the libc implementation. - * Use a self defined value to have consistent behaviour accross all platforms. + * Use a self defined value to have consistent behaviour across all platforms. */ #define BUFFER_SIZE 8192 @@ -495,7 +495,7 @@ if (!locale) { /* Neither LC_ALL nor LANG env vars are defined or are set to - * a non existant/installed locale. Try with a generic UTF-8 + * a non existent/installed locale. Try with a generic UTF-8 * locale which is expected to be available on all POSIX * systems. */ locale = setlocale(LC_ALL, "C.UTF-8"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/ipc/message.go new/aerc-0.20.0/lib/ipc/message.go --- old/aerc-0.19.0/lib/ipc/message.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/ipc/message.go 2025-01-25 21:55:48.000000000 +0100 @@ -2,7 +2,7 @@ import "encoding/json" -// Request constains all parameters needed for the main instance to respond to +// Request contains all parameters needed for the main instance to respond to // a request. type Request struct { // Arguments contains the commandline arguments. The detection of what diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/iterator/index.go new/aerc-0.20.0/lib/iterator/index.go --- old/aerc-0.19.0/lib/iterator/index.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/iterator/index.go 2025-01-25 21:55:48.000000000 +0100 @@ -1,6 +1,6 @@ package iterator -// IndexProvider implements a subset of the Interator interface +// IndexProvider implements a subset of the Iterator interface type IndexProvider interface { StartIndex() int EndIndex() int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/iterator/iterator_test.go new/aerc-0.20.0/lib/iterator/iterator_test.go --- old/aerc-0.19.0/lib/iterator/iterator_test.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/iterator/iterator_test.go 2025-01-25 21:55:48.000000000 +0100 @@ -55,18 +55,18 @@ got = append(got, iter.Value().(models.UID)) } if len(got) != len(want) { - t.Errorf(label + "number of elements not correct") + t.Errorf("%s: number of elements not correct", label) } for i, u := range want { if got[i] != u { - t.Errorf(label + "order not correct") + t.Errorf("%s: order not correct", label) } } if iter.StartIndex() != start { - t.Errorf(label + "start index not correct") + t.Errorf("%s: start index not correct", label) } if iter.EndIndex() != end { - t.Errorf(label + "end index not correct") + t.Errorf("%s: end index not correct", label) } } @@ -80,17 +80,17 @@ got = append(got, iter.Value().(*types.Thread)) } if len(got) != len(want) { - t.Errorf(label + "number of elements not correct") + t.Errorf("%s: number of elements not correct", label) } for i, th := range want { if got[i].Uid != th.Uid { - t.Errorf(label + "order not correct") + t.Errorf("%s: order not correct", label) } } if iter.StartIndex() != start { - t.Errorf(label + "start index not correct") + t.Errorf("%s: start index not correct", label) } if iter.EndIndex() != end { - t.Errorf(label + "end index not correct") + t.Errorf("%s: end index not correct", label) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/marker/marker.go new/aerc-0.20.0/lib/marker/marker.go --- old/aerc-0.19.0/lib/marker/marker.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/marker/marker.go 2025-01-25 21:55:48.000000000 +0100 @@ -40,7 +40,7 @@ } } -// Mark markes the uid as marked +// Mark marks the uid as marked func (mc *controller) Mark(uid models.UID) { if mc.visualMarkMode { // visual mode has override, bogus input from user diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/msgstore.go new/aerc-0.20.0/lib/msgstore.go --- old/aerc-0.19.0/lib/msgstore.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/msgstore.go 2025-01-25 21:55:48.000000000 +0100 @@ -309,6 +309,7 @@ store.Messages = newMap update = true + store.directoryContentsLoaded = true case *types.MessageInfo: infoUpdated := msg.Info.Envelope != nil || msg.Info.Error != nil if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/pama/init.go new/aerc-0.20.0/lib/pama/init.go --- old/aerc-0.19.0/lib/pama/init.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/pama/init.go 2025-01-25 21:55:48.000000000 +0100 @@ -4,7 +4,7 @@ "git.sr.ht/~rjarry/aerc/lib/pama/models" ) -// Init creats a new revision control project +// Init creates a new revision control project func (m PatchManager) Init(name, path string, overwrite bool) error { id, root, err := m.detect(path) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/pama/models/models.go new/aerc-0.20.0/lib/pama/models/models.go --- old/aerc-0.19.0/lib/pama/models/models.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/pama/models/models.go 2025-01-25 21:55:48.000000000 +0100 @@ -76,7 +76,7 @@ // ApplyCmd returns a string with an executable command that is used to // apply patches with the :pipe command. ApplyCmd() string - // CreateWorktree creats a worktree in path at commit. + // CreateWorktree creates a worktree in path at commit. CreateWorktree(path string, commit string) error // DeleteWorktree removes the linked worktree stored in the path // location. Note that this function should be called from the base diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/pama/pama_test.go new/aerc-0.20.0/lib/pama/pama_test.go --- old/aerc-0.19.0/lib/pama/pama_test.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/pama/pama_test.go 2025-01-25 21:55:48.000000000 +0100 @@ -133,7 +133,7 @@ func (s *mockStore) StoreProject(p models.Project, ow bool) error { _, ok := s.data[p.Name] if ok && !ow { - return errors.New("alreay there") + return errors.New("already there") } s.data[p.Name] = p return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/pama/store/store.go new/aerc-0.20.0/lib/pama/store/store.go --- old/aerc-0.19.0/lib/pama/store/store.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/pama/store/store.go 2025-01-25 21:55:48.000000000 +0100 @@ -19,7 +19,7 @@ ) var ( - // versTag should be incremented when the underyling data structure + // versTag should be incremented when the underlying data structure // changes. versTag = []byte("0001") versTagKey = []byte("version.tag") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/rfc822/message.go new/aerc-0.20.0/lib/rfc822/message.go --- old/aerc-0.19.0/lib/rfc822/message.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/rfc822/message.go 2025-01-25 21:55:48.000000000 +0100 @@ -174,7 +174,7 @@ return &body, nil } -// CreateTextPlainBody creats a plain-vanilla text/plain body structure. +// CreateTextPlainBody creates a plain-vanilla text/plain body structure. func CreateTextPlainBody() *models.BodyStructure { body := &models.BodyStructure{} body.MIMEType = "text" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/ui/context.go new/aerc-0.20.0/lib/ui/context.go --- old/aerc-0.19.0/lib/ui/context.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/ui/context.go 2025-01-25 21:55:48.000000000 +0100 @@ -38,7 +38,7 @@ panic(fmt.Errorf("Attempted to create context with negative offset")) } win := ctx.window.New(x, y, width, height) - return &Context{win, x, y, ctx.onPopover} + return &Context{win, ctx.x + x, ctx.y + y, ctx.onPopover} } func (ctx *Context) SetCell(x, y int, ch rune, style vaxis.Style) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/ui/grid.go new/aerc-0.20.0/lib/ui/grid.go --- old/aerc-0.19.0/lib/ui/grid.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/ui/grid.go 2025-01-25 21:55:48.000000000 +0100 @@ -30,7 +30,7 @@ // If Strategy = SIZE_EXACT, this function returns the number of cells // this row/col shall occupy. If SIZE_WEIGHT, the space left after all - // exact rows/cols are measured is distributed amonst the remainder + // exact rows/cols are measured is distributed amongst the remainder // weighted by the value returned by this function. Size func() int } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/lib/ui/ui.go new/aerc-0.20.0/lib/ui/ui.go --- old/aerc-0.19.0/lib/ui/ui.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/lib/ui/ui.go 2025-01-25 21:55:48.000000000 +0100 @@ -171,7 +171,7 @@ Invalidate() default: // We never care about num or caps lock. Remove them so it - // doesn't interefere with key matching + // doesn't interfere with key matching if key, ok := event.(vaxis.Key); ok { key.Modifiers &^= vaxis.ModCapsLock key.Modifiers &^= vaxis.ModNumLock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/stylesets/default new/aerc-0.20.0/stylesets/default --- old/aerc-0.19.0/stylesets/default 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/stylesets/default 2025-01-25 21:55:48.000000000 +0100 @@ -17,13 +17,16 @@ #*.selected.bold = true #statusline_*.dim = true -#statusline_*.bg = 8 -#statusline_*.fg = 15 -#*warning.fg = 3 -#*success.fg = 2 -#*error.fg = 1 +#*warning.dim = false +#*warning.bold = true +#*warning.fg = 11 +#*success.dim = false +#*success.bold = true +#*success.fg = 10 +#*error.dim = false #*error.bold = true +#*error.fg = 9 #border.fg = 12 #border.bold = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/worker/imap/connect.go new/aerc-0.20.0/worker/imap/connect.go --- old/aerc-0.19.0/worker/imap/connect.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/worker/imap/connect.go 2025-01-25 21:55:48.000000000 +0100 @@ -10,6 +10,7 @@ "git.sr.ht/~rjarry/aerc/lib/log" "github.com/emersion/go-imap" "github.com/emersion/go-imap/client" + "github.com/emersion/go-sasl" ) // connect establishes a new tcp connection to the imap server, logs in and @@ -88,6 +89,13 @@ username, password, w.config.name, c); err != nil { return nil, err } + } else if plain, err := c.SupportAuth("PLAIN"); err != nil { + return nil, err + } else if plain { + auth := sasl.NewPlainClient("", username, password) + if err := c.Authenticate(auth); err != nil { + return nil, err + } } else if err := c.Login(username, password); err != nil { return nil, err } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/worker/imap/extensions/xgmext/client.go new/aerc-0.20.0/worker/imap/extensions/xgmext/client.go --- old/aerc-0.19.0/worker/imap/extensions/xgmext/client.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/worker/imap/extensions/xgmext/client.go 2025-01-25 21:55:48.000000000 +0100 @@ -24,12 +24,12 @@ threadIds, err := h.fetchThreadIds(requested) if err != nil { return nil, - fmt.Errorf("faild to fetch thread IDs: %w", err) + fmt.Errorf("failed to fetch thread IDs: %w", err) } uids, err := h.searchUids(threadIds) if err != nil { return nil, - fmt.Errorf("faild to search for thread IDs: %w", err) + fmt.Errorf("failed to search for thread IDs: %w", err) } return uids, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aerc-0.19.0/worker/jmap/set.go new/aerc-0.20.0/worker/jmap/set.go --- old/aerc-0.19.0/worker/jmap/set.go 2025-01-14 23:05:09.000000000 +0100 +++ new/aerc-0.20.0/worker/jmap/set.go 2025-01-25 21:55:48.000000000 +0100 @@ -172,14 +172,14 @@ for _, a := range msg.Add { mboxId, ok := w.dir2mbox[a] if !ok { - return fmt.Errorf("unkown label: %q", a) + return fmt.Errorf("unknown label: %q", a) } patch[w.mboxPatch(mboxId)] = true } for _, r := range msg.Remove { mboxId, ok := w.dir2mbox[r] if !ok { - return fmt.Errorf("unkown label: %q", r) + return fmt.Errorf("unknown label: %q", r) } patch[w.mboxPatch(mboxId)] = nil } ++++++ vendor.tar.zst ++++++