~rjarry/aerc-devel

aerc: composer: add focus-body option v3 SUPERSEDED

Markus Unkel: 1
 composer: add focus-body option
Robin Jarry: 1
 composer: add focus-body option

 16 files changed, 49 insertions(+), 14 deletions(-)
#1366043 alpine-edge.yml success
#1366044 openbsd.yml success
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/55893/mbox | git am -3
Learn more about email & git

[PATCH aerc v3] composer: add focus-body option Export this patch

When the composer window opens, an user might want to start writing
the email body before adding a subject and recipients. Setting the
focus-body option to true achieves that by setting the focus to the
editor.

Signed-off-by: Markus Unkel <markus@unkel.io>
---
Thanks for reviewing the design of the [compose].focus-body option to
Koni and Robin by agreeing on not introducing focusBody flags on message
commands.
 app/aerc.go                 | 4 ++--
 app/compose.go              | 9 ++++++---
 commands/account/compose.go | 3 ++-
 commands/account/recover.go | 3 ++-
 commands/msg/forward.go     | 3 ++-
 commands/msg/invite.go      | 3 ++-
 commands/msg/recall.go      | 3 ++-
 commands/msg/reply.go       | 3 ++-
 commands/msg/unsubscribe.go | 6 ++++--
 config/aerc.conf            | 6 ++++++
 config/compose.go           | 1 +
 doc/aerc-config.5.scd       | 5 +++++
 12 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/app/aerc.go b/app/aerc.go
index 12bb6893..650252ee 100644
--- a/app/aerc.go
+++ b/app/aerc.go
@@ -799,8 +799,8 @@ func (aerc *Aerc) mailto(addr *url.URL) error {

	composer, err := NewComposer(acct,
		acct.AccountConfig(), acct.Worker(),
		config.Compose.EditHeaders, template, h, nil,
		strings.NewReader(body))
		config.Compose.EditHeaders, config.Compose.FocusBody,
		template, h, nil, strings.NewReader(body))
	if err != nil {
		return err
	}
