It compiles. Ship it!

This commit is contained in:
Tulir Asokan 2019-04-10 01:04:39 +03:00
parent dbee49476d
commit bbde121947
11 changed files with 113 additions and 152 deletions

View File

@ -34,8 +34,8 @@ type MatrixContainer interface {
Logout() Logout()
SendPreferencesToMatrix() SendPreferencesToMatrix()
SendMessage(roomID string, msgtype mautrix.MessageType, message string) (string, error) PrepareMarkdownMessage(roomID string, msgtype mautrix.MessageType, message string) *mautrix.Event
SendMarkdownMessage(roomID string, msgtype mautrix.MessageType, message string) (string, error) SendEvent(event *mautrix.Event) (string, error)
SendTyping(roomID string, typing bool) SendTyping(roomID string, typing bool)
MarkRead(roomID, eventID string) MarkRead(roomID, eventID string)
JoinRoom(roomID, server string) (*rooms.Room, error) JoinRoom(roomID, server string) (*rooms.Room, error)

View File

@ -53,14 +53,6 @@ type MainView interface {
InitialSyncDone() InitialSyncDone()
} }
type MessageDirection int
const (
AppendMessage MessageDirection = iota
PrependMessage
IgnoreMessage
)
type RoomView interface { type RoomView interface {
MxRoom() *rooms.Room MxRoom() *rooms.Room
@ -69,8 +61,7 @@ type RoomView interface {
UpdateUserList() UpdateUserList()
ParseEvent(evt *mautrix.Event) Message ParseEvent(evt *mautrix.Event) Message
AppendMessage(message Message) AddMessage(message Message)
MarkMessageFailed(message Message)
AddServiceMessage(message string) AddServiceMessage(message string)
} }
@ -81,4 +72,8 @@ type Message interface {
Timestamp() time.Time Timestamp() time.Time
NotificationSenderName() string NotificationSenderName() string
NotificationContent() string NotificationContent() string
SetState(state mautrix.OutgoingEventState)
SetIsHighlight(highlight bool)
SetID(id string)
} }

View File

