-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
history.go
149 lines (135 loc) · 3.67 KB
/
history.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2019 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.
package main
import (
"context"
"fmt"
"io"
"log"
"strings"
"time"
"github.com/rivo/tview"
"mellium.im/communique/internal/client/event"
"mellium.im/communique/internal/storage"
"mellium.im/communique/internal/ui"
"mellium.im/xmpp/roster"
"mellium.im/xmpp/stanza"
"mellium.im/xmpp/styling"
)
/* #nosec */
func writeMask(buf *strings.Builder, mask styling.Style) {
// Reset all styles, then rewrite the one we want.
buf.WriteString("[::-]")
if mask&styling.BlockEndDirective != 0 {
return
}
buf.WriteString("[::")
if mask&styling.SpanEmph == styling.SpanEmph {
buf.WriteString("i")
}
if mask&styling.SpanStrong == styling.SpanStrong {
buf.WriteString("b")
}
if mask&styling.SpanStrike == styling.SpanStrike {
buf.WriteString("s")
}
if mask&styling.Directive != 0 || mask&styling.SpanPre == styling.SpanPre {
buf.WriteString("d")
}
buf.WriteString("]")
}
func writeMessage(pane *ui.UI, configPath string, msg event.ChatMessage, notNew bool) error {
if msg.Body == "" {
return nil
}
historyAddr := msg.From
arrow := "←"
if msg.Sent {
historyAddr = msg.To
arrow = "→"
}
var buf strings.Builder
var prevEnd bool
msg.Body = tview.Escape(msg.Body)
d := styling.NewDecoder(strings.NewReader(msg.Body))
for d.Next() {
tok := d.Token()
if prevEnd || tok.Mask != 0 {
prevEnd = false
writeMask(&buf, tok.Mask)
}
/* #nosec */
buf.Write(tok.Data)
if tok.Mask&styling.SpanEndDirective != 0 {
prevEnd = true
}
}
buf.WriteString("[::-]")
var historyLine string
if msg.Type == stanza.GroupChatMessage {
j := msg.From
if msg.Sent {
j = msg.To
}
historyLine = fmt.Sprintf("%s %s [%s] %s\n", time.Now().UTC().Format(time.RFC3339), arrow, tview.Escape(j.Resourcepart()), buf.String())
} else {
historyLine = fmt.Sprintf("%s %s %s\n", time.Now().UTC().Format(time.RFC3339), arrow, buf.String())
}
history := pane.History()
j := historyAddr.Bare()
if pane.ChatsOpen() {
if selected := pane.GetRosterJID(); j.Equal(selected) {
// If the message JID is selected and the window is open, write it to the
// history window.
_, err := io.WriteString(history, historyLine)
return err
}
}
// If it's not selected (or the message window is not open), mark the item as
// unread in the roster and recent conversations view.
// If the message isn't a new one (we're just loading history), skip all this.
if !msg.Sent && !notNew {
ok := pane.Roster().MarkUnread(j.String(), msg.ID)
if !ok {
// If the item did not exist, create it then try to mark it as unread
// again.
pane.UpdateConversations(ui.Conversation{
JID: j,
// TODO: get the preferred nickname.
Name: j.Localpart(),
})
pane.Roster().MarkUnread(j.String(), msg.ID)
}
pane.Redraw()
}
return nil
}
func loadBuffer(ctx context.Context, pane *ui.UI, db *storage.DB, configPath string, ev roster.Item, msgID string, logger *log.Logger) error {
history := pane.History()
history.SetText("")
iter := db.QueryHistory(ctx, ev.JID.String(), "")
for iter.Next() {
cur := iter.Message()
if cur.ID != "" && cur.ID == msgID {
_, err := io.WriteString(history, "─\n")
if err != nil {
return err
}
}
err := writeMessage(pane, configPath, cur, true)
if err != nil {
err = fmt.Errorf("error writing history: %w", err)
history.SetText(err.Error())
logger.Println(err)
return nil
}
}
if err := iter.Err(); err != nil {
history.SetText(err.Error())
err = fmt.Errorf("error querying history for %s: %w", ev.JID, err)
logger.Println(err)
}
history.ScrollToEnd()
return nil
}