aboutsummaryrefslogtreecommitdiff
path: root/widgets
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-03-31 12:14:37 -0400
committerDrew DeVault <sir@cmpwn.com>2019-03-31 12:14:37 -0400
commit27b25174e2f0249a6a1d4ba45b70f8504b63ffb1 (patch)
treeb8626c746e07d9a38f95a5a817a7094c9275bfd1 /widgets
parent143289bbd0736d72553a3c2a080aa3d125366b38 (diff)
Make the message viewer real, part one
Diffstat (limited to 'widgets')
-rw-r--r--widgets/aerc.go2
-rw-r--r--widgets/msgviewer.go172
2 files changed, 54 insertions, 120 deletions
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 781cb2b..773848d 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -62,8 +62,6 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
tabs.Add(view, acct.Name)
}
- tabs.Add(NewMessageViewer(), "[PATCH todo.sr.ht v2 …")
-
return aerc
}
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index ecfac3b..2c77aeb 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -2,124 +2,58 @@ package widgets
import (
"bytes"
+ "fmt"
"io"
"os/exec"
+ "github.com/emersion/go-imap"
"github.com/gdamore/tcell"
"github.com/mattn/go-runewidth"
+ "git.sr.ht/~sircmpwn/aerc2/lib"
"git.sr.ht/~sircmpwn/aerc2/lib/ui"
+ "git.sr.ht/~sircmpwn/aerc2/worker/types"
)
type MessageViewer struct {
+ mail io.Reader
+ pipe io.Writer
grid *ui.Grid
term *Terminal
}
-var testMsg = `Makes the following changes to the Event type:
-
-* make 'user' and 'ticket' nullable since some events require it
-* add 'by_user' and 'from_ticket' to enable mentions
-* remove 'assinged_user' which is no longer used
-
-Ticket: https://todo.sr.ht/~sircmpwn/todo.sr.ht/156
----
- tests/test_comments.py | 23 ++-
- .../versions/75ff2f7624fd_new_event_fields.py | 142 ++++++++++++++++++
- todosrht/templates/events.html | 18 ++-
- todosrht/templates/ticket.html | 31 +++-
- todosrht/tickets.py | 14 +-
- todosrht/types/event.py | 16 +-
- 6 files changed, 207 insertions(+), 37 deletions(-)
- create mode 100644 todosrht/alembic/versions/75ff2f7624fd_new_event_fields.py
-
-diff --git a/tests/test_comments.py b/tests/test_comments.py
-index 4b3161d..b85d751 100644
---- a/tests/test_comments.py
-+++ b/tests/test_comments.py
-@@ -253,20 +253,25 @@ def test_notifications_and_events(mailbox):
- # Check correct events are generated
- comment_events = {e for e in ticket.events
- if e.event_type == EventType.comment}
-- user_events = {e for e in ticket.events
-+ u1_events = {e for e in u1.events
-+ if e.event_type == EventType.user_mentioned}
-+ u2_events = {e for e in u2.events
- if e.event_type == EventType.user_mentioned}
-
- assert len(comment_events) == 1
-- assert len(user_events) == 2
-+ assert len(u1_events) == 1
-+ assert len(u2_events) == 1
-
-- u1_mention = next(e for e in user_events if e.user == u1)
-- u2_mention = next(e for e in user_events if e.user == u2)
-+ u1_mention = u1_events.pop()
-+ u2_mention = u2_events.pop()
-
- assert u1_mention.comment == comment
-- assert u1_mention.ticket == ticket
-+ assert u1_mention.from_ticket == ticket
-+ assert u1_mention.by_user == commenter
-
- assert u2_mention.comment == comment
-- assert u2_mention.ticket == ticket
-+ assert u2_mention.from_ticket == ticket
-+ assert u2_mention.by_user == commenter
-
- assert len(t1.events) == 1
- assert len(t2.events) == 1
-@@ -276,10 +281,12 @@ def test_notifications_and_events(mailbox):
- t2_mention = t2.events[0]
-
- assert t1_mention.comment == comment
-- assert t1_mention.user == commenter
-+ assert t1_mention.from_ticket == ticket
-+ assert t1_mention.by_user == commenter
-
- assert t2_mention.comment == comment
-- assert t2_mention.user == commenter
-+ assert t2_mention.from_ticket == ticket
-+ assert t2_mention.by_user == commenter
+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()
+}
- def test_ticket_mention_pattern():
- def match(text):
-diff --git a/todosrht/alembic/versions/75ff2f7624fd_new_event_fields.py
-b/todosrht/alembic/versions/75ff2f7624fd_new_event_fields.py
-new file mode 100644
-index 0000000..1c55bfe
---- /dev/null
-+++ b/todosrht/alembic/versions/75ff2f7624fd_new_event_fields.py
-@@ -0,0 +1,142 @@
-+"""Add new event fields and migrate data.
-+
-+Also makes Event.ticket_id and Event.user_id nullable since some these fields
-+can be empty for mention events.
-+
-+Revision ID: 75ff2f7624fd
-+Revises: c7146cb70d6b
-+Create Date: 2019-03-28 16:26:18.714300
-+
-+"""
-+
-+# revision identifiers, used by Alembic.
-+revision = "75ff2f7624fd"
-+down_revision = "c7146cb70d6b"
-`
+func NewMessageViewer(store *lib.MessageStore,
+ msg *types.MessageInfo) *MessageViewer {
-func NewMessageViewer() *MessageViewer {
grid := ui.NewGrid().Rows([]ui.GridSpec{
- {ui.SIZE_EXACT, 4},
+ {ui.SIZE_EXACT, 3}, // TODO: Based on number of header rows
{ui.SIZE_WEIGHT, 1},
}).Columns([]ui.GridSpec{
{ui.SIZE_WEIGHT, 1},
})
+ // TODO: let user specify additional headers to show by default
headers := ui.NewGrid().Rows([]ui.GridSpec{
{ui.SIZE_EXACT, 1},
{ui.SIZE_EXACT, 1},
{ui.SIZE_EXACT, 1},
- {ui.SIZE_EXACT, 1},
}).Columns([]ui.GridSpec{
{ui.SIZE_WEIGHT, 1},
{ui.SIZE_WEIGHT, 1},
@@ -127,25 +61,19 @@ func NewMessageViewer() *MessageViewer {
headers.AddChild(
&HeaderView{
Name: "From",
- Value: "Ivan Habunek <ivan@habunek.com>",
+ Value: formatAddresses(msg.Envelope.From),
}).At(0, 0)
headers.AddChild(
&HeaderView{
Name: "To",
- Value: "~sircmpwn/sr.ht-dev@lists.sr.ht",
+ Value: formatAddresses(msg.Envelope.To),
}).At(0, 1)
headers.AddChild(
&HeaderView{
- Name: "Subject",
- Value: "[PATCH todo.sr.ht v2 1/3 Alter Event fields " +
- "and migrate data]",
+ Name: "Subject",
+ Value: msg.Envelope.Subject,
}).At(1, 0).Span(1, 2)
- headers.AddChild(
- &HeaderView{
- Name: "PGP",
- Value: "✓ Valid PGP signature from Ivan Habunek",
- }).At(2, 0).Span(1, 2)
- headers.AddChild(ui.NewFill(' ')).At(3, 0).Span(1, 2)
+ headers.AddChild(ui.NewFill(' ')).At(2, 0).Span(1, 2)
body := ui.NewGrid().Rows([]ui.GridSpec{
{ui.SIZE_WEIGHT, 1},
@@ -154,25 +82,30 @@ func NewMessageViewer() *MessageViewer {
{ui.SIZE_EXACT, 20},
})
- cmd := exec.Command("sh", "-c", "./contrib/hldiff.py | less -R")
+ cmd := exec.Command("less")
pipe, _ := cmd.StdinPipe()
term, _ := NewTerminal(cmd)
- term.OnStart = func() {
+ // TODO: configure multipart view. I left a spot for it in the grid
+ body.AddChild(term).At(0, 0).Span(1, 2)
+
+ grid.AddChild(headers).At(0, 0)
+ grid.AddChild(body).At(1, 0)
+
+ viewer := &MessageViewer{
+ pipe: pipe,
+ grid: grid,
+ term: term,
+ }
+
+ store.FetchBodyPart(msg.Uid, 0, func(reader io.Reader) {
+ viewer.mail = reader
go func() {
- reader := bytes.NewBufferString(testMsg)
io.Copy(pipe, reader)
pipe.Close()
}()
- }
- term.Focus(true)
- body.AddChild(term).At(0, 0)
-
- body.AddChild(ui.NewBordered(
- &MultipartView{}, ui.BORDER_LEFT)).At(0, 1)
+ })
- grid.AddChild(headers).At(0, 0)
- grid.AddChild(body).At(1, 0)
- return &MessageViewer{grid, term}
+ return viewer
}
func (mv *MessageViewer) Draw(ctx *ui.Context) {
@@ -205,7 +138,10 @@ type HeaderView struct {
}
func (hv *HeaderView) Draw(ctx *ui.Context) {
- size := runewidth.StringWidth(hv.Name)
+ name := hv.Name
+ size := runewidth.StringWidth(name)
+ lim := ctx.Width() - size - 1
+ value := runewidth.Truncate(" "+hv.Value, lim, "…")
var (
hstyle tcell.Style
vstyle tcell.Style
@@ -219,8 +155,8 @@ func (hv *HeaderView) Draw(ctx *ui.Context) {
hstyle = tcell.StyleDefault.Bold(true)
}
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', vstyle)
- ctx.Printf(0, 0, hstyle, hv.Name)
- ctx.Printf(size, 0, vstyle, " "+hv.Value)
+ ctx.Printf(0, 0, hstyle, name)
+ ctx.Printf(size, 0, vstyle, value)
}
func (hv *HeaderView) Invalidate() {