@ -304,9 +304,9 @@ func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) {
} }
// TODO switch to roomView.AddEvent // TODO switch to roomView.AddEvent
message := mainView.ParseEvent(roomView, evt) message := roomView.ParseEvent(evt)
if message != nil { if message != nil {
roomView.AddMessage(message, ifc.AppendMessage) roomView.AddMessage(message)
roomView.MxRoom().LastReceivedMessage = message.Timestamp() roomView.MxRoom().LastReceivedMessage = message.Timestamp()
if c.syncer.FirstSyncDone { if c.syncer.FirstSyncDone {
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should() pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
@ -480,25 +480,10 @@ func (c *Container) MarkRead(roomID, eventID string) {
c.client.MakeRequest("POST", urlPath, struct{}{}, nil) c.client.MakeRequest("POST", urlPath, struct{}{}, nil)
} }
// SendMessage sends a message with the given text to the given room.
func (c *Container) SendMessage(roomID string, msgtype mautrix.MessageType, text string) (string, error) {
defer debug.Recover()
c.SendTyping(roomID, false)
resp, err := c.client.SendMessageEvent(roomID, mautrix.EventMessage,
mautrix.Content{MsgType: msgtype, Body: text})
if err != nil {
return "", err
}
return resp.EventID, nil
}
var mentionRegex = regexp.MustCompile("\\[(.+?)]\\(https://matrix.to/#/@.+?:.+?\\)") var mentionRegex = regexp.MustCompile("\\[(.+?)]\\(https://matrix.to/#/@.+?:.+?\\)")
var roomRegex = regexp.MustCompile("\\[.+?]\\(https://matrix.to/#/(#.+?:[^/]+?)\\)") var roomRegex = regexp.MustCompile("\\[.+?]\\(https://matrix.to/#/(#.+?:[^/]+?)\\)")
// SendMarkdownMessage sends a message with the given markdown text to the given room. func (c *Container) PrepareMarkdownMessage(roomID string, msgtype mautrix.MessageType, text string) *mautrix.Event {
func (c *Container) SendMarkdownMessage(roomID string, msgtype mautrix.MessageType, text string) (string, error) {
defer debug.Recover()
content := format.RenderMarkdown(text) content := format.RenderMarkdown(text)
content.MsgType = msgtype content.MsgType = msgtype
@ -506,10 +491,9 @@ func (c *Container) SendMarkdownMessage(roomID string, msgtype mautrix.MessageTy
content.Body = mentionRegex.ReplaceAllString(content.Body, "$1") content.Body = mentionRegex.ReplaceAllString(content.Body, "$1")
content.Body = roomRegex.ReplaceAllString(content.Body, "$1") content.Body = roomRegex.ReplaceAllString(content.Body, "$1")
c.SendTyping(roomID, false)
roomView := c.ui.MainView().GetRoom(roomID)
txnID := c.client.TxnID() txnID := c.client.TxnID()
localEcho := roomView.ParseEvent(&mautrix.Event{ localEcho := &mautrix.Event{
ID: txnID,
Sender: c.config.UserID, Sender: c.config.UserID,
Type: mautrix.EventMessage, Type: mautrix.EventMessage,
Timestamp: time.Now().UnixNano() / 1e6, Timestamp: time.Now().UnixNano() / 1e6,
@ -519,11 +503,17 @@ func (c *Container) SendMarkdownMessage(roomID string, msgtype mautrix.MessageTy
TransactionID: txnID, TransactionID: txnID,
OutgoingState: mautrix.EventStateLocalEcho, OutgoingState: mautrix.EventStateLocalEcho,
}, },
}) }
roomView.AppendMessage(localEcho) return localEcho
resp, err := c.client.SendMessageEvent(roomID, mautrix.EventMessage, content, mautrix.ReqSendEvent{TransactionID: txnID}) }
// SendMarkdownMessage sends a message with the given markdown text to the given room.
func (c *Container) SendEvent(event *mautrix.Event) (string, error) {
defer debug.Recover()
c.SendTyping(event.RoomID, false)
resp, err := c.client.SendMessageEvent(event.RoomID, event.Type, event.Content, mautrix.ReqSendEvent{TransactionID: event.Unsigned.TransactionID})
if err != nil { if err != nil {
roomView.MarkMessageFailed(localEcho, err)
return "", err return "", err
} }
return resp.EventID, nil return resp.EventID, nil
@ -592,6 +582,7 @@ func (c *Container) GetHistory(room *rooms.Room, limit int) ([]*mautrix.Event, e
} }
} }
room.PrevBatch = resp.End room.PrevBatch = resp.End
c.config.PutRoom(room)
debug.Printf("Loaded %d events for %s from server from %s to %s", len(resp.Chunk), room.ID, resp.Start, resp.End) debug.Printf("Loaded %d events for %s from server from %s to %s", len(resp.Chunk), room.ID, resp.Start, resp.End)
return resp.Chunk, nil return resp.Chunk, nil
} }

View File

@ -27,16 +27,13 @@ import (
"github.com/lucasb-eyer/go-colorful" "github.com/lucasb-eyer/go-colorful"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/format"
"maunium.net/go/gomuks/debug" "maunium.net/go/gomuks/debug"
"maunium.net/go/mautrix"
) )
func cmdMe(cmd *Command) { func cmdMe(cmd *Command) {
text := strings.Join(cmd.Args, " ") text := strings.Join(cmd.Args, " ")
tempMessage := cmd.Room.NewTempMessage("m.emote", text) go cmd.Room.SendMessage(mautrix.MsgEmote, text)
go cmd.MainView.sendTempMessage(cmd.Room, tempMessage, text)
cmd.UI.Render() cmd.UI.Render()
} }
@ -97,8 +94,7 @@ func cmdRainbow(cmd *Command) {
color := rainbow.GetInterpolatedColorFor(float64(i) / float64(len(text))).Hex() color := rainbow.GetInterpolatedColorFor(float64(i) / float64(len(text))).Hex()
fmt.Fprintf(&html, "<font color=\"%s\">%c</font>", color, char) fmt.Fprintf(&html, "<font color=\"%s\">%c</font>", color, char)
} }
tempMessage := cmd.Room.NewTempMessage("m.text", format.HTMLToText(html.String())) go cmd.Room.SendMessage("m.text", html.String())
go cmd.MainView.sendTempMessage(cmd.Room, tempMessage, html.String())
cmd.UI.Render() cmd.UI.Render()
} }

