~sircmpwn/aerc

76a91813d8dc0f0011202f8120fc197097f022aa — Drew DeVault a month ago b9af9b5
Revert "Remove duration from the status methods"

This reverts commit f06d683688e3d2139b14f67b7e349089e7200bf4.
M commands/account/mkdir.go => commands/account/mkdir.go +3 -2
@@ 3,6 3,7 @@ package account
import (
	"errors"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/aerc/widgets"
	"git.sr.ht/~sircmpwn/aerc/worker/types"


@@ 36,10 37,10 @@ func (MakeDir) Execute(aerc *widgets.Aerc, args []string) error {
	}, func(msg types.WorkerMessage) {
		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus("Directory created.")
			aerc.PushStatus("Directory created.", 10*time.Second)
			acct.Directories().Select(name)
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
		}
	})
	return nil

M commands/account/view.go => commands/account/view.go +2 -1
@@ 2,6 2,7 @@ package account

import (
	"errors"
	"time"

	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 41,7 42,7 @@ func (ViewMessage) Execute(aerc *widgets.Aerc, args []string) error {
	lib.NewMessageStoreView(msg, store, aerc.DecryptKeys,
		func(view lib.MessageView, err error) {
			if err != nil {
				aerc.PushError(err.Error())
				aerc.PushError(err.Error(), 10*time.Second)
				return
			}
			viewer := widgets.NewMessageViewer(acct, aerc.Config(), view)

M commands/compose/attach.go => commands/compose/attach.go +5 -4
@@ 4,6 4,7 @@ import (
	"fmt"
	"os"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/aerc/commands"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 34,23 35,23 @@ func (Attach) Execute(aerc *widgets.Aerc, args []string) error {

	path, err := homedir.Expand(path)
	if err != nil {
		aerc.PushError(" " + err.Error())
		aerc.PushError(" "+err.Error(), 10*time.Second)
		return err
	}

	pathinfo, err := os.Stat(path)
	if err != nil {
		aerc.PushError(" " + err.Error())
		aerc.PushError(" "+err.Error(), 10*time.Second)
		return err
	} else if pathinfo.IsDir() {
		aerc.PushError("Attachment must be a file, not a directory")
		aerc.PushError("Attachment must be a file, not a directory", 10*time.Second)
		return nil
	}

	composer, _ := aerc.SelectedTab().(*widgets.Composer)
	composer.AddAttachment(path)

	aerc.PushSuccess(fmt.Sprintf("Attached %s", pathinfo.Name()))
	aerc.PushSuccess(fmt.Sprintf("Attached %s", pathinfo.Name()), 10*time.Second)

	return nil
}

M commands/compose/detach.go => commands/compose/detach.go +2 -1
@@ 3,6 3,7 @@ package compose
import (
	"fmt"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/aerc/widgets"
)


@@ 42,7 43,7 @@ func (Detach) Execute(aerc *widgets.Aerc, args []string) error {
		return err
	}

	aerc.PushSuccess(fmt.Sprintf("Detached %s", path))
	aerc.PushSuccess(fmt.Sprintf("Detached %s", path), 10*time.Second)

	return nil
}

M commands/compose/postpone.go => commands/compose/postpone.go +4 -4
@@ 63,7 63,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
	go func() {
		errStr := <-errChan
		if errStr != "" {
			aerc.PushError(" " + errStr)
			aerc.PushError(" "+errStr, 10*time.Second)
			return
		}



@@ 71,7 71,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
		ctr := datacounter.NewWriterCounter(ioutil.Discard)
		err = composer.WriteMessage(header, ctr)
		if err != nil {
			aerc.PushError(errors.Wrap(err, "WriteMessage").Error())
			aerc.PushError(errors.Wrap(err, "WriteMessage").Error(), 10*time.Second)
			composer.Close()
			return
		}


@@ 86,11 86,11 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
		}, func(msg types.WorkerMessage) {
			switch msg := msg.(type) {
			case *types.Done:
				aerc.PushStatus("Message postponed.")
				aerc.PushStatus("Message postponed.", 10*time.Second)
				r.Close()
				composer.Close()
			case *types.Error:
				aerc.PushError(" " + msg.Error.Error())
				aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
				r.Close()
				composer.Close()
			}

M commands/compose/send.go => commands/compose/send.go +5 -5
@@ 221,14 221,14 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
	}

	go func() {
		aerc.PushStatus("Sending...")
		aerc.PushStatus("Sending...", 10*time.Second)
		nbytes, err := sendAsync()
		if err != nil {
			aerc.SetError(" " + err.Error())
			return
		}
		if config.CopyTo != "" {
			aerc.PushStatus("Copying to " + config.CopyTo)
			aerc.PushStatus("Copying to "+config.CopyTo, 10*time.Second)
			worker := composer.Worker()
			r, w := io.Pipe()
			worker.PostAction(&types.AppendMessage{


@@ 240,12 240,12 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
			}, func(msg types.WorkerMessage) {
				switch msg := msg.(type) {
				case *types.Done:
					aerc.PushStatus("Message sent.")
					aerc.PushStatus("Message sent.", 10*time.Second)
					r.Close()
					composer.SetSent()
					composer.Close()
				case *types.Error:
					aerc.PushError(" " + msg.Error.Error())
					aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
					r.Close()
					composer.Close()
				}


@@ 254,7 254,7 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
			composer.WriteMessage(header, w)
			w.Close()
		} else {
			aerc.PushStatus("Message sent.")
			aerc.PushStatus("Message sent.", 10*time.Second)
			composer.SetSent()
			composer.Close()
		}

M commands/exec.go => commands/exec.go +4 -3
@@ 4,6 4,7 @@ import (
	"errors"
	"fmt"
	"os/exec"
	"time"

	"git.sr.ht/~sircmpwn/aerc/widgets"
)


@@ 30,16 31,16 @@ func (ExecCmd) Execute(aerc *widgets.Aerc, args []string) error {
	go func() {
		err := cmd.Run()
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		} else {
			if cmd.ProcessState.ExitCode() != 0 {
				aerc.PushError(fmt.Sprintf(
					"%s: completed with status %d", args[0],
					cmd.ProcessState.ExitCode()))
					cmd.ProcessState.ExitCode()), 10*time.Second)
			} else {
				aerc.PushStatus(fmt.Sprintf(
					"%s: completed with status %d", args[0],
					cmd.ProcessState.ExitCode()))
					cmd.ProcessState.ExitCode()), 10*time.Second)
			}
		}
	}()

M commands/msg/archive.go => commands/msg/archive.go +3 -2
@@ 5,6 5,7 @@ import (
	"fmt"
	"path"
	"sync"
	"time"

	"git.sr.ht/~sircmpwn/aerc/commands"
	"git.sr.ht/~sircmpwn/aerc/models"


@@ 85,7 86,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
			case *types.Done:
				wg.Done()
			case *types.Error:
				aerc.PushError(" " + msg.Error.Error())
				aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
				success = false
				wg.Done()
			}


@@ 95,7 96,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
	go func() {
		wg.Wait()
		if success {
			aerc.PushStatus("Messages archived.")
			aerc.PushStatus("Messages archived.", 10*time.Second)
		}
	}()
	return nil

M commands/msg/copy.go => commands/msg/copy.go +3 -2
@@ 3,6 3,7 @@ package msg
import (
	"errors"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/getopt"



@@ 57,9 58,9 @@ func (Copy) Execute(aerc *widgets.Aerc, args []string) error {

			switch msg := msg.(type) {
			case *types.Done:
				aerc.PushStatus("Messages copied.")
				aerc.PushStatus("Messages copied.", 10*time.Second)
			case *types.Error:
				aerc.PushError(" " + msg.Error.Error())
				aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
			}
		})
	return nil

M commands/msg/delete.go => commands/msg/delete.go +4 -3
@@ 2,6 2,7 @@ package msg

import (
	"errors"
	"time"

	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/models"


@@ 44,9 45,9 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error {
	store.Delete(uids, func(msg types.WorkerMessage) {
		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus("Messages deleted.")
			aerc.PushStatus("Messages deleted.", 10*time.Second)
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
		}
	})



@@ 67,7 68,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error {
			lib.NewMessageStoreView(next, store, aerc.DecryptKeys,
				func(view lib.MessageView, err error) {
					if err != nil {
						aerc.PushError(err.Error())
						aerc.PushError(err.Error(), 10*time.Second)
						return
					}
					nextMv := widgets.NewMessageViewer(acct, aerc.Config(), view)

M commands/msg/forward.go => commands/msg/forward.go +2 -1
@@ 9,6 9,7 @@ import (
	"os"
	"path"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/aerc/models"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 83,7 84,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
		composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), acct.AccountConfig(),
			acct.Worker(), template, defaults, original)
		if err != nil {
			aerc.PushError("Error: " + err.Error())
			aerc.PushError("Error: "+err.Error(), 10*time.Second)
			return nil, err
		}


M commands/msg/modify-labels.go => commands/msg/modify-labels.go +3 -2
@@ 2,6 2,7 @@ package msg

import (
	"errors"
	"time"

	"git.sr.ht/~sircmpwn/aerc/commands"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 55,9 56,9 @@ func (ModifyLabels) Execute(aerc *widgets.Aerc, args []string) error {

		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus("labels updated")
			aerc.PushStatus("labels updated", 10*time.Second)
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
		}
	})
	return nil

M commands/msg/move.go => commands/msg/move.go +3 -2
@@ 3,6 3,7 @@ package msg
import (
	"errors"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/getopt"



@@ 68,9 69,9 @@ func (Move) Execute(aerc *widgets.Aerc, args []string) error {

		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus("Message moved to " + joinedArgs)
			aerc.PushStatus("Message moved to "+joinedArgs, 10*time.Second)
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
		}
	})
	return nil

M commands/msg/pipe.go => commands/msg/pipe.go +5 -4
@@ 5,6 5,7 @@ import (
	"fmt"
	"io"
	"os/exec"
	"time"

	"git.sr.ht/~sircmpwn/aerc/commands"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 74,7 75,7 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
	doTerm := func(reader io.Reader, name string) {
		term, err := commands.QuickTerm(aerc, cmd, reader)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
			return
		}
		aerc.NewTab(term, name)


@@ 92,16 93,16 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
		}()
		err = ecmd.Run()
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		} else {
			if ecmd.ProcessState.ExitCode() != 0 {
				aerc.PushError(fmt.Sprintf(
					"%s: completed with status %d", cmd[0],
					ecmd.ProcessState.ExitCode()))
					ecmd.ProcessState.ExitCode()), 10*time.Second)
			} else {
				aerc.PushStatus(fmt.Sprintf(
					"%s: completed with status %d", cmd[0],
					ecmd.ProcessState.ExitCode()))
					ecmd.ProcessState.ExitCode()), 10*time.Second)
			}
		}
	}