diff --git a/app/compose.go b/app/compose.go
index 7a581505..a31a1061 100644
--- a/app/compose.go
+++ b/app/compose.go
@@ -59,6 +59,7 @@ type Composer struct {
	encrypt     bool
	attachKey   bool
	editHeaders bool
	focusBody   bool

	layout    HeaderLayout
	focusable []ui.MouseableDrawableInteractive
@@ -79,8 +80,9 @@ type Composer struct {

func NewComposer(
	acct *AccountView, acctConfig *config.AccountConfig,
	worker *types.Worker, editHeaders bool, template string,
	h *mail.Header, orig *models.OriginalMail, body io.Reader,
	worker *types.Worker, editHeaders bool, focusBody bool,
	template string, h *mail.Header, orig *models.OriginalMail,
	body io.Reader,
) (*Composer, error) {
	if h == nil {
		h = new(mail.Header)
@@ -105,6 +107,7 @@ func NewComposer(
		completer: nil,

		editHeaders: editHeaders,
		focusBody:   focusBody,
	}

	data := state.NewDataSetter()
@@ -1276,7 +1279,7 @@ func (c *Composer) showTerminal() error {
	c.focusable = append(c.focusable, c.editor)
	c.review = nil
	c.updateGrid()
	if c.editHeaders {
	if c.editHeaders || c.focusBody {
		c.focusTerminalPriv()
	}
	return nil
diff --git a/commands/account/compose.go b/commands/account/compose.go
index 5e5d3e0f..9ae17640 100644
--- a/commands/account/compose.go
+++ b/commands/account/compose.go
@@ -66,6 +66,7 @@ func (c Compose) Execute(args []string) error {
		c.Template = config.Templates.NewMessage
	}
	editHeaders := (config.Compose.EditHeaders || c.Edit) && !c.NoEdit
	focusBody := config.Compose.FocusBody

	acct := app.SelectedAccount()
	if acct == nil {
@@ -82,7 +83,7 @@ func (c Compose) Execute(args []string) error {

	composer, err := app.NewComposer(acct,
		acct.AccountConfig(), acct.Worker(), editHeaders,
		c.Template, &headers, nil, msg.Body)
		focusBody, c.Template, &headers, nil, msg.Body)
	if err != nil {
		return err
	}
diff --git a/commands/account/recover.go b/commands/account/recover.go
index 7f5b27f5..584cf6f2 100644
--- a/commands/account/recover.go
+++ b/commands/account/recover.go
@@ -67,10 +67,11 @@ func (r Recover) Execute(args []string) error {
	}

	editHeaders := (config.Compose.EditHeaders || r.Edit) && !r.NoEdit
	focusBody := config.Compose.FocusBody

	composer, err := app.NewComposer(acct,
		acct.AccountConfig(), acct.Worker(), editHeaders,
		"", nil, nil, bytes.NewReader(data))
		focusBody, "", nil, nil, bytes.NewReader(data))
	if err != nil {
		return err
	}
diff --git a/commands/msg/forward.go b/commands/msg/forward.go
index ce5f75f0..79982ab9 100644
--- a/commands/msg/forward.go
+++ b/commands/msg/forward.go
@@ -62,6 +62,7 @@ func (f forward) Execute(args []string) error {
		return errors.New("Options -A and -F are mutually exclusive")
	}
	editHeaders := (config.Compose.EditHeaders || f.Edit) && !f.NoEdit
	focusBody := config.Compose.FocusBody

	widget := app.SelectedTabContent().(app.ProvidesMessage)
	acct := widget.SelectedAccount()
@@ -99,7 +100,7 @@ func (f forward) Execute(args []string) error {
	addTab := func() (*app.Composer, error) {
		composer, err := app.NewComposer(acct,
			acct.AccountConfig(), acct.Worker(), editHeaders,
			f.Template, h, &original, nil)
			focusBody, f.Template, h, &original, nil)
		if err != nil {
			app.PushError("Error: " + err.Error())
			return nil, err
diff --git a/commands/msg/invite.go b/commands/msg/invite.go
index 36add098..785d5d2f 100644
--- a/commands/msg/invite.go
+++ b/commands/msg/invite.go
@@ -59,6 +59,7 @@ func (i invite) Execute(args []string) error {
	}

	editHeaders := (config.Compose.EditHeaders || i.Edit) && !i.NoEdit
	focusBody := config.Compose.FocusBody

	subject := trimLocalizedRe(msg.Envelope.Subject, acct.AccountConfig().LocalizedRe)
	switch args[0] {
@@ -132,7 +133,7 @@ func (i invite) Execute(args []string) error {
	addTab := func(cr *calendar.Reply) error {
		composer, err := app.NewComposer(acct,
			acct.AccountConfig(), acct.Worker(), editHeaders,
			"", h, &original, cr.PlainText)
			focusBody, "", h, &original, cr.PlainText)
		if err != nil {
			app.PushError("Error: " + err.Error())
			return err
diff --git a/commands/msg/recall.go b/commands/msg/recall.go
index 53a0de34..377d18e3 100644
--- a/commands/msg/recall.go
+++ b/commands/msg/recall.go
@@ -43,6 +43,7 @@ func (Recall) Aliases() []string {

func (r Recall) Execute(args []string) error {
	editHeaders := (config.Compose.EditHeaders || r.Edit) && !r.NoEdit
	focusBody := config.Compose.FocusBody

	widget := app.SelectedTabContent().(app.ProvidesMessage)
	acct := widget.SelectedAccount()
@@ -112,7 +113,7 @@ func (r Recall) Execute(args []string) error {
			msg.FetchBodyPart(path, func(reader io.Reader) {
				composer, err := app.NewComposer(acct,
					acct.AccountConfig(), acct.Worker(), editHeaders,
					"", msgInfo.RFC822Headers, nil, reader)
					focusBody, "", msgInfo.RFC822Headers, nil, reader)
				if err != nil {
					app.PushError(err.Error())
					return
diff --git a/commands/msg/reply.go b/commands/msg/reply.go
index 4cbd27c8..7d79becb 100644
--- a/commands/msg/reply.go
+++ b/commands/msg/reply.go
@@ -58,6 +58,7 @@ func (*reply) CompleteAccount(arg string) []string {

func (r reply) Execute(args []string) error {
	editHeaders := (config.Compose.EditHeaders || r.Edit) && !r.NoEdit
	focusBody := config.Compose.FocusBody

	widget := app.SelectedTabContent().(app.ProvidesMessage)

@@ -181,7 +182,7 @@ func (r reply) Execute(args []string) error {
	addTab := func() error {
		composer, err := app.NewComposer(acct,
			acct.AccountConfig(), acct.Worker(), editHeaders,
			r.Template, h, &original, nil)
			focusBody, r.Template, h, &original, nil)
		if err != nil {
			app.PushError("Error: " + err.Error())
			return err
diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go
index 57299aa8..6eb207e9 100644
--- a/commands/msg/unsubscribe.go
+++ b/commands/msg/unsubscribe.go
@@ -43,6 +43,7 @@ func (Unsubscribe) Aliases() []string {
// Execute runs the Unsubscribe command
func (u Unsubscribe) Execute(args []string) error {
	editHeaders := (config.Compose.EditHeaders || u.Edit) && !u.NoEdit
	focusBody := config.Compose.FocusBody

	widget := app.SelectedTabContent().(app.ProvidesMessage)
	msg, err := widget.SelectedMessage()
@@ -68,7 +69,7 @@ func (u Unsubscribe) Execute(args []string) error {
		var err error
		switch strings.ToLower(method.Scheme) {
		case "mailto":
			err = unsubscribeMailto(method, editHeaders)
			err = unsubscribeMailto(method, editHeaders, focusBody)
		case "http", "https":
			err = unsubscribeHTTP(method)
		default:
@@ -140,7 +141,7 @@ func parseUnsubscribeMethods(header string) (methods []*url.URL) {
	}
}

func unsubscribeMailto(u *url.URL, editHeaders bool) error {
func unsubscribeMailto(u *url.URL, editHeaders bool, focusBody bool) error {
	widget := app.SelectedTabContent().(app.ProvidesMessage)
	acct := widget.SelectedAccount()
	if acct == nil {
@@ -159,6 +160,7 @@ func unsubscribeMailto(u *url.URL, editHeaders bool) error {
		acct.AccountConfig(),
		acct.Worker(),
		editHeaders,
		focusBody,
		"",
		h,
		nil,
diff --git a/config/aerc.conf b/config/aerc.conf
index 4a83625a..9070bcf3 100644
--- a/config/aerc.conf
+++ b/config/aerc.conf
@@ -654,6 +654,12 @@
# Default: false
#edit-headers=false

#
# Sets focus to the email body when the composer window opens.
#
# Default: false
#focus-body=false

#
# Specifies the command to be used to tab-complete email addresses. Any
# occurrence of "%s" in the address-book-cmd will be replaced with what the
diff --git a/config/compose.go b/config/compose.go
index d6f25d31..4ed1f07d 100644
--- a/config/compose.go
+++ b/config/compose.go
@@ -17,6 +17,7 @@ type ComposeConfig struct {
	FilePickerCmd       string         `ini:"file-picker-cmd"`
	FormatFlowed        bool           `ini:"format-flowed"`
	EditHeaders         bool           `ini:"edit-headers"`
	FocusBody           bool           `ini:"focus-body" default:"false"`
	LFEditor            bool           `ini:"lf-editor"`
}

diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 80922fa1..56c4e209 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -883,6 +883,11 @@ These options are configured in the *[compose]* section of _aerc.conf_.

	Default: _false_

*focus-body* = _true_|_false_
	Sets focus to the email body when the composer window opens.

	Default: _false_

*address-book-cmd* = _<command>_
	Specifies the command to be used to tab-complete email addresses. Any
	occurrence of _%s_ in the *address-book-cmd* will be replaced with anything
-- 
2.47.0
aerc/patches: SUCCESS in 2m6s

[composer: add focus-body option][0] v3 from [Markus Unkel][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/55893
[1]: mailto:markus@unkel.io

✓ #1366044 SUCCESS aerc/patches/openbsd.yml     https://builds.sr.ht/~rjarry/job/1366044
✓ #1366043 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1366043

Re: [PATCH aerc v3] composer: add focus-body option Export this patch

Markus Unkel, Nov 09, 2024 at 19:35:
> When the composer window opens, an user might want to start writing
> the email body before adding a subject and recipients. Setting the
> focus-body option to true achieves that by setting the focus to the
> editor.
>
> Signed-off-by: Markus Unkel <markus@unkel.io>
> ---
> Thanks for reviewing the design of the [compose].focus-body option to
> Koni and Robin by agreeing on not introducing focusBody flags on message
> commands.

Thanks for v3 markus. Now that there is only the config option, the code 
can be greatly simplified.

The composer does not need any focusBody field. Here's what I would 
suggest:

diff --git a/app/compose.go b/app/compose.go
index 7a58150513c2..2cd7fd61b5f9 100644
--- a/app/compose.go
+++ b/app/compose.go
@@ -1276,7 +1276,7 @@ func (c *Composer) showTerminal() error {
	c.focusable = append(c.focusable, c.editor)
	c.review = nil
	c.updateGrid()
	if c.editHeaders {
	if c.editHeaders || config.Compose.FocusBody {
		c.focusTerminalPriv()
	}
	return nil
diff --git a/config/aerc.conf b/config/aerc.conf
index 4a83625aa8f9..9070bcf3f4a8 100644
--- a/config/aerc.conf
+++ b/config/aerc.conf
@@ -654,6 +654,12 @@
# Default: false
#edit-headers=false

#
# Sets focus to the email body when the composer window opens.
#
# Default: false
#focus-body=false

#
# Specifies the command to be used to tab-complete email addresses. Any
# occurrence of "%s" in the address-book-cmd will be replaced with what the
diff --git a/config/compose.go b/config/compose.go
index d6f25d314aeb..db963f56d8f0 100644
--- a/config/compose.go
+++ b/config/compose.go
@@ -17,6 +17,7 @@ type ComposeConfig struct {
	FilePickerCmd       string         `ini:"file-picker-cmd"`
	FormatFlowed        bool           `ini:"format-flowed"`
	EditHeaders         bool           `ini:"edit-headers"`
	FocusBody           bool           `ini:"focus-body"`
	LFEditor            bool           `ini:"lf-editor"`
}

diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 80922fa1c386..56c4e2099fa0 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -883,6 +883,11 @@ These options are configured in the *[compose]* section of _aerc.conf_.

	Default: _false_

*focus-body* = _true_|_false_
	Sets focus to the email body when the composer window opens.

	Default: _false_

*address-book-cmd* = _<command>_
	Specifies the command to be used to tab-complete email addresses. Any
	occurrence of _%s_ in the *address-book-cmd* will be replaced with anything
-- 
2.47.0