View File

@ -89,7 +89,7 @@ func (view *MessageView) updateWidestSender(sender string) {
} }
} }
func (view *MessageView) UpdateMessageID(ifcMessage ifc.Message, newID string) { /*func (view *MessageView) UpdateMessageID(ifcMessage ifc.Message, newID string) {
message, ok := ifcMessage.(messages.UIMessage) message, ok := ifcMessage.(messages.UIMessage)
if !ok { if !ok {
debug.Print("[Warning] Passed non-UIMessage ifc.Message object to UpdateMessageID().") debug.Print("[Warning] Passed non-UIMessage ifc.Message object to UpdateMessageID().")
@ -99,9 +99,17 @@ func (view *MessageView) UpdateMessageID(ifcMessage ifc.Message, newID string) {
delete(view.messageIDs, message.ID()) delete(view.messageIDs, message.ID())
message.SetID(newID) message.SetID(newID)
view.messageIDs[message.ID()] = message view.messageIDs[message.ID()] = message
} }*/
func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.MessageDirection) { type MessageDirection int
const (
AppendMessage MessageDirection = iota
PrependMessage
IgnoreMessage
)
func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction MessageDirection) {
if ifcMessage == nil { if ifcMessage == nil {
return return
} }
@ -117,11 +125,11 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
var messageExists bool var messageExists bool
if oldMsg, messageExists = view.messageIDs[message.ID()]; messageExists { if oldMsg, messageExists = view.messageIDs[message.ID()]; messageExists {
view.replaceMessage(oldMsg, message) view.replaceMessage(oldMsg, message)
direction = ifc.IgnoreMessage direction = IgnoreMessage
} else if oldMsg, messageExists = view.messageIDs[message.TxnID()]; messageExists { } else if oldMsg, messageExists = view.messageIDs[message.TxnID()]; messageExists {
view.replaceMessage(oldMsg, message) view.replaceMessage(oldMsg, message)
delete(view.messageIDs, message.TxnID()) delete(view.messageIDs, message.TxnID())
direction = ifc.IgnoreMessage direction = IgnoreMessage
} }
view.updateWidestSender(message.Sender()) view.updateWidestSender(message.Sender())
@ -133,13 +141,13 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
} }
message.CalculateBuffer(view.config.Preferences, width) message.CalculateBuffer(view.config.Preferences, width)
if direction == ifc.AppendMessage { if direction == AppendMessage {
if view.ScrollOffset > 0 { if view.ScrollOffset > 0 {
view.ScrollOffset += message.Height() view.ScrollOffset += message.Height()
} }
view.messages = append(view.messages, message) view.messages = append(view.messages, message)
view.appendBuffer(message) view.appendBuffer(message)
} else if direction == ifc.PrependMessage { } else if direction == PrependMessage {
view.messages = append([]messages.UIMessage{message}, view.messages...) view.messages = append([]messages.UIMessage{message}, view.messages...)
} else if oldMsg != nil { } else if oldMsg != nil {
view.replaceBuffer(oldMsg, message) view.replaceBuffer(oldMsg, message)

View File

@ -192,6 +192,9 @@ func (msg *BaseMessage) FormatDate() string {
} }
func (msg *BaseMessage) ID() string { func (msg *BaseMessage) ID() string {
if len(msg.MsgID) == 0 {
return msg.MsgTxnID
}
return msg.MsgID return msg.MsgID
} }
@ -199,6 +202,10 @@ func (msg *BaseMessage) SetID(id string) {
msg.MsgID = id msg.MsgID = id
} }
func (msg *BaseMessage) TxnID() string {
return msg.MsgTxnID
}
func (msg *BaseMessage) Type() mautrix.MessageType { func (msg *BaseMessage) Type() mautrix.MessageType {
return msg.MsgType return msg.MsgType
} }
@ -219,14 +226,6 @@ func (msg *BaseMessage) SetIsHighlight(isHighlight bool) {
msg.MsgIsHighlight = isHighlight msg.MsgIsHighlight = isHighlight
} }
func (msg *BaseMessage) IsService() bool {
return msg.MsgIsService
}
func (msg *BaseMessage) SetIsService(isService bool) {
msg.MsgIsService = isService
}
func (msg *BaseMessage) Source() json.RawMessage { func (msg *BaseMessage) Source() json.RawMessage {
return msg.MsgSource return msg.MsgSource
} }

