~sircmpwn/aerc

Abort composer on editor non-zero exit status v1 PROPOSED

Daniel Bridges
Daniel Bridges: 1
 Abort composer on editor non-zero exit status

 8 files changed, 68 insertions(+), 37 deletions(-)
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/~sircmpwn/aerc/patches/7500/mbox | git am -3
Learn more about email & git

[PATCH] Abort composer on editor non-zero exit status Export this patch

Daniel Bridges
---
I talked to Kevin about this, he wasn't going to be able to work on it
in the near term, and I had already done some work duplicate work
without realizing it. As always, open to suggestions.

 commands/account/compose.go | 10 +---------
 commands/compose/abort.go   |  1 -
 commands/msg/reply.go       | 10 +---------
 commands/msg/unsubscribe.go | 10 +---------
 lib/observer.go             | 27 +++++++++++++++++++++++++++
 widgets/aerc.go             | 26 +++++++++++++++++---------
 widgets/compose.go          | 17 +++++++++++++++++
 widgets/terminal.go         |  4 ++++
 8 files changed, 68 insertions(+), 37 deletions(-)
 create mode 100644 lib/observer.go

diff --git a/commands/account/compose.go b/commands/account/compose.go
index a4836b7..ee7ec16 100644
--- a/commands/account/compose.go
+++ b/commands/account/compose.go
@@ -31,15 +31,7 @@ func (_ Compose) Execute(aerc *widgets.Aerc, args []string) error {
	acct := aerc.SelectedAccount()
	composer := widgets.NewComposer(
		aerc.Config(), acct.AccountConfig(), acct.Worker(), nil)
	tab := aerc.NewTab(composer, "New email")
	composer.OnHeaderChange("Subject", func(subject string) {
		if subject == "" {
			tab.Name = "New email"
		} else {
			tab.Name = subject
		}
		tab.Content.Invalidate()
	})
	aerc.NewComposerTab(composer, "New email")
	go composer.SetContents(strings.NewReader(body))
	return nil
}
diff --git a/commands/compose/abort.go b/commands/compose/abort.go
index 4c121d7..f3ae113 100644
--- a/commands/compose/abort.go
+++ b/commands/compose/abort.go
@@ -26,7 +26,6 @@ func (_ Abort) Execute(aerc *widgets.Aerc, args []string) error {
	}
	composer, _ := aerc.SelectedTab().(*widgets.Composer)

	aerc.RemoveTab(composer)
	composer.Close()

	return nil
diff --git a/commands/msg/reply.go b/commands/msg/reply.go
index 029cb42..4aef0b7 100644
--- a/commands/msg/reply.go
+++ b/commands/msg/reply.go
@@ -128,15 +128,7 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
	}

	addTab := func() {
		tab := aerc.NewTab(composer, subject)
		composer.OnHeaderChange("Subject", func(subject string) {
			if subject == "" {
				tab.Name = "New email"
			} else {
				tab.Name = subject
			}
			tab.Content.Invalidate()
		})
		aerc.NewComposerTab(composer, subject)
	}

	if args[0] == "forward" {
diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go
index f18da07..50e1889 100644
--- a/commands/msg/unsubscribe.go
+++ b/commands/msg/unsubscribe.go
@@ -94,15 +94,7 @@ func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
		defaults,
	)
	composer.SetContents(strings.NewReader(u.Query().Get("body")))
	tab := aerc.NewTab(composer, "unsubscribe")
	composer.OnHeaderChange("Subject", func(subject string) {
		if subject == "" {
			tab.Name = "unsubscribe"
		} else {
			tab.Name = subject
		}
		tab.Content.Invalidate()
	})
	aerc.NewComposerTab(composer, "unsubscribe")
	return nil
}

diff --git a/lib/observer.go b/lib/observer.go
new file mode 100644
index 0000000..685f2e5
--- /dev/null
+++ b/lib/observer.go
@@ -0,0 +1,27 @@
package lib

type Observer struct {
	callbacks map[int][]func()
}

func NewObserver() *Observer {
	return &Observer{
		callbacks: make(map[int][]func()),
	}
}

