aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--commands/commands.go5
-rw-r--r--commands/commands_test.go52
-rw-r--r--lib/state/templates.go120
-rw-r--r--models/templates.go1
-rw-r--r--widgets/account.go6
-rw-r--r--widgets/compose.go11
-rw-r--r--widgets/dirlist.go6
-rw-r--r--widgets/dirtree.go4
-rw-r--r--widgets/msglist.go10
-rw-r--r--widgets/status.go5
10 files changed, 147 insertions, 73 deletions
diff --git a/commands/commands.go b/commands/commands.go
index 7dfd183b..59f87321 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -98,8 +98,7 @@ func templateData(
msg, _ = acct.SelectedMessage()
}
- var data state.TemplateData
-
+ data := state.NewDataSetter()
data.SetAccount(cfg)
data.SetFolder(folder)
data.SetInfo(msg, 0, false)
@@ -109,7 +108,7 @@ func templateData(
})
}
- return &data
+ return data.Data()
}
func (cmds *Commands) ExecuteCommand(
diff --git a/commands/commands_test.go b/commands/commands_test.go
index a424d16d..dccb8572 100644
--- a/commands/commands_test.go
+++ b/commands/commands_test.go
@@ -3,8 +3,10 @@ package commands
import (
"reflect"
"testing"
+ "time"
- "git.sr.ht/~rjarry/aerc/lib/state"
+ "git.sr.ht/~rjarry/aerc/models"
+ "github.com/emersion/go-message/mail"
)
func TestExecuteCommand_expand(t *testing.T) {
@@ -40,7 +42,7 @@ func TestExecuteCommand_expand(t *testing.T) {
},
}
- data := state.TemplateData{}
+ var data dummyData
for i, test := range tests {
got, err := expand(&data, test.args)
@@ -52,3 +54,49 @@ func TestExecuteCommand_expand(t *testing.T) {
}
}
}
+
+// only for validation
+type dummyData struct{}
+
+var (
+ addr1 = mail.Address{Name: "John Foo", Address: "foo@bar.org"}
+ addr2 = mail.Address{Name: "John Bar", Address: "bar@foo.org"}
+)
+
+func (d *dummyData) Account() string { return "work" }
+func (d *dummyData) Folder() string { return "INBOX" }
+func (d *dummyData) To() []*mail.Address { return []*mail.Address{&addr1} }
+func (d *dummyData) Cc() []*mail.Address { return nil }
+func (d *dummyData) Bcc() []*mail.Address { return nil }
+func (d *dummyData) From() []*mail.Address { return []*mail.Address{&addr2} }
+func (d *dummyData) Peer() []*mail.Address { return d.From() }
+func (d *dummyData) ReplyTo() []*mail.Address { return nil }
+func (d *dummyData) Date() time.Time { return time.Now() }
+func (d *dummyData) DateAutoFormat(time.Time) string { return "" }
+func (d *dummyData) Header(string) string { return "" }
+func (d *dummyData) ThreadPrefix() string { return "└─>" }
+func (d *dummyData) Subject() string { return "Re: [PATCH] hey" }
+func (d *dummyData) SubjectBase() string { return "[PATCH] hey" }
+func (d *dummyData) Number() int { return 0 }
+func (d *dummyData) Labels() []string { return nil }
+func (d *dummyData) Flags() []string { return nil }
+func (d *dummyData) MessageId() string { return "123456789@foo.org" }
+func (d *dummyData) Size() int { return 420 }
+func (d *dummyData) OriginalText() string { return "Blah blah blah" }
+func (d *dummyData) OriginalDate() time.Time { return time.Now() }
+func (d *dummyData) OriginalFrom() []*mail.Address { return d.From() }
+func (d *dummyData) OriginalMIMEType() string { return "text/plain" }
+func (d *dummyData) OriginalHeader(string) string { return "" }
+func (d *dummyData) Recent(...string) int { return 1 }
+func (d *dummyData) Unread(...string) int { return 3 }
+func (d *dummyData) Exists(...string) int { return 14 }
+func (d *dummyData) RUE(...string) string { return "1/3/14" }
+func (d *dummyData) Connected() bool { return false }
+func (d *dummyData) ConnectionInfo() string { return "" }
+func (d *dummyData) ContentInfo() string { return "" }
+func (d *dummyData) StatusInfo() string { return "" }
+func (d *dummyData) TrayInfo() string { return "" }
+func (d *dummyData) PendingKeys() string { return "" }
+func (d *dummyData) Role() string { return "inbox" }
+func (d *dummyData) Style(string, string) string { return "" }
+func (d *dummyData) StyleSwitch(string, ...models.Case) string { return "" }
diff --git a/lib/state/templates.go b/lib/state/templates.go
index e93d0bb0..b0daa2cc 100644
--- a/lib/state/templates.go
+++ b/lib/state/templates.go
@@ -12,7 +12,19 @@ import (
"github.com/emersion/go-message/mail"
)
-type TemplateData struct {
+type DataSetter interface {
+ Data() models.TemplateData
+ SetHeaders(*mail.Header, *models.OriginalMail)
+ SetInfo(*models.MessageInfo, int, bool)
+ SetThreading(string, bool)
+ SetAccount(*config.AccountConfig)
+ SetFolder(*models.Directory)
+ SetRUE([]string, func(string) (int, int, int))
+ SetState(s *AccountState)
+ SetPendingKeys([]config.KeyStroke)
+}
+
+type templateData struct {
// only available when composing/replying/forwarding
headers *mail.Header
// only available when replying with a quote
@@ -37,25 +49,35 @@ type TemplateData struct {
pendingKeys []config.KeyStroke
}
+func NewDataSetter() DataSetter {
+ return &templateData{}
+}
+
+// Data returns the template data
+func (d *templateData) Data() models.TemplateData {
+ return d
+}
+
// only used for compose/reply/forward
-func (d *TemplateData) SetHeaders(h *mail.Header, o *models.OriginalMail) {
+func (d *templateData) SetHeaders(h *mail.Header, o *models.OriginalMail) {
d.headers = h
d.parent = o
}
// only used for message list templates
-func (d *TemplateData) SetInfo(info *models.MessageInfo, num int, marked bool) {
+func (d *templateData) SetInfo(info *models.MessageInfo, num int, marked bool,
+) {
d.info = info
d.msgNum = num
d.marked = marked
}
-func (d *TemplateData) SetThreading(prefix string, same bool) {
+func (d *templateData) SetThreading(prefix string, same bool) {
d.threadPrefix = prefix
d.threadSameSubject = same
}
-func (d *TemplateData) SetAccount(acct *config.AccountConfig) {
+func (d *templateData) SetAccount(acct *config.AccountConfig) {
d.account = acct
d.myAddresses = make(map[string]bool)
if acct != nil {
@@ -66,49 +88,51 @@ func (d *TemplateData) SetAccount(acct *config.AccountConfig) {
}
}
-func (d *TemplateData) SetFolder(folder *models.Directory) {
+func (d *templateData) SetFolder(folder *models.Directory) {
d.folder = folder
}
-func (d *TemplateData) SetRUE(folders []string, cb func(string) (int, int, int)) {
+func (d *templateData) SetRUE(folders []string,
+ cb func(string) (int, int, int),
+) {
d.folders = folders
d.getRUEcount = cb
}
-func (d *TemplateData) SetState(state *AccountState) {
+func (d *templateData) SetState(state *AccountState) {
d.state = state
}
-func (d *TemplateData) SetPendingKeys(keys []config.KeyStroke) {
+func (d *templateData) SetPendingKeys(keys []config.KeyStroke) {
d.pendingKeys = keys
}
-func (d *TemplateData) Account() string {
+func (d *templateData) Account() string {
if d.account != nil {
return d.account.Name
}
return ""
}
-func (d *TemplateData) Folder() string {
+func (d *templateData) Folder() string {
if d.folder != nil {
return d.folder.Name
}
return ""
}
-func (d *TemplateData) Role() string {
+func (d *templateData) Role() string {
if d.folder != nil {
return string(d.folder.Role)
}
return ""
}
-func (d *TemplateData) ui() *config.UIConfig {
+func (d *templateData) ui() *config.UIConfig {
return config.Ui.ForAccount(d.Account()).ForFolder(d.Folder())
}
-func (d *TemplateData) To() []*mail.Address {
+func (d *templateData) To() []*mail.Address {
var to []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -119,7 +143,7 @@ func (d *TemplateData) To() []*mail.Address {
return to
}
-func (d *TemplateData) Cc() []*mail.Address {
+func (d *templateData) Cc() []*mail.Address {
var cc []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -130,7 +154,7 @@ func (d *TemplateData) Cc() []*mail.Address {
return cc
}
-func (d *TemplateData) Bcc() []*mail.Address {
+func (d *templateData) Bcc() []*mail.Address {
var bcc []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -141,7 +165,7 @@ func (d *TemplateData) Bcc() []*mail.Address {
return bcc
}
-func (d *TemplateData) From() []*mail.Address {
+func (d *templateData) From() []*mail.Address {
var from []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -152,7 +176,7 @@ func (d *TemplateData) From() []*mail.Address {
return from
}
-func (d *TemplateData) Peer() []*mail.Address {
+func (d *templateData) Peer() []*mail.Address {
var from, to []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -170,7 +194,7 @@ func (d *TemplateData) Peer() []*mail.Address {
return from
}
-func (d *TemplateData) ReplyTo() []*mail.Address {
+func (d *templateData) ReplyTo() []*mail.Address {
var replyTo []*mail.Address
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -181,7 +205,7 @@ func (d *TemplateData) ReplyTo() []*mail.Address {
return replyTo
}
-func (d *TemplateData) Date() time.Time {
+func (d *templateData) Date() time.Time {
var date time.Time
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -194,7 +218,7 @@ func (d *TemplateData) Date() time.Time {
return date
}
-func (d *TemplateData) DateAutoFormat(date time.Time) string {
+func (d *templateData) DateAutoFormat(date time.Time) string {
if date.IsZero() {
return ""
}
@@ -218,7 +242,7 @@ func (d *TemplateData) DateAutoFormat(date time.Time) string {
return date.Format(fmt)
}
-func (d *TemplateData) Header(name string) string {
+func (d *templateData) Header(name string) string {
var h *mail.Header
switch {
case d.headers != nil:
@@ -235,11 +259,11 @@ func (d *TemplateData) Header(name string) string {
return text
}
-func (d *TemplateData) ThreadPrefix() string {
+func (d *templateData) ThreadPrefix() string {
return d.threadPrefix
}
-func (d *TemplateData) Subject() string {
+func (d *templateData) Subject() string {
var subject string
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -253,7 +277,7 @@ func (d *TemplateData) Subject() string {
return subject
}
-func (d *TemplateData) SubjectBase() string {
+func (d *templateData) SubjectBase() string {
var subject string
switch {
case d.info != nil && d.info.Envelope != nil:
@@ -265,18 +289,18 @@ func (d *TemplateData) SubjectBase() string {
return base
}
-func (d *TemplateData) Number() int {
+func (d *templateData) Number() int {
return d.msgNum
}
-func (d *TemplateData) Labels() []string {
+func (d *templateData) Labels() []string {
if d.info == nil {
return nil
}
return d.info.Labels
}
-func (d *TemplateData) Flags() []string {
+func (d *templateData) Flags() []string {
var flags []string
if d.info == nil {
return flags
@@ -312,35 +336,35 @@ func (d *TemplateData) Flags() []string {
return flags
}
-func (d *TemplateData) MessageId() string {
+func (d *templateData) MessageId() string {
if d.info == nil || d.info.Envelope == nil {
return ""
}
return d.info.Envelope.MessageId
}
-func (d *TemplateData) Size() int {
+func (d *templateData) Size() int {
if d.info == nil || d.info.Envelope == nil {
return 0
}
return int(d.info.Size)
}
-func (d *TemplateData) OriginalText() string {
+func (d *templateData) OriginalText() string {
if d.parent == nil {
return ""
}
return d.parent.Text
}
-func (d *TemplateData) OriginalDate() time.Time {
+func (d *templateData) OriginalDate() time.Time {
if d.parent == nil {
return time.Time{}
}
return d.parent.Date
}
-func (d *TemplateData) OriginalFrom() []*mail.Address {
+func (d *templateData) OriginalFrom() []*mail.Address {
if d.parent == nil || d.parent.RFC822Headers == nil {
return nil
}
@@ -348,14 +372,14 @@ func (d *TemplateData) OriginalFrom() []*mail.Address {
return from
}
-func (d *TemplateData) OriginalMIMEType() string {
+func (d *templateData) OriginalMIMEType() string {
if d.parent == nil {
return ""
}
return d.parent.MIMEType
}
-func (d *TemplateData) OriginalHeader(name string) string {
+func (d *templateData) OriginalHeader(name string) string {
if d.parent == nil || d.parent.RFC822Headers == nil {
return ""
}
@@ -366,7 +390,7 @@ func (d *TemplateData) OriginalHeader(name string) string {
return text
}
-func (d *TemplateData) rue(folders ...string) (int, int, int) {
+func (d *templateData) rue(folders ...string) (int, int, int) {
var recent, unread, exists int
if d.getRUEcount != nil {
if len(folders) == 0 {
@@ -382,22 +406,22 @@ func (d *TemplateData) rue(folders ...string) (int, int, int) {
return recent, unread, exists
}
-func (d *TemplateData) Recent(folders ...string) int {
+func (d *templateData) Recent(folders ...string) int {
r, _, _ := d.rue(folders...)
return r
}
-func (d *TemplateData) Unread(folders ...string) int {
+func (d *templateData) Unread(folders ...string) int {
_, u, _ := d.rue(folders...)
return u
}
-func (d *TemplateData) Exists(folders ...string) int {
+func (d *templateData) Exists(folders ...string) int {
_, _, e := d.rue(folders...)
return e
}
-func (d *TemplateData) RUE(folders ...string) string {
+func (d *templateData) RUE(folders ...string) string {
r, u, e := d.rue(folders...)
switch {
case r > 0:
@@ -410,14 +434,14 @@ func (d *TemplateData) RUE(folders ...string) string {
return ""
}
-func (d *TemplateData) Connected() bool {
+func (d *templateData) Connected() bool {
if d.state != nil {
return d.state.Connected
}
return false
}
-func (d *TemplateData) ConnectionInfo() string {
+func (d *templateData) ConnectionInfo() string {
switch {
case d.state == nil:
return ""
@@ -430,7 +454,7 @@ func (d *TemplateData) ConnectionInfo() string {
}
}
-func (d *TemplateData) ContentInfo() string {
+func (d *templateData) ContentInfo() string {
if d.state == nil {
return ""
}
@@ -447,7 +471,7 @@ func (d *TemplateData) ContentInfo() string {
return strings.Join(content, config.Statusline.Separator)
}
-func (d *TemplateData) StatusInfo() string {
+func (d *templateData) StatusInfo() string {
stat := d.ConnectionInfo()
if content := d.ContentInfo(); content != "" {
stat += config.Statusline.Separator + content
@@ -455,7 +479,7 @@ func (d *TemplateData) StatusInfo() string {
return stat
}
-func (d *TemplateData) TrayInfo() string {
+func (d *templateData) TrayInfo() string {
if d.state == nil {
return ""
}
@@ -473,17 +497,17 @@ func (d *TemplateData) TrayInfo() string {
return strings.Join(tray, config.Statusline.Separator)
}
-func (d *TemplateData) PendingKeys() string {
+func (d *templateData) PendingKeys() string {
return config.FormatKeyStrokes(d.pendingKeys)
}
-func (d *TemplateData) Style(content, name string) string {
+func (d *templateData) Style(content, name string) string {
cfg := config.Ui.ForAccount(d.Account())
style := cfg.GetUserStyle(name)
return parse.ApplyStyle(style, content)
}
-func (d *TemplateData) StyleSwitch(content string, cases ...models.Case) string {
+func (d *templateData) StyleSwitch(content string, cases ...models.Case) string {
for _, c := range cases {
if c.Matches(content) {
cfg := config.Ui.ForAccount(d.Account())
diff --git a/models/templates.go b/models/templates.go
index cebad5ea..f6d79c36 100644
--- a/models/templates.go
+++ b/models/templates.go
@@ -26,6 +26,7 @@ type TemplateData interface {
Labels() []string
Flags() []string
MessageId() string
+ Role() string
Size() int
OriginalText() string
OriginalDate() time.Time
diff --git a/widgets/account.go b/widgets/account.go
index e28804de..d76333d2 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -605,17 +605,17 @@ func (acct *AccountView) Vsplit(n int) error {
// setTitle executes the title template and sets the tab title
func (acct *AccountView) setTitle() {
- var data state.TemplateData
-
if acct.tab == nil {
return
}
+
+ data := state.NewDataSetter()
data.SetAccount(acct.acct)
data.SetFolder(acct.Directories().SelectedDirectory())
data.SetRUE(acct.dirlist.List(), acct.dirlist.GetRUECount)
var buf bytes.Buffer
- err := templates.Render(acct.uiConf.TabTitleAccount, &buf, &data)
+ err := templates.Render(acct.uiConf.TabTitleAccount, &buf, data.Data())
if err != nil {
acct.PushError(err)
return
diff --git a/widgets/compose.go b/widgets/compose.go
index 4735782b..ea6a50a4 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -96,11 +96,11 @@ func NewComposer(
completer: nil,
}
- var data state.TemplateData
+ data := state.NewDataSetter()
data.SetAccount(acct.acct)
data.SetFolder(acct.Directories().SelectedDirectory())
data.SetHeaders(h, orig)
- if err := c.AddTemplate(template, &data); err != nil {
+ if err := c.AddTemplate(template, data.Data()); err != nil {
return nil, err
}
c.AddSignature()
@@ -1588,8 +1588,6 @@ func (c *Composer) setTitle() {
return
}
- var data state.TemplateData
-
header := c.header.Copy()
// Get subject direct from the textinput
subject, ok := c.editors["subject"]
@@ -1599,12 +1597,15 @@ func (c *Composer) setTitle() {
if header.Get("subject") == "" {
header.SetSubject("New Email")
}
+
+ data := state.NewDataSetter()
data.SetAccount(c.acctConfig)
data.SetFolder(c.acct.Directories().SelectedDirectory())
data.SetHeaders(&header, c.parent)
var buf bytes.Buffer
- err := templates.Render(c.acct.UiConfig().TabTitleComposer, &buf, &data)
+ err := templates.Render(c.acct.UiConfig().TabTitleComposer, &buf,
+ data.Data())
if err != nil {
c.acct.PushError(err)
return
diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index 25d1e7ff..8112ebd2 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -238,8 +238,8 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
}
listCtx := ctx.Subcontext(0, 0, textWidth, ctx.Height())
- var data state.TemplateData
+ data := state.NewDataSetter()
data.SetAccount(dirlist.acctConf)
for i, name := range dirlist.dirs {
@@ -254,7 +254,7 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
data.SetFolder(dirlist.Directory(name))
data.SetRUE([]string{name}, dirlist.GetRUECount)
left, right, style := dirlist.renderDir(
- name, uiConfig, &data,
+ name, uiConfig, data.Data(),
name == dirlist.selecting, listCtx.Width(),
)
listCtx.Printf(0, row, style, "%s %s", left, right)
@@ -267,7 +267,7 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
}
func (dirlist *DirectoryList) renderDir(
- path string, conf *config.UIConfig, data *state.TemplateData,
+ path string, conf *config.UIConfig, data models.TemplateData,
selected bool, width int,
) (string, string, tcell.Style) {
var left, right string
diff --git a/widgets/dirtree.go b/widgets/dirtree.go
index 98b25850..9a33e6c3 100644
--- a/widgets/dirtree.go
+++ b/widgets/dirtree.go
@@ -98,8 +98,8 @@ func (dt *DirectoryTree) Draw(ctx *ui.Context) {
}
treeCtx := ctx.Subcontext(0, 0, textWidth, ctx.Height())
- var data state.TemplateData
+ data := state.NewDataSetter()
data.SetAccount(dt.acctConf)
n = 0
@@ -124,7 +124,7 @@ func (dt *DirectoryTree) Draw(ctx *ui.Context) {
data.SetRUE([]string{path}, dt.GetRUECount)
left, right, style := dt.renderDir(
- path, uiConfig, &data,
+ path, uiConfig, data.Data(),
i == dt.listIdx, treeCtx.Width(),
)
diff --git a/widgets/msglist.go b/widgets/msglist.go
index 1fc33279..df005431 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -91,8 +91,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
}
var needsHeaders []uint32
- var data state.TemplateData
+ data := state.NewDataSetter()
data.SetAccount(acct.acct)
data.SetFolder(acct.Directories().SelectedDirectory())
@@ -171,7 +171,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
lastSubject = baseSubject
prevThread = thread
- if addMessage(store, thread.Uid, &table, &data, uiConfig) {
+ if addMessage(store, thread.Uid, &table, data, uiConfig) {
break threadLoop
}
}
@@ -183,7 +183,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
continue
}
uid := iter.Value().(uint32)
- if addMessage(store, uid, &table, &data, uiConfig) {
+ if addMessage(store, uid, &table, data, uiConfig) {
break
}
}
@@ -216,7 +216,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
func addMessage(
store *lib.MessageStore, uid uint32,
- table *ui.Table, data *state.TemplateData,
+ table *ui.Table, data state.DataSetter,
uiConfig *config.UIConfig,
) bool {
msg := store.Messages[uid]
@@ -258,7 +258,7 @@ func addMessage(
for c, col := range table.Columns {
var buf bytes.Buffer
- err := col.Def.Template.Execute(&buf, data)
+ err := col.Def.Template.Execute(&buf, data.Data())
if err != nil {
log.Errorf("<%s> %s", msg.Envelope.MessageId, err)
cells[c] = err.Error()
diff --git a/widgets/status.go b/widgets/status.go
index 9f2544c7..6157dd10 100644
--- a/widgets/status.go
+++ b/widgets/status.go
@@ -49,7 +49,7 @@ func (status *StatusLine) Draw(ctx *ui.Context) {
style := status.uiConfig().GetStyle(config.STYLE_STATUSLINE_ERROR)
ctx.Printf(0, 0, style, "%s", msg)
case status.aerc != nil && status.acct != nil:
- var data state.TemplateData
+ data := state.NewDataSetter()
data.SetPendingKeys(status.aerc.pendingKeys)
data.SetState(&status.acct.state)
data.SetAccount(status.acct.acct)
@@ -66,7 +66,8 @@ func (status *StatusLine) Draw(ctx *ui.Context) {
var buf bytes.Buffer
cells := make([]string, len(table.Columns))
for c, col := range table.Columns {
- err := templates.Render(col.Def.Template, &buf, &data)
+ err := templates.Render(col.Def.Template, &buf,
+ data.Data())
if err != nil {
log.Errorf("%s", err)
cells[c] = err.Error()