View File

@ -19,6 +19,7 @@ package messages
import ( import (
"maunium.net/go/gomuks/config" "maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/interface" "maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"maunium.net/go/mauview" "maunium.net/go/mauview"
"maunium.net/go/tcell" "maunium.net/go/tcell"
) )
@ -27,6 +28,7 @@ import (
type UIMessage interface { type UIMessage interface {
ifc.Message ifc.Message
Type() mautrix.MessageType
Sender() string Sender() string
SenderColor() tcell.Color SenderColor() tcell.Color
TextColor() tcell.Color TextColor() tcell.Color

View File

@ -29,7 +29,6 @@ import (
"maunium.net/go/gomuks/ui/messages/html" "maunium.net/go/gomuks/ui/messages/html"
"maunium.net/go/gomuks/ui/messages/tstring" "maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/gomuks/ui/widget" "maunium.net/go/gomuks/ui/widget"
htmlp "maunium.net/go/gomuks/ui/messages/html"
) )
func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage { func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {

View File

@ -18,6 +18,7 @@ package messages
import ( import (
"fmt" "fmt"
"time"
"maunium.net/go/mautrix" "maunium.net/go/mautrix"
@ -39,6 +40,18 @@ func NewTextMessage(event *mautrix.Event, displayname string, text string) UIMes
} }
} }
func NewServiceMessage(text string) UIMessage {
return &TextMessage{
BaseMessage: BaseMessage{
MsgSenderID: "*",
MsgSender: "*",
MsgTimestamp: time.Now(),
MsgIsService: true,
},
MsgText: text,
}
}
func (msg *TextMessage) getCache() tstring.TString { func (msg *TextMessage) getCache() tstring.TString {
if msg.cache == nil { if msg.cache == nil {
switch msg.MsgType { switch msg.MsgType {
@ -57,11 +70,6 @@ func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
msg.cache = nil msg.cache = nil
} }
func (msg *TextMessage) SetIsService(isService bool) {
msg.BaseMessage.SetIsService(isService)
msg.cache = nil
}
func (msg *TextMessage) NotificationContent() string { func (msg *TextMessage) NotificationContent() string {
return msg.MsgText return msg.MsgText
} }

View File

@ -20,7 +20,6 @@ import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"sort" "sort"
"strconv"
"strings" "strings"
"time" "time"
@ -379,6 +378,44 @@ func (view *RoomView) InputTabComplete(text string, cursorOffset int) {
view.SetCompletions(strCompletions) view.SetCompletions(strCompletions)
} }
func (view *RoomView) InputSubmit(text string) {
if len(text) == 0 {
return
} else if cmd := view.parent.cmdProcessor.ParseCommand(view, text); cmd != nil {
go view.parent.cmdProcessor.HandleCommand(cmd)
} else {
go view.SendMessage(mautrix.MsgText, text)
}
view.SetInputText("")
}
func (view *RoomView) SendMessage(msgtype mautrix.MessageType, text string) {
defer debug.Recover()
debug.Print("Sending message", msgtype, text, "to", view.Room.ID)
if !view.config.Preferences.DisableEmojis {
text = emoji.Sprint(text)
}
evt := view.parent.matrix.PrepareMarkdownMessage(view.Room.ID, msgtype, text)
msg := view.ParseEvent(evt)
view.AddMessage(msg)
eventID, err := view.parent.matrix.SendEvent(evt)
if err != nil {
msg.SetState(mautrix.EventStateSendFail)
// Show shorter version if available
if httpErr, ok := err.(mautrix.HTTPError); ok {
err = httpErr
if respErr := httpErr.RespError; respErr != nil {
err = respErr
}
}
view.AddServiceMessage(fmt.Sprintf("Failed to send message: %v", err))
view.parent.parent.Render()
} else {
debug.Print("Event ID received:", eventID)
//view.MessageView().UpdateMessageID(msg, eventID)
}
}
func (view *RoomView) MessageView() *MessageView { func (view *RoomView) MessageView() *MessageView {
return view.content return view.content
} }
@ -406,37 +443,12 @@ func (view *RoomView) UpdateUserList() {
} }
} }
func (view *RoomView) newUIMessage(id, sender string, msgtype mautrix.MessageType, text string, timestamp time.Time) messages.UIMessage {
member := view.Room.GetMember(sender)
displayname := sender
if member != nil {
displayname = member.Displayname
}
msg := messages.NewTextMessage(id, sender, displayname, msgtype, text, timestamp)
return msg
}
func (view *RoomView) NewTempMessage(msgtype mautrix.MessageType, text string) ifc.Message {
now := time.Now()
id := strconv.FormatInt(now.UnixNano(), 10)
sender := ""
if ownerMember := view.Room.GetMember(view.Room.GetSessionOwner()); ownerMember != nil {
sender = ownerMember.Displayname
}
message := view.newUIMessage(id, sender, msgtype, text, now)
message.SetState(ifc.MessageStateSending)
view.AddMessage(message, ifc.AppendMessage)
return message
}
func (view *RoomView) AddServiceMessage(text string) { func (view *RoomView) AddServiceMessage(text string) {
message := view.newUIMessage(view.parent.matrix.Client().TxnID(), "*", "gomuks.service", text, time.Now()) view.content.AddMessage(messages.NewServiceMessage(text), AppendMessage)
message.SetIsService(true)
view.AddMessage(message, ifc.AppendMessage)
} }
func (view *RoomView) AddMessage(message ifc.Message, direction ifc.MessageDirection) { func (view *RoomView) AddMessage(message ifc.Message) {
view.content.AddMessage(message, direction) view.content.AddMessage(message, AppendMessage)
} }
func (view *RoomView) ParseEvent(evt *mautrix.Event) ifc.Message { func (view *RoomView) ParseEvent(evt *mautrix.Event) ifc.Message {

View File

@ -23,9 +23,6 @@ import (
"time" "time"
"unicode" "unicode"
"github.com/kyokomi/emoji"
"maunium.net/go/mautrix"
"maunium.net/go/mauview" "maunium.net/go/mauview"
"maunium.net/go/tcell" "maunium.net/go/tcell"
@ -152,45 +149,6 @@ func findWordToTabComplete(text string) string {
return output return output
} }
func (view *MainView) InputSubmit(roomView *RoomView, text string) {
if len(text) == 0 {
return
} else if text[0] == '/' {
cmd := view.cmdProcessor.ParseCommand(roomView, text)
go view.cmdProcessor.HandleCommand(cmd)
} else {
view.SendMessage(roomView, text)
}
roomView.SetInputText("")
}
func (view *MainView) SendMessage(roomView *RoomView, text string) {
go view.goSendMessage(roomView, text)
}
func (view *MainView) goSendMessage(roomView *RoomView, text string) {
defer debug.Recover()
debug.Print("Sending message", tempMessage.Type(), text)
if !roomView.config.Preferences.DisableEmojis {
text = emoji.Sprint(text)
}
eventID, err := view.matrix.SendMarkdownMessage(roomView.Room.ID, tempMessage.Type(), text)
if err != nil {
tempMessage.SetState(ifc.MessageStateFailed)
if httpErr, ok := err.(mautrix.HTTPError); ok {
if respErr := httpErr.RespError; respErr != nil {
// Show shorter version if available
err = respErr
}
}
roomView.AddServiceMessage(fmt.Sprintf("Failed to send message: %v", err))
view.parent.Render()
} else {
debug.Print("Event ID received:", eventID)
roomView.MessageView().UpdateMessageID(tempMessage, eventID)
}
}
func (view *MainView) ShowBare(roomView *RoomView) { func (view *MainView) ShowBare(roomView *RoomView) {
if roomView == nil { if roomView == nil {
return return
@ -204,7 +162,7 @@ func (view *MainView) ShowBare(roomView *RoomView) {
fmt.Println(roomView.MessageView().CapturePlaintext(height)) fmt.Println(roomView.MessageView().CapturePlaintext(height))
fmt.Println("Press enter to return to normal mode.") fmt.Println("Press enter to return to normal mode.")
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
reader.ReadRune() _, _, _ = reader.ReadRune()
print("\033[2J\033[0;0H") print("\033[2J\033[0;0H")
}) })
} }
@ -310,7 +268,6 @@ func (view *MainView) SwitchRoom(tag string, room *rooms.Room) {
func (view *MainView) addRoomPage(room *rooms.Room) { func (view *MainView) addRoomPage(room *rooms.Room) {
if _, ok := view.rooms[room.ID]; !ok { if _, ok := view.rooms[room.ID]; !ok {
roomView := NewRoomView(view, room). roomView := NewRoomView(view, room).
SetInputSubmitFunc(view.InputSubmit).
SetInputChangedFunc(view.InputChanged) SetInputChangedFunc(view.InputChanged)
view.rooms[room.ID] = roomView view.rooms[room.ID] = roomView
roomView.UpdateUserList() roomView.UpdateUserList()
@ -428,8 +385,8 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
sendNotification(room, message.NotificationSenderName(), message.NotificationContent(), should.Highlight, shouldPlaySound) sendNotification(room, message.NotificationSenderName(), message.NotificationContent(), should.Highlight, shouldPlaySound)
} }
// TODO Make sure this happens somewhere else // TODO this should probably happen somewhere else
//message.SetIsHighlight(should.Highlight) message.SetIsHighlight(should.Highlight)
} }
func (view *MainView) InitialSyncDone() { func (view *MainView) InitialSyncDone() {
@ -443,15 +400,16 @@ func (view *MainView) InitialSyncDone() {
func (view *MainView) LoadHistory(room string) { func (view *MainView) LoadHistory(room string) {
defer debug.Recover() defer debug.Recover()
roomView := view.rooms[room] roomView := view.rooms[room]
msgView := roomView.MessageView()
batch := roomView.Room.PrevBatch batch := roomView.Room.PrevBatch
lockTime := time.Now().Unix() + 1 lockTime := time.Now().Unix() + 1
roomView.Room.LockHistory() roomView.Room.LockHistory()
roomView.MessageView().LoadingMessages = true msgView.LoadingMessages = true
defer func() { defer func() {
roomView.Room.UnlockHistory() roomView.Room.UnlockHistory()
roomView.MessageView().LoadingMessages = false msgView.LoadingMessages = false
}() }()
// There's no clean way to try to lock a mutex, so we just check if we still // There's no clean way to try to lock a mutex, so we just check if we still
@ -468,16 +426,9 @@ func (view *MainView) LoadHistory(room string) {
return return
} }
for _, evt := range history { for _, evt := range history {
message := roomView.ParseEvent(evt) if message := roomView.ParseEvent(evt); message != nil {
if message != nil { msgView.AddMessage(message, PrependMessage)
roomView.AddMessage(message, ifc.PrependMessage)
} }
} }
// TODO?
/*err = roomView.SaveHistory(view.config.HistoryDir)
if err != nil {
debug.Printf("Failed to save history of %s: %v", roomView.Room.GetTitle(), err)
}*/
view.config.PutRoom(roomView.Room)
view.parent.Render() view.parent.Render()
} }