diff options
author | Robin Jarry <robin@jarry.cc> | 2023-02-02 00:48:51 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-02-20 14:40:59 +0100 |
commit | 9fa296fb762231d386db88913d1c2ea521bd813c (patch) | |
tree | 445bf6554084bb37e6aed479c9942b5afecb2149 /config | |
parent | 28483808727fd288b95b9dd26a716f6cf7c02b5a (diff) | |
download | aerc-9fa296fb762231d386db88913d1c2ea521bd813c.tar.gz |
templates: unify data interface
Require that all aerc template data objects implement the same
TemplateData interface.
Implement that interface in two different places:
1) state.TemplateData (renamed/moved from templates.TemplateData).
This structure (along with all its methods) needs to be decoupled
from the templates package to break the import cycle with the config
package. This allows much simpler construction of this object and
ensure that values are calculated only when requested.
2) config.dummyData (extracted from templates).
This is only used in the config package to validate user templates.
Putting it here allows also to break an import cycle.
Use state.TemplateData everywhere (including for account tabs title
rendering).
Signed-off-by: Robin Jarry <robin@jarry.cc>
Reviewed-by: Moritz Poldrack <moritz@poldrack.dev>
Diffstat (limited to 'config')
-rw-r--r-- | config/columns.go | 4 | ||||
-rw-r--r-- | config/templates.go | 48 | ||||
-rw-r--r-- | config/ui_test.go | 31 |
3 files changed, 62 insertions, 21 deletions
diff --git a/config/columns.go b/config/columns.go index b1c7191b..55efa2a7 100644 --- a/config/columns.go +++ b/config/columns.go @@ -90,9 +90,7 @@ func parseColumnDef(col string, section *ini.Section) (*ColumnDef, error) { return nil, err } - data := templates.DummyData() - var buf bytes.Buffer - err = t.Execute(&buf, data) + err = templates.Render(t, &bytes.Buffer{}, &dummyData{}) if err != nil { return nil, err } diff --git a/config/templates.go b/config/templates.go index 5580c056..f9dda0ea 100644 --- a/config/templates.go +++ b/config/templates.go @@ -3,9 +3,11 @@ package config import ( "path" "strings" + "time" "git.sr.ht/~rjarry/aerc/lib/templates" "git.sr.ht/~rjarry/aerc/log" + "github.com/emersion/go-message/mail" "github.com/go-ini/ini" ) @@ -48,13 +50,13 @@ func parseTemplates(file *ini.File) error { // we want to fail during startup if the templates are not ok // hence we do dummy executes here t := Templates - if err := templates.CheckTemplate(t.NewMessage, t.TemplateDirs); err != nil { + if err := checkTemplate(t.NewMessage, t.TemplateDirs); err != nil { return err } - if err := templates.CheckTemplate(t.QuotedReply, t.TemplateDirs); err != nil { + if err := checkTemplate(t.QuotedReply, t.TemplateDirs); err != nil { return err } - if err := templates.CheckTemplate(t.Forwards, t.TemplateDirs); err != nil { + if err := checkTemplate(t.Forwards, t.TemplateDirs); err != nil { return err } @@ -62,3 +64,43 @@ func parseTemplates(file *ini.File) error { return nil } + +func checkTemplate(filename string, dirs []string) error { + var data dummyData + _, err := templates.ParseTemplateFromFile(filename, dirs, &data) + return err +} + +// 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) Subject() 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() int { return 1 } +func (d *dummyData) Unread() int { return 3 } +func (d *dummyData) Exists() int { return 14 } diff --git a/config/ui_test.go b/config/ui_test.go index c5eb6031..677dcc86 100644 --- a/config/ui_test.go +++ b/config/ui_test.go @@ -1,13 +1,20 @@ package config import ( - "bytes" + "reflect" "testing" + "text/template" - "git.sr.ht/~rjarry/aerc/lib/templates" "github.com/stretchr/testify/assert" ) +func templateText(t *template.Template) string { + // unfortunately, the original template text is stored as a private + // field, for test purposes, access its value via reflection + v := reflect.ValueOf(t).Elem() + return v.FieldByName("text").String() +} + func TestConvertIndexFormat(t *testing.T) { columns, err := convertIndexFormat("%-20.20D %-17.17n %Z %s") if err != nil { @@ -15,32 +22,26 @@ func TestConvertIndexFormat(t *testing.T) { } assert.Len(t, columns, 4) - data := templates.DummyData() - var buf bytes.Buffer - assert.Equal(t, "date", columns[0].Name) assert.Equal(t, 20.0, columns[0].Width) assert.Equal(t, ALIGN_LEFT|WIDTH_EXACT, columns[0].Flags) - assert.Nil(t, columns[0].Template.Execute(&buf, data)) + assert.Equal(t, `{{.DateAutoFormat .Date.Local}}`, + templateText(columns[0].Template)) - buf.Reset() assert.Equal(t, "name", columns[1].Name) assert.Equal(t, 17.0, columns[1].Width) assert.Equal(t, ALIGN_LEFT|WIDTH_EXACT, columns[1].Flags) - assert.Nil(t, columns[1].Template.Execute(&buf, data)) - assert.Equal(t, "John Doe", buf.String()) + assert.Equal(t, `{{index (.From | names) 0}}`, + templateText(columns[1].Template)) - buf.Reset() assert.Equal(t, "flags", columns[2].Name) assert.Equal(t, 4.0, columns[2].Width) assert.Equal(t, ALIGN_RIGHT|WIDTH_EXACT, columns[2].Flags) - assert.Nil(t, columns[2].Template.Execute(&buf, data)) - assert.Equal(t, "O!*", buf.String()) + assert.Equal(t, `{{.Flags | join ""}}`, + templateText(columns[2].Template)) - buf.Reset() assert.Equal(t, "subject", columns[3].Name) assert.Equal(t, 0.0, columns[3].Width) assert.Equal(t, ALIGN_LEFT|WIDTH_AUTO, columns[3].Flags) - assert.Nil(t, columns[3].Template.Execute(&buf, data)) - assert.Equal(t, "[PATCH aerc 2/3] foo: baz bar buz", buf.String()) + assert.Equal(t, `{{.Subject}}`, templateText(columns[3].Template)) } |