~sircmpwn/aerc

Add Templates v1 PROPOSED

Srivathsan Murali: 1
 Add Templates

 3 files changed, 47 insertions(+), 5 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/8581/mbox | git am -3
Learn more about email & git

[PATCH] Add Templates Export this patch

This adds the ability to load templates into the body of the
email. When compose is called with '-T' flag, the default template
or the template with the name passed as value is used to populate
the body of the email.

There are two new configs options for accounts.conf: TemplateDir
and DefaultTemplate. Template Dir specifies the directory containing
the templates.DefaultTemplate specifies the template that is loaded
if no template name is provided.
---
Implementation for #60: Email Templates
 commands/account/compose.go | 43 ++++++++++++++++++++++++++++++++-----
 config/config.go            |  2 ++
 doc/aerc-config.5.scd       |  7 ++++++
 3 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/commands/account/compose.go b/commands/account/compose.go
index 039eb92363c6..d8d97970bad8 100644
--- a/commands/account/compose.go
+++ b/commands/account/compose.go
@@ -2,11 +2,15 @@ package account

import (
	"errors"
	"io/ioutil"
	"path"
	"regexp"
	"strings"

	"git.sr.ht/~sircmpwn/aerc/widgets"
	"git.sr.ht/~sircmpwn/getopt"
	"git.sr.ht/~sircmpwn/aerc/config"
	"github.com/mitchellh/go-homedir"
)

type Compose struct{}
@@ -24,11 +28,11 @@ func (Compose) Complete(aerc *widgets.Aerc, args []string) []string {
}

func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
	body, err := buildBody(args)
	acct := aerc.SelectedAccount()
	body, err := buildBody(args, acct.AccountConfig())
	if err != nil {
		return err
	}
	acct := aerc.SelectedAccount()
	composer := widgets.NewComposer(aerc,
		aerc.Config(), acct.AccountConfig(), acct.Worker(), nil)
	tab := aerc.NewTab(composer, "New email")
@@ -44,9 +48,9 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
	return nil
}

func buildBody(args []string) (string, error) {
func buildBody(args []string, acct *config.AccountConfig) (string, error) {
	var body, headers string
	opts, optind, err := getopt.Getopts(args, "H:")
	opts, optind, err := getopt.Getopts(args, ":T:H:")
	if err != nil {
		return "", err
	}
@@ -60,11 +64,25 @@ func buildBody(args []string) (string, error) {
			} else {
				headers += opt.Value + ":\n"
			}
		case 'T':
			template, err := readTemplateFromFile(opt.Value, acct.TemplateDir)
			if err != nil {
				return "", err
			}
			body = template
		case ':':
			if opt.Value == "T" {
				template, err := readTemplateFromFile(acct.DefaultTemplate, acct.TemplateDir)
				if err != nil {
					return "", err
				}
				body = template
			}
		}
	}
	posargs := args[optind:]
	if len(posargs) > 1 {
		return "", errors.New("Usage: compose [-H] [body]")
		return "", errors.New("Usage: compose [-H] [-T template] [body]")
	}
	if len(posargs) == 1 {
		body = posargs[0]
@@ -78,3 +96,18 @@ func buildBody(args []string) (string, error) {
	}
	return body, nil
}

func readTemplateFromFile(templateName string, templateDir string)  (string, error) {
	if templateDir == "" {
		return "", errors.New("Template Directory is not set.")
	}
	templateFile, err := homedir.Expand(path.Join(templateDir, templateName))
	if err != nil {
		return "", errors.New("Error while expanding template path.")
	}
	template, err := ioutil.ReadFile(templateFile)
	if err != nil {
		return "", errors.New("Error while reading template.")
	}
	return string(template), nil
}
diff --git a/config/config.go b/config/config.go
index 133a7f4ed5ca..a7ca2f27aed2 100644
--- a/config/config.go
+++ b/config/config.go
@@ -59,6 +59,8 @@ type AccountConfig struct {
	OutgoingCredCmd string
	SignatureFile   string
	SignatureCmd    string
	TemplateDir     string
	DefaultTemplate string
}

type BindingConfig struct {
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index f4f02f2cb0f3..2be0c425a5c1 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -320,6 +320,13 @@ Note that many of these configuration options are written for you, such as
	signature to be added to emails sent from this account. If the command
	fails then *signature-file* is used instead.

*template-dir*
	Specifies the location of the folder containing email templates.

*default-template*
	Specifies the name of the default template used when no template
	is given as part of the compose command.

# BINDS.CONF

This file is used for configuring keybindings used in the aerc interactive
-- 
2.23.0
Nice work. I've added some comments and have a couple of questions:

Should other commands e.g. reply or forward have a template
available as well? If so, then it could be a good idea to put some of
this logic in a lib file.

Also, could you add docs for the command in doc/aerc.1.scd?
Okay, so you mentioned this in the ticket and went with the easier
approach - but hear me out. If we put this into the composor and make it
work for replies, we can generalize this nicely by using golang text
templates. Then, the default reply template becomes something like this:

On {{.Date}}, {{.From.Name}} wrote:
{{quote(.Original)}}

{{cursor()}}

I don't recall exactly how text templates work, but something like this.
The quote function would quote and wrap the original email at 72
columns, and the cursor() function would emit an empty string but would
magically record the current index and move the cursor there.

Thoughts?
View this thread in the archives