M commands/msg/read.go => commands/msg/read.go +5 -4
@@ 3,6 3,7 @@ package msg
import (
	"errors"
	"sync"
	"time"

	"git.sr.ht/~sircmpwn/getopt"



@@ 90,9 91,9 @@ func submitReadChange(aerc *widgets.Aerc, store *lib.MessageStore,
	store.Read(uids, newState, func(msg types.WorkerMessage) {
		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus(msg_success)
			aerc.PushStatus(msg_success, 10*time.Second)
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
		}
	})
}


@@ 105,7 106,7 @@ func submitReadChangeWg(aerc *widgets.Aerc, store *lib.MessageStore,
		case *types.Done:
			wg.Done()
		case *types.Error:
			aerc.PushError(" " + msg.Error.Error())
			aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
			*success = false
			wg.Done()
		}


@@ 135,7 136,7 @@ func submitToggle(aerc *widgets.Aerc, store *lib.MessageStore, h *helper) error 
	go func() {
		wg.Wait()
		if success {
			aerc.PushStatus(msg_success)
			aerc.PushStatus(msg_success, 10*time.Second)
		}
	}()
	return nil

M commands/msg/recall.go => commands/msg/recall.go +2 -1
@@ 2,6 2,7 @@ package msg

import (
	"io"
	"time"

	"github.com/emersion/go-message"
	_ "github.com/emersion/go-message/charset"


@@ 91,7 92,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error {
			}, func(msg types.WorkerMessage) {
				switch msg := msg.(type) {
				case *types.Error:
					aerc.PushError(" " + msg.Error.Error())
					aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
					composer.Close()
				}
			})

