~sircmpwn/aerc

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH] implement index format to display message list in an organized manner

Details
Message ID
<20190606130309.7043-1-yash111998@gmail.com>
Sender timestamp
1559826189
DKIM signature
missing
Download raw message
Patch: +237 -6
---
 config/aerc.conf.in |   6 +-
 config/config.go    |   4 +-
 lib/indexformat.go  | 230 ++++++++++++++++++++++++++++++++++++++++++++
 widgets/msglist.go  |   3 +-
 4 files changed, 237 insertions(+), 6 deletions(-)
 create mode 100644 lib/indexformat.go

diff --git a/config/aerc.conf.in b/config/aerc.conf.in
index 090e624..6d352ab 100644
--- a/config/aerc.conf.in
+++ b/config/aerc.conf.in
@@ -10,10 +10,10 @@
index-format=%4C %Z %D %-17.17n %s

#
# See strftime(3)
# See time.Time#Format
#
# Default: %F %l:%M %p (ISO 8501 + 12 hour time)
timestamp-format=%F %l:%M %p
# Default: 2006-01-02 03:04 PM (ISO 8501 + 12 hour time)
timestamp-format=2006-01-02 03:04 PM

#
# Width of the sidebar, including the border.
diff --git a/config/config.go b/config/config.go
index 1fb764b..600c0ba 100644
--- a/config/config.go
+++ b/config/config.go
@@ -242,8 +242,8 @@ func LoadConfig(root *string, sharedir string) (*AercConfig, error) {
		Ini: file,

		Ui: UIConfig{
			IndexFormat:     "%4C %Z %D %-17.17n %s",
			TimestampFormat: "%F %l:%M %p",
			IndexFormat:     "%4C %Z %D %-17.17F %s",
			TimestampFormat: "2006-01-02 03:04 PM",
			ShowHeaders: []string{
				"From", "To", "Cc", "Bcc", "Subject", "Date",
			},
diff --git a/lib/indexformat.go b/lib/indexformat.go
new file mode 100644
index 0000000..fdda953
--- /dev/null
+++ b/lib/indexformat.go
@@ -0,0 +1,230 @@
package lib

import (
	"bytes"
	"fmt"
	"strings"
	"unicode"

	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc/config"
	"git.sr.ht/~sircmpwn/aerc/worker/types"
)

func ParseIndexFormat(conf *config.AercConfig, number int, msg *types.MessageInfo) (string, []interface{}) {
	format := conf.Ui.IndexFormat
	retval := make([]byte, 0, len(format))
	var args []interface{}

	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
		ni++
		// Check for fmt flags
		if ni == len(format) {
			goto handle_error
		}
		c = rune(format[ni])
		if c == '+' || c == '-' || c == '#' || c == ' ' || c == '0' {
			ni++
		}

		// Check for precision and width
		if ni == len(format) {
			goto handle_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_error
		}
		c = rune(format[ni])
		switch c {
		case '%':
			retval = append(retval, '%')
		case 'a':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := msg.Envelope.From[0]
			retval = append(retval, 's')
			args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName,
				addr.HostName))
		case 'A':
			var addr *imap.Address
			if len(msg.Envelope.ReplyTo) == 0 {
				if len(msg.Envelope.From) == 0 {
					goto handle_error
				} else {
					addr = msg.Envelope.From[0]
				}
			} else {
				addr = msg.Envelope.ReplyTo[0]
			}
			retval = append(retval, 's')
			args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName,
				addr.HostName))
		case 'C':
			retval = append(retval, 'd')
			args = append(args, number)
		case 'd':
			retval = append(retval, 's')
			args = append(args, msg.InternalDate.Format(conf.Ui.TimestampFormat))
		case 'D':
			retval = append(retval, 's')
			args = append(args, msg.InternalDate.Local().Format(conf.Ui.TimestampFormat))
		case 'e':
			// TODO: current message number in thread
		case 'E':
			// TODO: number of messages in current thread
		case 'f':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := formatAddresses(msg.Envelope.From[0:1])
			retval = append(retval, 's')
			args = append(args, addr)
		case 'F':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := msg.Envelope.From[0]
			// TODO: handle case when sender is you. Then
			// use recipient's name
			var val string
			if addr.PersonalName != "" {
				val = addr.PersonalName
			} else {
				val = fmt.Sprintf("%s@%s",
					addr.MailboxName, addr.HostName)
			}
			retval = append(retval, 's')
			args = append(args, val)

		case 'H':
			// TODO: spam attribute(s) of this message
		case 'i':
			retval = append(retval, 's')
			args = append(args, msg.Envelope.MessageId)
		case 'l':
			// TODO: number of lines in the message
			retval = append(retval, 'd')
			args = append(args, msg.Size)
		case 'L':
			// TODO:
		case 'n':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := msg.Envelope.From[0]
			var val string
			if addr.PersonalName != "" {
				val = addr.PersonalName
			} else {
				val = fmt.Sprintf("%s@%s",
					addr.MailboxName, addr.HostName)
			}
			retval = append(retval, 's')
			args = append(args, val)
		case 'r':
			addrs := formatAddresses(msg.Envelope.To)
			retval = append(retval, 's')
			args = append(args, addrs)
		case 'R':
			addrs := formatAddresses(msg.Envelope.Cc)
			retval = append(retval, 's')
			args = append(args, addrs)
		case 's':
			retval = append(retval, 's')
			args = append(args, msg.Envelope.Subject)
		case 'u':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := msg.Envelope.From[0]
			retval = append(retval, 's')
			args = append(args, addr.MailboxName)
		case 'v':
			if len(msg.Envelope.From) == 0 {
				goto handle_error
			}
			addr := msg.Envelope.From[0]
			// check if message is form current user
			if addr.PersonalName != "" {
				retval = append(retval, 's')
				args = append(args, strings.Split(addr.PersonalName, " ")[0])
			}
		case 'X':
			// TODO: number of attachments
		case 'y':
			// TODO: X-Label field
		case 'Y':
		// TODO: X-Label field and some other constraints
		case 'Z':
			// calculate all flags
			var readFlag = ""
			var delFlag = ""
			var flaggedFlag = ""
			for _, flag := range msg.Flags {
				if flag == "\\Seen" {
					readFlag = "O" // message is old
				} else if flag == "\\Recent" {
					readFlag = "N" // message is new
				} else if flag == "\\Answered" {
					readFlag = "r" // message has been replied to
				} else if flag == "\\Deleted" {
					delFlag = "D"
					// TODO: check if attachments
				} else if flag == "\\Flagged" {
					flaggedFlag = "!"
				}
				// TODO: check gpg stuff
			}
			retval = append(retval, '3', 's')
			args = append(args, readFlag+delFlag+flaggedFlag)
		}
		i = ni + 1
	}

	return string(retval), args
