aboutsummaryrefslogtreecommitdiffstats
path: root/lib/format
diff options
context:
space:
mode:
Diffstat (limited to 'lib/format')
-rw-r--r--lib/format/format.go319
1 files changed, 0 insertions, 319 deletions
diff --git a/lib/format/format.go b/lib/format/format.go
index 7466cfd5..9a675ef0 100644
--- a/lib/format/format.go
+++ b/lib/format/format.go
@@ -1,14 +1,12 @@
package format
import (
- "errors"
"fmt"
"regexp"
"strings"
"time"
"unicode"
- "git.sr.ht/~rjarry/aerc/models"
"github.com/emersion/go-message/mail"
"github.com/mattn/go-runewidth"
"github.com/rivo/uniseg"
@@ -110,323 +108,6 @@ func ShellQuote(args []string) string {
return strings.Join(quoted, " ")
}
-type Ctx struct {
- FromAddress string
- AccountName string
- MsgNum int
- MsgInfo *models.MessageInfo
- MsgIsMarked bool
-
- // UI controls for threading
- ThreadPrefix string
- ThreadSameSubject bool
-}
-
-func ParseMessageFormat(format string, timeFmt string, thisDayTimeFmt string,
- thisWeekTimeFmt string, thisYearTimeFmt string, iconAttachment string, ctx Ctx) (
- string, []interface{}, error,
-) {
- if ctx.MsgInfo.Error != nil {
- return "", nil,
- errors.New("(unable to fetch header)")
- }
- retval := make([]byte, 0, len(format))
- var args []interface{}
-
- accountFromAddress, err := mail.ParseAddress(ctx.FromAddress)
- if err != nil {
- return "", nil, err
- }
-
- envelope := ctx.MsgInfo.Envelope
- if envelope == nil {
- return "", nil,
- errors.New("no envelope available for this message")
- }
-
- var c rune
- for i, ni := 0, 0; i < len(format); {
- ni = strings.IndexByte(format[i:], '%')
- if ni < 0 {
- ni = len(format)
- retval = append(retval, []byte(format[i:ni])...)
- break
- }
- ni += i + 1
- // Check for fmt flags
- if ni == len(format) {
- goto handle_end_error
- }
- c = rune(format[ni])
- if c == '+' || c == '-' || c == '#' || c == ' ' || c == '0' {
- ni++
- }
-
- // Check for precision and width
- if ni == len(format) {
- goto handle_end_error
- }
- c = rune(format[ni])
- for unicode.IsDigit(c) {
- ni++
- c = rune(format[ni])
- }
- if c == '.' {
- ni++
- c = rune(format[ni])
- for unicode.IsDigit(c) {
- ni++
- c = rune(format[ni])
- }
- }
-
- retval = append(retval, []byte(format[i:ni])...)
- // Get final format verb
- if ni == len(format) {
- goto handle_end_error
- }
- c = rune(format[ni])
- switch c {
- case '%':
- retval = append(retval, '%')
- case 'a':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := envelope.From[0]
- retval = append(retval, 's')
- args = append(args, addr.Address)
- case 'A':
- var addr *mail.Address
- if len(envelope.ReplyTo) == 0 {
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender or reply-to")
- } else {
- addr = envelope.From[0]
- }
- } else {
- addr = envelope.ReplyTo[0]
- }
- retval = append(retval, 's')
- args = append(args, addr.Address)
- case 'C':
- retval = append(retval, 'd')
- args = append(args, ctx.MsgNum)
- case 'd':
- date := envelope.Date
- if date.IsZero() {
- date = ctx.MsgInfo.InternalDate
- }
- retval = append(retval, 's')
- args = append(args,
- DummyIfZeroDate(date.Local(),
- timeFmt, thisDayTimeFmt,
- thisWeekTimeFmt, thisYearTimeFmt))
- case 'D':
- date := envelope.Date
- if date.IsZero() {
- date = ctx.MsgInfo.InternalDate
- }
- retval = append(retval, 's')
- args = append(args,
- DummyIfZeroDate(date.Local(),
- timeFmt, thisDayTimeFmt,
- thisWeekTimeFmt, thisYearTimeFmt))
- case 'f':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := AddressForHumans(envelope.From[0])
- retval = append(retval, 's')
- args = append(args, addr)
- case 'F':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := envelope.From[0]
- var val string
-
- if addr.Name == accountFromAddress.Name && len(envelope.To) != 0 {
- addr = envelope.To[0]
- }
-
- if addr.Name != "" {
- val = addr.Name
- } else {
- val = addr.Address
- }
- retval = append(retval, 's')
- args = append(args, val)
-
- case 'g':
- retval = append(retval, 's')
- args = append(args, strings.Join(ctx.MsgInfo.Labels, ", "))
-
- case 'i':
- retval = append(retval, 's')
- args = append(args, envelope.MessageId)
- case 'n':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := envelope.From[0]
- var val string
- if addr.Name != "" {
- val = addr.Name
- } else {
- val = addr.Address
- }
- retval = append(retval, 's')
- args = append(args, val)
- case 'r':
- addrs := FormatAddresses(envelope.To)
- retval = append(retval, 's')
- args = append(args, addrs)
- case 'R':
- addrs := FormatAddresses(envelope.Cc)
- retval = append(retval, 's')
- args = append(args, addrs)
- case 's':
- retval = append(retval, 's')
- // if we are threaded strip the repeated subjects unless it's the
- // first on the screen
- subject := envelope.Subject
- if ctx.ThreadSameSubject {
- subject = ""
- }
- args = append(args, ctx.ThreadPrefix+subject)
- case 't':
- if len(envelope.To) == 0 {
- return "", nil,
- errors.New("found no address for recipient")
- }
- addr := envelope.To[0]
- retval = append(retval, 's')
- args = append(args, addr.Address)
- case 'T':
- retval = append(retval, 's')
- args = append(args, ctx.AccountName)
- case 'u':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := envelope.From[0]
- mailbox := addr.Address // fallback if there's no @ sign
- if split := strings.SplitN(addr.Address, "@", 2); len(split) == 2 {
- mailbox = split[1]
- }
- retval = append(retval, 's')
- args = append(args, mailbox)
- case 'v':
- if len(envelope.From) == 0 {
- return "", nil,
- errors.New("found no address for sender")
- }
- addr := envelope.From[0]
- // check if message is from current user
- if addr.Name != "" {
- retval = append(retval, 's')
- args = append(args,
- strings.Split(addr.Name, " ")[0])
- }
- case 'Z':
- // calculate all flags
- flags := ctx.MsgInfo.Flags
- f := ""
-
- switch {
- case flags.Has(models.SeenFlag | models.AnsweredFlag):
- f += "r" // message has been replied to
- case flags.Has(models.SeenFlag):
- break
- case flags.Has(models.RecentFlag):
- f += "N" // message is new
- default:
- f += "O" // message is old
- }
- if flags.Has(models.DeletedFlag) {
- f += "D"
- }
- for _, bS := range ctx.MsgInfo.BodyStructure.Parts {
- if strings.ToLower(bS.Disposition) == "attachment" {
- f += iconAttachment
- break
- }
- }
- if flags.Has(models.FlaggedFlag) {
- f += "!"
- }
- if ctx.MsgIsMarked {
- f += "*"
- }
- retval = append(retval, '4', 's')
- args = append(args, f)
-
- // Move the below cases to proper alphabetical positions once
- // implemented
- case 'l':
- // TODO: number of lines in the message
- retval = append(retval, 'd')
- args = append(args, ctx.MsgInfo.Size)
- case 'e':
- // TODO: current message number in thread
- fallthrough
- case 'E':
- // TODO: number of messages in current thread
- fallthrough
- case 'H':
- // TODO: spam attribute(s) of this message
- fallthrough
- case 'L':
- // TODO:
- fallthrough
- case 'X':
- // TODO: number of attachments
- fallthrough
- case 'y':
- // TODO: X-Label field
- fallthrough
- case 'Y':
- // TODO: X-Label field and some other constraints
- fallthrough
- default:
- // Just ignore it and print as is
- // so %k in index format becomes %%k to Printf
- retval = append(retval, '%')
- retval = append(retval, byte(c))
- }
- i = ni + 1
- }
-
- const zeroWidthSpace rune = '\u200b'
- for i, val := range args {
- if s, ok := val.(string); ok {
- var out strings.Builder
- for _, r := range s {
- w := runewidth.RuneWidth(r)
- for w > 1 {
- out.WriteRune(zeroWidthSpace)
- w -= 1
- }
- out.WriteRune(r)
- }
- args[i] = out.String()
- }
- }
-
- return string(retval), args, nil
-
-handle_end_error:
- return "", nil,
- errors.New("reached end of string while parsing message format")
-}
-
func DummyIfZeroDate(date time.Time, format string, todayFormat string,
thisWeekFormat string, thisYearFormat string,
) string {