M commands/msg/reply.go => commands/msg/reply.go +2 -1
@@ 7,6 7,7 @@ import (
	"io"
	gomail "net/mail"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/getopt"



@@ 139,7 140,7 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
		composer, err := widgets.NewComposer(aerc, acct, aerc.Config(),
			acct.AccountConfig(), acct.Worker(), template, defaults, original)
		if err != nil {
			aerc.PushError("Error: " + err.Error())
			aerc.PushError("Error: "+err.Error(), 10*time.Second)
			return err
		}


M commands/msgview/next.go => commands/msgview/next.go +3 -1
@@ 1,6 1,8 @@
package msgview

import (
	"time"

	"git.sr.ht/~sircmpwn/aerc/commands/account"
	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 40,7 42,7 @@ func (NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error {
	lib.NewMessageStoreView(nextMsg, store, aerc.DecryptKeys,
		func(view lib.MessageView, err error) {
			if err != nil {
				aerc.PushError(err.Error())
				aerc.PushError(err.Error(), 10*time.Second)
				return
			}
			nextMv := widgets.NewMessageViewer(acct, aerc.Config(), view)

M commands/msgview/open.go => commands/msgview/open.go +5 -4
@@ 7,6 7,7 @@ import (
	"io/ioutil"
	"mime"
	"os"
	"time"

	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/widgets"


@@ 48,23 49,23 @@ func (Open) Execute(aerc *widgets.Aerc, args []string) error {

		tmpFile, err := ioutil.TempFile(os.TempDir(), "aerc-*"+extension)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
			return
		}
		defer tmpFile.Close()

		_, err = io.Copy(tmpFile, reader)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
			return
		}

		err = lib.OpenFile(tmpFile.Name())
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}

		aerc.PushStatus("Opened")
		aerc.PushStatus("Opened", 10*time.Second)
	})

	return nil

M commands/msgview/save.go => commands/msgview/save.go +2 -2
@@ 128,10 128,10 @@ func (Save) Execute(aerc *widgets.Aerc, args []string) error {
	go func() {
		err := <-ch
		if err != nil {
			aerc.PushError(fmt.Sprintf("Save failed: %v", err))
			aerc.PushError(fmt.Sprintf("Save failed: %v", err), 10*time.Second)
			return
		}
		aerc.PushStatus("Saved to " + path)
		aerc.PushStatus("Saved to "+path, 10*time.Second)
	}()
	return nil
}

M commands/pwd.go => commands/pwd.go +2 -1
@@ 3,6 3,7 @@ package commands
import (
	"errors"
	"os"
	"time"

	"git.sr.ht/~sircmpwn/aerc/widgets"
)


@@ 29,6 30,6 @@ func (PrintWorkDir) Execute(aerc *widgets.Aerc, args []string) error {
	if err != nil {
		return err
	}
	aerc.PushStatus(pwd)
	aerc.PushStatus(pwd, 10*time.Second)
	return nil
}

M commands/term.go => commands/term.go +2 -1
@@ 2,6 2,7 @@ package commands

import (
	"os/exec"
	"time"

	"github.com/riywo/loginshell"



@@ 46,7 47,7 @@ func TermCore(aerc *widgets.Aerc, args []string) error {
	term.OnClose = func(err error) {
		aerc.RemoveTab(term)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
	}
	return nil

M commands/util.go => commands/util.go +5 -3
@@ 8,6 8,7 @@ import (
	"path/filepath"
	"sort"
	"strings"
	"time"

	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/models"


@@ 31,11 32,12 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter

	term.OnClose = func(err error) {
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
			// remove the tab on error, otherwise it gets stuck
			aerc.RemoveTab(term)
		} else {
			aerc.PushStatus("Process complete, press any key to close.")
			aerc.PushStatus("Process complete, press any key to close.",
				10*time.Second)
			term.OnEvent = func(event tcell.Event) bool {
				aerc.RemoveTab(term)
				return true


@@ 54,7 56,7 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter

		err := <-status
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
	}


M widgets/account-wizard.go => widgets/account-wizard.go +4 -3
@@ 10,6 10,7 @@ import (
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/gdamore/tcell"
	"github.com/go-ini/ini"


@@ 428,7 429,7 @@ func (wizard *AccountWizard) ConfigureTemporaryAccount(temporary bool) {

func (wizard *AccountWizard) errorFor(d ui.Interactive, err error) {
	if d == nil {
		wizard.aerc.PushError(" " + err.Error())
		wizard.aerc.PushError(" "+err.Error(), 10*time.Second)
		wizard.Invalidate()
		return
	}


@@ 443,7 444,7 @@ func (wizard *AccountWizard) errorFor(d ui.Interactive, err error) {
				wizard.step = step
				wizard.focus = focus
				wizard.Focus(true)
				wizard.aerc.PushError(" " + err.Error())
				wizard.aerc.PushError(" "+err.Error(), 10*time.Second)
				wizard.Invalidate()
				return
			}


@@ 554,7 555,7 @@ func (wizard *AccountWizard) finish(tutorial bool) {
		term.OnClose = func(err error) {
			wizard.aerc.RemoveTab(term)
			if err != nil {
				wizard.aerc.PushError(" " + err.Error())
				wizard.aerc.PushError(" "+err.Error(), 10*time.Second)
			}
		}
	}

M widgets/account.go => widgets/account.go +2 -1
@@ 4,6 4,7 @@ import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/gdamore/tcell"



@@ 289,7 290,7 @@ func (acct *AccountView) getSortCriteria() []*types.SortCriterion {
	}
	criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort)
	if err != nil {
		acct.aerc.PushError(" ui.sort: " + err.Error())
		acct.aerc.PushError(" ui.sort: "+err.Error(), 10*time.Second)
		return nil
	}
	return criteria

M widgets/aerc.go => widgets/aerc.go +10 -10
@@ 386,16 386,16 @@ func (aerc *Aerc) SetError(status string) *StatusMessage {
	return aerc.statusline.SetError(status)
}

func (aerc *Aerc) PushStatus(text string) *StatusMessage {
	return aerc.statusline.Push(text, 10*time.Second)
func (aerc *Aerc) PushStatus(text string, expiry time.Duration) *StatusMessage {
	return aerc.statusline.Push(text, expiry)
}

func (aerc *Aerc) PushError(text string) *StatusMessage {
	return aerc.statusline.PushError(text, 10*time.Second)
func (aerc *Aerc) PushError(text string, expiry time.Duration) *StatusMessage {
	return aerc.statusline.PushError(text, expiry)
}

func (aerc *Aerc) PushSuccess(text string) *StatusMessage {
	return aerc.statusline.PushSuccess(text, 10*time.Second)
func (aerc *Aerc) PushSuccess(text string, expiry time.Duration) *StatusMessage {
	return aerc.statusline.PushSuccess(text, expiry)
}

func (aerc *Aerc) focus(item ui.Interactive) {


@@ 424,11 424,11 @@ func (aerc *Aerc) BeginExCommand(cmd string) {
	exline := NewExLine(aerc.conf, cmd, func(cmd string) {
		parts, err := shlex.Split(cmd)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
		err = aerc.cmd(parts)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
		// only add to history if this is an unsimulated command,
		// ie one not executed from a keybinding


@@ 452,7 452,7 @@ func (aerc *Aerc) RegisterPrompt(prompt string, cmd []string) {
		}
		err := aerc.cmd(cmd)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
	}, func(cmd string) []string {
		return nil // TODO: completions


@@ 479,7 479,7 @@ func (aerc *Aerc) RegisterChoices(choices []Choice) {
		}
		err := aerc.cmd(cmd)
		if err != nil {
			aerc.PushError(" " + err.Error())
			aerc.PushError(" "+err.Error(), 10*time.Second)
		}
	}, func(cmd string) []string {
		return nil // TODO: completions

M widgets/compose.go => widgets/compose.go +3 -2
@@ 73,7 73,7 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,
	templateData := templates.ParseTemplateData(defaults, original)
	cmpl := completer.New(conf.Compose.AddressBookCmd, func(err error) {
		aerc.PushError(
			fmt.Sprintf("could not complete header: %v", err))
			fmt.Sprintf("could not complete header: %v", err), 10*time.Second)
		worker.Logger.Printf("could not complete header: %v", err)
	}, aerc.Logger())
	layout, editors, focusable := buildComposeHeader(aerc, cmpl, defaults)


@@ 261,7 261,8 @@ func (c *Composer) readSignatureFromFile() []byte {
	signature, err := ioutil.ReadFile(sigFile)
	if err != nil {
		c.aerc.PushError(
			fmt.Sprintf(" Error loading signature from file: %v", sigFile))
			fmt.Sprintf(" Error loading signature from file: %v", sigFile),
			10*time.Second)
		return nil
	}
	return signature

M widgets/msglist.go => widgets/msglist.go +2 -1
@@ 3,6 3,7 @@ package widgets
import (
	"fmt"
	"log"
	"time"

	"github.com/gdamore/tcell"
	"github.com/mattn/go-runewidth"


@@ 185,7 186,7 @@ func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) {
				lib.NewMessageStoreView(msg, store, ml.aerc.DecryptKeys,
					func(view lib.MessageView, err error) {
						if err != nil {
							ml.aerc.PushError(err.Error())
							ml.aerc.PushError(err.Error(), 10*time.Second)
							return
						}
						viewer := NewMessageViewer(acct, ml.aerc.Config(), view)

M widgets/tabhost.go => widgets/tabhost.go +7 -3
@@ 1,11 1,15 @@
package widgets

import (
	"time"
)

type TabHost interface {
	BeginExCommand(cmd string)
	SetStatus(status string) *StatusMessage
	SetError(err string) *StatusMessage
	PushStatus(text string) *StatusMessage
	PushError(text string) *StatusMessage
	PushSuccess(text string) *StatusMessage
	PushStatus(text string, expiry time.Duration) *StatusMessage
	PushError(text string, expiry time.Duration) *StatusMessage
	PushSuccess(text string, expiry time.Duration) *StatusMessage
	Beep()
}