handle_error:
	return "error: while parsing index format", nil
}

func formatAddresses(addrs []*imap.Address) string {
	val := bytes.Buffer{}
	for i, addr := range addrs {
		if addr.PersonalName != "" {
			val.WriteString(fmt.Sprintf("%s <%s@%s>",
				addr.PersonalName, addr.MailboxName, addr.HostName))
		} else {
			val.WriteString(fmt.Sprintf("%s@%s",
				addr.MailboxName, addr.HostName))
		}
		if i != len(addrs)-1 {
			val.WriteString(", ")
		}
	}
	return val.String()
}
diff --git a/widgets/msglist.go b/widgets/msglist.go
index caa868f..5188540 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -80,7 +80,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
			style = style.Foreground(tcell.ColorGray)
		}
		ctx.Fill(0, row, ctx.Width(), 1, ' ', style)
		ctx.Printf(0, row, style, "%s", msg.Envelope.Subject)
		fmtStr, args := lib.ParseIndexFormat(ml.conf, i, msg)
		ctx.Printf(0, row, style, fmtStr, args...)

		row += 1
	}
-- 
2.21.0

Re: [PATCH] implement index format to display message list in an organized manner

Details
Message ID
<BUMP2GYHBDNM.16DDFWUTXGJTE@T440p>
In-Reply-To
<20190606130309.7043-1-yash111998@gmail.com> (view parent)
Sender timestamp
1559828535
DKIM signature
missing
Download raw message
On Thu Jun 6, 2019 at 6:33 PM Yash Srivastav wrote:
> +++ b/config/aerc.conf.in
> @@ -10,10 +10,10 @@
>  index-format=%4C %Z %D %-17.17n %s
>  
>  #
> -# See strftime(3)
> +# See time.Time#Format
>  #
> -# Default: %F %l:%M %p (ISO 8501 + 12 hour time)
> -timestamp-format=%F %l:%M %p
> +# Default: 2006-01-02 03:04 PM (ISO 8501 + 12 hour time)
> +timestamp-format=2006-01-02 03:04 PM

Probably should also correct the comment to say "ISO 8601" instead of
"ISO 8501" (the latter is about working with steel rather than computer
date formats).

Re: [PATCH] implement index format to display message list in an organized manner

Details
Message ID
<BUNJB1GWNI0X.22O9Z08SKGU1Q@homura>
In-Reply-To
<20190606130309.7043-1-yash111998@gmail.com> (view parent)
Sender timestamp
1559913840
DKIM signature
missing
Download raw message
This looks pretty good! A few comments, though.

On Thu Jun 6, 2019 at 6:33 PM Yash Srivastav wrote:
> diff --git a/config/aerc.conf.in b/config/aerc.conf.in
> index 090e624..6d352ab 100644
> --- a/config/aerc.conf.in
> +++ b/config/aerc.conf.in
> @@ -10,10 +10,10 @@
>  index-format=%4C %Z %D %-17.17n %s

Let's make the default "%D %-17.17n %s" while we're here

> diff --git a/config/config.go b/config/config.go
> index 1fb764b..600c0ba 100644
> --- a/config/config.go
> +++ b/config/config.go
> @@ -242,8 +242,8 @@ func LoadConfig(root *string, sharedir string) (*AercConfig, error) {
>  		Ini: file,
>  
>  		Ui: UIConfig{
> -			IndexFormat:     "%4C %Z %D %-17.17n %s",
> -			TimestampFormat: "%F %l:%M %p",
> +			IndexFormat:     "%4C %Z %D %-17.17F %s",
> +			TimestampFormat: "2006-01-02 03:04 PM",

Here too

> diff --git a/lib/indexformat.go b/lib/indexformat.go
> new file mode 100644
> index 0000000..fdda953
> --- /dev/null
> +++ b/lib/indexformat.go
> -%<
> +func ParseIndexFormat(conf *config.AercConfig, number int, msg *types.MessageInfo) (string, []interface{}) {

This needs to be wrapped to 80 cols. We should also return an error, not
a string. errors.New("error message...")

> +		if ni < 0 {
> +			ni = len(format)
> +			retval = append(retval, []byte(format[i:ni])...)
> +			break
> +		}
> +		ni += i
> +		ni++

This can be simplified to ni += i + 1
Reply to thread Export thread (mbox)