Compare commits

..

2 commits

5 changed files with 126 additions and 0 deletions

View file

@ -0,0 +1,36 @@
package compose
import (
"fmt"
"git.sr.ht/~rjarry/aerc/widgets"
)
type MarkUp struct{}
func init() {
register(MarkUp{})
}
func (MarkUp) Aliases() []string {
return []string{"markup"}
}
func (MarkUp) Complete(aerc *widgets.Aerc, args []string) []string {
composer, _ := aerc.SelectedTabContent().(*widgets.Composer)
return composer.GetMarkups()
}
func (MarkUp) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return fmt.Errorf("Usage: :markup <label>")
}
markupKey := args[1]
composer, _ := aerc.SelectedTabContent().(*widgets.Composer)
if err := composer.GenerateMarkup(markupKey); err != nil {
aerc.PushError(err.Error())
return err
} else {
aerc.PushSuccess(fmt.Sprintf("Markup generated"))
}
return nil
}

View file

@ -253,6 +253,11 @@ type TemplateConfig struct {
Forwards string `ini:"forwards"` Forwards string `ini:"forwards"`
} }
type MarkupConfig struct {
Name string
Cmd string
}
type AercConfig struct { type AercConfig struct {
Bindings BindingConfig Bindings BindingConfig
ContextualBinds []BindingConfigContext ContextualBinds []BindingConfigContext
@ -267,6 +272,7 @@ type AercConfig struct {
ContextualUis []UIConfigContext ContextualUis []UIConfigContext
General GeneralConfig General GeneralConfig
Templates TemplateConfig Templates TemplateConfig
Markups []MarkupConfig
Openers map[string][]string Openers map[string][]string
} }
@ -616,6 +622,17 @@ func (config *AercConfig) LoadConfig(file *ini.File) error {
} }
} }
if markupsSec, err := file.GetSection("markups"); err == nil {
for _, markupKey := range markupsSec.KeyStrings() {
markupCmd := markupsSec.KeysHash()[markupKey]
mark := MarkupConfig{
Name: markupKey,
Cmd: markupCmd,
}
config.Markups = append(config.Markups, mark)
}
}
// append default paths to template-dirs and styleset-dirs // append default paths to template-dirs and styleset-dirs
for _, dir := range SearchDirs { for _, dir := range SearchDirs {
config.Ui.StyleSetDirs = append( config.Ui.StyleSetDirs = append(

View file

@ -602,6 +602,22 @@ text/plain=gvim {} +125
message/rfc822=thunderbird message/rfc822=thunderbird
``` ```
## MARKUPS
Markups allows you to pipe the content of a message being composed through a
shell command to generate HTML markup from the plaintext message. Markups
can be defined in *[markups]* section within aerc.conf.
Example:
```
[markups]
work=pandoc -f markdown -t html --template=company.tpl
```
The command *:markup* becomes available during the compose-review stage, and
will only append text/html part to the email if the shell command exits
successfully and content is written to standard output.
## TRIGGERS ## TRIGGERS
Triggers specify commands to execute when certain events occur. Triggers specify commands to execute when certain events occur.

View file

@ -500,6 +500,12 @@ message list, the message in the message viewer, etc).
*edit* *edit*
(Re-) opens your text editor to edit the message in progress. (Re-) opens your text editor to edit the message in progress.
*markup* <label>
Passes the message to external command, and appends result as text/html
message part. The label and command is defined under the *markups* section
configuration. For details on configuring markup support consult
*aerc-config*(5).
*next-field*, *prev-field* *next-field*, *prev-field*
Cycles between input fields in the compose window. Cycles between input fields in the compose window.

View file

@ -529,6 +529,57 @@ func (c *Composer) readSignatureFromFile() []byte {
return signature return signature
} }
func (c *Composer) GenerateMarkup(markupKey string) error {
markupCmd, err := c.getMarkupCmdByName(markupKey)
if err != nil {
return err
}
proc := exec.Command("sh", "-c", markupCmd)
stdin, err := proc.StdinPipe()
if err != nil {
return err
}
go func() {
defer stdin.Close()
_, err := c.email.Seek(0, io.SeekStart)
if err != nil {
logging.Warnf("failed to seek beginning of mail: %v", err)
return
}
io.Copy(stdin, c.email)
}()
outBytes, err := proc.Output()
if err != nil {
return err
}
if len(outBytes) < 1 {
return fmt.Errorf("markup %s did not generate content", markupKey)
}
ioReader := bytes.NewReader(outBytes)
return c.AppendPart("text/html", nil, ioReader)
}
func (c *Composer) GetMarkups() []string {
if len(c.config.Markups) < 1 {
return nil
}
markupKeys := []string{}
for _, cmd := range c.config.Markups {
markupKeys = append(markupKeys, cmd.Name)
}
return markupKeys
}
func (c *Composer) getMarkupCmdByName(markupKey string) (string, error) {
for _, markupConfig := range c.config.Markups {
if markupConfig.Name == markupKey {
return markupConfig.Cmd, nil
}
}
return "", fmt.Errorf("unknown markup label %s", markupKey)
}
func (c *Composer) FocusTerminal() *Composer { func (c *Composer) FocusTerminal() *Composer {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()