func (o *Observer) Register(eventType int, fn func()) {
	if cbs, ok := o.callbacks[eventType]; ok {
		o.callbacks[eventType] = append(cbs, fn)
	} else {
		o.callbacks[eventType] = []func(){fn}
	}
}

func (o *Observer) Emit(eventType int) {
	if cbs, ok := o.callbacks[eventType]; ok {
		for _, cb := range cbs {
			cb()
		}
	}
}
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 5a7914a..9b38a12 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -250,6 +250,22 @@ func (aerc *Aerc) NewTab(drawable ui.Drawable, name string) *ui.Tab {
	return tab
}

func (aerc *Aerc) NewComposerTab(composer *Composer, title string) *ui.Tab {
	tab := aerc.NewTab(composer, title)
	composer.OnHeaderChange("Subject", func(subject string) {
		if subject == "" {
			tab.Name = title
		} else {
			tab.Name = subject
		}
		tab.Content.Invalidate()
	})
	composer.OnClose(func() {
		aerc.RemoveTab(composer)
	})
	return tab
}

func (aerc *Aerc) RemoveTab(tab ui.Drawable) {
	aerc.tabs.Remove(tab)
}
@@ -395,15 +411,7 @@ func (aerc *Aerc) Mailto(addr *url.URL) error {
		title = subj
		composer.FocusTerminal()
	}
	tab := aerc.NewTab(composer, title)
	composer.OnHeaderChange("Subject", func(subject string) {
		if subject == "" {
			tab.Name = "New email"
		} else {
			tab.Name = subject
		}
		tab.Content.Invalidate()
	})
	aerc.NewComposerTab(composer, title)
	return nil
}

diff --git a/widgets/compose.go b/widgets/compose.go
index c7e38b8..310aadc 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -20,10 +20,15 @@ import (
	"github.com/pkg/errors"

	"git.sr.ht/~sircmpwn/aerc/config"
	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/lib/ui"
	"git.sr.ht/~sircmpwn/aerc/worker/types"
)

const (
	ON_CLOSE = iota
)

type Composer struct {
	editors map[string]*headerEditor

@@ -38,6 +43,7 @@ type Composer struct {
	header      *ui.Grid
	review      *reviewMessage
	worker      *types.Worker
	observer    *lib.Observer

	layout    HeaderLayout
	focusable []ui.DrawableInteractive
@@ -74,6 +80,7 @@ func NewComposer(conf *config.AercConfig,
		// You have to backtab to get to "From", since you usually don't edit it
		focused:   1,
		focusable: focusable,
		observer:  lib.NewObserver(),
	}

	c.updateGrid()
@@ -162,6 +169,10 @@ func (c *Composer) OnHeaderChange(header string, fn func(subject string)) {
	}
}

func (c *Composer) OnClose(fn func()) {
	c.observer.Register(ON_CLOSE, fn)
}

func (c *Composer) Draw(ctx *ui.Context) {
	c.grid.Draw(ctx)
}
@@ -187,6 +198,7 @@ func (c *Composer) Close() {
		c.editor.Destroy()
		c.editor = nil
	}
	c.observer.Emit(ON_CLOSE)
}

func (c *Composer) Bindings() string {
@@ -462,6 +474,11 @@ func (c *Composer) resetReview() {
}

func (c *Composer) termClosed(err error) {
	if _, ok := err.(*exec.ExitError); ok {
		// editor exit code not 0, aborting
		c.Close()
		return
	}
	c.grid.RemoveChild(c.editor)
	c.review = newReviewMessage(c, err)
	c.grid.AddChild(c.review).At(1, 0)
diff --git a/widgets/terminal.go b/widgets/terminal.go
index 008a36f..0b2fec0 100644
--- a/widgets/terminal.go
+++ b/widgets/terminal.go
@@ -180,6 +180,10 @@ func (term *Terminal) Close(err error) {
	}
	if term.cmd != nil && term.cmd.Process != nil {
		term.cmd.Process.Kill()
		if err == nil {
			err = term.cmd.Wait()
			term.err = err
		}
		term.cmd = nil
	}
	if !term.closed && term.OnClose != nil {
-- 
2.20.1
Can you introduce this "Observer" idea in a separate commit?
View this thread in the archives