aboutsummaryrefslogtreecommitdiff
path: root/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'widgets')
-rw-r--r--widgets/aerc.go18
-rw-r--r--widgets/msgviewer.go207
-rw-r--r--widgets/termhost.go52
3 files changed, 213 insertions, 64 deletions
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 3ba4e0d..a36db23 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -39,19 +39,11 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
{libui.SIZE_WEIGHT, 1},
{libui.SIZE_EXACT, 1},
}).Columns([]libui.GridSpec{
- {libui.SIZE_EXACT, conf.Ui.SidebarWidth},
{libui.SIZE_WEIGHT, 1},
})
- grid.AddChild(statusbar).At(2, 1)
- // Minor hack
- grid.AddChild(libui.NewBordered(
- libui.NewFill(' '), libui.BORDER_RIGHT)).At(2, 0)
-
- grid.AddChild(libui.NewText("aerc").
- Strategy(libui.TEXT_CENTER).
- Reverse(true))
- grid.AddChild(tabs.TabStrip).At(0, 1)
- grid.AddChild(tabs.TabContent).At(1, 0).Span(1, 2)
+ grid.AddChild(tabs.TabStrip)
+ grid.AddChild(tabs.TabContent).At(1, 0)
+ grid.AddChild(statusbar).At(2, 0)
aerc := &Aerc{
accounts: make(map[string]*AccountView),
@@ -70,6 +62,8 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
tabs.Add(view, acct.Name)
}
+ tabs.Add(NewMessageViewer(), "[PATCH todo.sr.ht v2 …")
+
return aerc
}
@@ -99,7 +93,7 @@ func (aerc *Aerc) getBindings() *config.KeyBindings {
switch aerc.SelectedTab().(type) {
case *AccountView:
return aerc.conf.Bindings.MessageList
- case *TermHost:
+ case *Terminal:
return aerc.conf.Bindings.Terminal
default:
return aerc.conf.Bindings.Global
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
new file mode 100644
index 0000000..e94ece4
--- /dev/null
+++ b/widgets/msgviewer.go
@@ -0,0 +1,207 @@
+package widgets
+
+import (
+ "bytes"
+ "io"
+ "os/exec"
+
+ "github.com/gdamore/tcell"
+ "github.com/mattn/go-runewidth"
+
+ "git.sr.ht/~sircmpwn/aerc2/lib/ui"
+)
+
+type MessageViewer struct {
+ 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
+
+ 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() *MessageViewer {
+ grid := ui.NewGrid().Rows([]ui.GridSpec{
+ {ui.SIZE_EXACT, 3},
+ {ui.SIZE_WEIGHT, 1},
+ }).Columns([]ui.GridSpec{
+ {ui.SIZE_WEIGHT, 1},
+ })
+
+ headers := ui.NewGrid().Rows([]ui.GridSpec{
+ {ui.SIZE_EXACT, 1},
+ {ui.SIZE_EXACT, 1},
+ {ui.SIZE_EXACT, 1},
+ }).Columns([]ui.GridSpec{
+ {ui.SIZE_WEIGHT, 1},
+ {ui.SIZE_WEIGHT, 1},
+ })
+ headers.AddChild(
+ &HeaderView{
+ Name: "From",
+ Value: "Ivan Habunek <ivan@habunek.com>",
+ }).At(0, 0)
+ headers.AddChild(
+ &HeaderView{
+ Name: "To",
+ Value: "~sircmpwn/sr.ht-dev@lists.sr.ht",
+ }).At(0, 1)
+ headers.AddChild(
+ &HeaderView{
+ Name: "Subject",
+ Value: "[PATCH todo.sr.ht v2 1/3 Alter Event fields " +
+ "and migrate data]",
+ }).At(1, 0).Span(1, 2)
+ headers.AddChild(ui.NewFill(' ')).At(2, 0).Span(1, 2)
+
+ cmd := exec.Command("sh", "-c", "./contrib/hldiff.py | less -R")
+ pipe, _ := cmd.StdinPipe()
+ term, _ := NewTerminal(cmd)
+ term.OnStart = func() {
+ go func() {
+ reader := bytes.NewBufferString(testMsg)
+ io.Copy(pipe, reader)
+ pipe.Close()
+ }()
+ }
+ term.Focus(true)
+
+ grid.AddChild(headers).At(0, 0)
+ grid.AddChild(term).At(1, 0)
+ return &MessageViewer{grid, term}
+}
+
+func (mv *MessageViewer) Draw(ctx *ui.Context) {
+ mv.grid.Draw(ctx)
+}
+
+func (mv *MessageViewer) Invalidate() {
+ mv.grid.Invalidate()
+}
+
+func (mv *MessageViewer) OnInvalidate(fn func(d ui.Drawable)) {
+ mv.grid.OnInvalidate(func(_ ui.Drawable) {
+ fn(mv)
+ })
+}
+
+func (mv *MessageViewer) Event(event tcell.Event) bool {
+ return mv.term.Event(event)
+}
+
+func (mv *MessageViewer) Focus(focus bool) {
+ mv.term.Focus(focus)
+}
+
+type HeaderView struct {
+ onInvalidate func(d ui.Drawable)
+
+ Name string
+ Value string
+}
+
+func (hv *HeaderView) Draw(ctx *ui.Context) {
+ size := runewidth.StringWidth(" " + hv.Name + " ")
+ ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
+ style := tcell.StyleDefault.Reverse(true)
+ ctx.Printf(0, 0, style, " "+hv.Name+" ")
+ style = tcell.StyleDefault
+ ctx.Printf(size, 0, style, " "+hv.Value)
+}
+
+func (hv *HeaderView) Invalidate() {
+ if hv.onInvalidate != nil {
+ hv.onInvalidate(hv)
+ }
+}
+
+func (hv *HeaderView) OnInvalidate(fn func(d ui.Drawable)) {
+ hv.onInvalidate = fn
+}
diff --git a/widgets/termhost.go b/widgets/termhost.go
deleted file mode 100644
index 7898b44..0000000
--- a/widgets/termhost.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package widgets
-
-import (
- "github.com/gdamore/tcell"
-
- "git.sr.ht/~sircmpwn/aerc2/config"
- "git.sr.ht/~sircmpwn/aerc2/lib/ui"
-)
-
-type TermHost struct {
- grid *ui.Grid
- term *Terminal
-}
-
-// Thin wrapper around terminal which puts it in a grid and passes through
-// input events. A bit of a hack tbh
-func NewTermHost(term *Terminal, conf *config.AercConfig) *TermHost {
- grid := ui.NewGrid().Rows([]ui.GridSpec{
- {ui.SIZE_WEIGHT, 1},
- }).Columns([]ui.GridSpec{
- {ui.SIZE_EXACT, conf.Ui.SidebarWidth},
- {ui.SIZE_WEIGHT, 1},
- })
- grid.AddChild(term).At(0, 1)
- return &TermHost{grid, term}
-}
-
-func (th *TermHost) Draw(ctx *ui.Context) {
- th.grid.Draw(ctx)
-}
-
-func (th TermHost) Invalidate() {
- th.grid.Invalidate()
-}
-
-func (th *TermHost) OnInvalidate(fn func(d ui.Drawable)) {
- th.grid.OnInvalidate(func(_ ui.Drawable) {
- fn(th)
- })
-}
-
-func (th *TermHost) Event(event tcell.Event) bool {
- return th.term.Event(event)
-}
-
-func (th *TermHost) Focus(focus bool) {
- th.term.Focus(focus)
-}
-
-func (th *TermHost) Terminal() *Terminal {
- return th.term
-}