Use already parsed events for replies if possible
This commit is contained in:
parent
9132e2b750
commit
db0e24ccc2
@ -61,6 +61,7 @@ type RoomView interface {
|
||||
UpdateUserList()
|
||||
|
||||
ParseEvent(evt *mautrix.Event) Message
|
||||
GetEvent(eventID string) Message
|
||||
AddMessage(message Message)
|
||||
AddServiceMessage(message string)
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ func (view *MessageView) handleMessageClick(message messages.UIMessage) bool {
|
||||
case *messages.ImageMessage:
|
||||
open.Open(message.Path())
|
||||
case messages.UIMessage:
|
||||
debug.Print("Message clicked:", message.NotificationContent())
|
||||
debug.Print("Message clicked:", message)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ type BaseMessage struct {
|
||||
MsgSource json.RawMessage
|
||||
ReplyTo UIMessage
|
||||
buffer []tstring.TString
|
||||
plainBuffer []tstring.TString
|
||||
}
|
||||
|
||||
func newBaseMessage(event *mautrix.Event, displayname string) BaseMessage {
|
||||
@ -259,6 +258,12 @@ func (msg *BaseMessage) Draw(screen mauview.Screen) {
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) clone() BaseMessage {
|
||||
clone := *msg
|
||||
clone.buffer = nil
|
||||
return clone
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) CalculateReplyBuffer(preferences config.UserPreferences, width int) {
|
||||
if msg.ReplyTo == nil {
|
||||
return
|
||||
|
@ -55,6 +55,14 @@ func NewDateChangeMessage(text string) UIMessage {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (msg *ExpandedTextMessage) Clone() UIMessage {
|
||||
return &ExpandedTextMessage{
|
||||
BaseMessage: msg.BaseMessage.clone(),
|
||||
MsgText: msg.MsgText.Clone(),
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *ExpandedTextMessage) GenerateText() tstring.TString {
|
||||
return msg.MsgText
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"maunium.net/go/mauview"
|
||||
)
|
||||
@ -37,6 +38,10 @@ func NewBlockquoteEntity(children []Entity) *BlockquoteEntity {
|
||||
}}
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) Clone() Entity {
|
||||
return &BlockquoteEntity{BaseEntity: be.BaseEntity.Clone().(*BaseEntity)}
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) Draw(screen mauview.Screen) {
|
||||
be.BaseEntity.Draw(screen)
|
||||
for y := 0; y < be.height; y++ {
|
||||
@ -44,6 +49,33 @@ func (be *BlockquoteEntity) Draw(screen mauview.Screen) {
|
||||
}
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) PlainText() string {
|
||||
if len(be.Children) == 0 {
|
||||
return ""
|
||||
}
|
||||
var buf strings.Builder
|
||||
newlined := false
|
||||
for i, child := range be.Children {
|
||||
if i != 0 && child.IsBlock() && !newlined {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
newlined = false
|
||||
for i, row := range strings.Split(child.PlainText(), "\n") {
|
||||
if i != 0 {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
buf.WriteRune('>')
|
||||
buf.WriteRune(' ')
|
||||
buf.WriteString(row)
|
||||
}
|
||||
if child.IsBlock() {
|
||||
buf.WriteRune('\n')
|
||||
newlined = true
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) String() string {
|
||||
return fmt.Sprintf("&html.BlockquoteEntity{%s},\n", be.BaseEntity)
|
||||
}
|
||||
|
@ -26,3 +26,15 @@ func NewBreakEntity() *BreakEntity {
|
||||
Block: true,
|
||||
}}
|
||||
}
|
||||
|
||||
func (be *BreakEntity) Clone() Entity {
|
||||
return NewBreakEntity()
|
||||
}
|
||||
|
||||
func (be *BreakEntity) PlainText() string {
|
||||
return "\n"
|
||||
}
|
||||
|
||||
func (be *BreakEntity) String() string {
|
||||
return "&html.BreakEntity{},\n"
|
||||
}
|
||||
|
@ -37,6 +37,13 @@ func NewCodeBlockEntity(children []Entity, background tcell.Style) *CodeBlockEnt
|
||||
}
|
||||
}
|
||||
|
||||
func (ce *CodeBlockEntity) Clone() Entity {
|
||||
return &CodeBlockEntity{
|
||||
BaseEntity: ce.BaseEntity.Clone().(*BaseEntity),
|
||||
Background: ce.Background,
|
||||
}
|
||||
}
|
||||
|
||||
func (ce *CodeBlockEntity) Draw(screen mauview.Screen) {
|
||||
screen.Fill(' ', ce.Background)
|
||||
ce.BaseEntity.Draw(screen)
|
||||
|
@ -165,17 +165,20 @@ func (he *BaseEntity) PlainText() string {
|
||||
buf.WriteString(he.Text)
|
||||
newlined := false
|
||||
for _, child := range he.Children {
|
||||
if child.IsBlock() && !newlined {
|
||||
text := child.PlainText()
|
||||
if !strings.HasPrefix(text, "\n") && child.IsBlock() && !newlined {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
newlined = false
|
||||
buf.WriteString(child.PlainText())
|
||||
buf.WriteString(text)
|
||||
if child.IsBlock() {
|
||||
buf.WriteRune('\n')
|
||||
if !strings.HasSuffix(text, "\n") {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
newlined = true
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
// Draw draws this entity onto the given mauview Screen.
|
||||
|
56
ui/messages/html/horizontalline.go
Normal file
56
ui/messages/html/horizontalline.go
Normal file
@ -0,0 +1,56 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2019 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package html
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"maunium.net/go/mauview"
|
||||
)
|
||||
|
||||
type HorizontalLineEntity struct {
|
||||
*BaseEntity
|
||||
}
|
||||
|
||||
const HorizontalLineChar = '━'
|
||||
|
||||
func NewHorizontalLineEntity() *HorizontalLineEntity {
|
||||
return &HorizontalLineEntity{&BaseEntity{
|
||||
Tag: "hr",
|
||||
Block: true,
|
||||
DefaultHeight: 1,
|
||||
}}
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) Clone() Entity {
|
||||
return NewHorizontalLineEntity()
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) Draw(screen mauview.Screen) {
|
||||
width, _ := screen.Size()
|
||||
for x := 0; x < width; x++ {
|
||||
screen.SetContent(x, 0, HorizontalLineChar, nil, he.Style)
|
||||
}
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) PlainText() string {
|
||||
return strings.Repeat(string(HorizontalLineChar), 5)
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) String() string {
|
||||
return "&html.HorizontalLineEntity{},\n"
|
||||
}
|
@ -56,6 +56,14 @@ func NewListEntity(ordered bool, start int, children []Entity) *ListEntity {
|
||||
return entity
|
||||
}
|
||||
|
||||
func (le *ListEntity) Clone() Entity {
|
||||
return &ListEntity{
|
||||
BaseEntity: le.BaseEntity.Clone().(*BaseEntity),
|
||||
Ordered: le.Ordered,
|
||||
Start: le.Start,
|
||||
}
|
||||
}
|
||||
|
||||
func (le *ListEntity) Draw(screen mauview.Screen) {
|
||||
width, _ := screen.Size()
|
||||
|
||||
@ -75,6 +83,31 @@ func (le *ListEntity) Draw(screen mauview.Screen) {
|
||||
}
|
||||
}
|
||||
|
||||
func (le *ListEntity) PlainText() string {
|
||||
if len(le.Children) == 0 {
|
||||
return ""
|
||||
}
|
||||
var buf strings.Builder
|
||||
for i, child := range le.Children {
|
||||
indent := strings.Repeat(" ", le.Indent)
|
||||
if le.Ordered {
|
||||
number := le.Start + i
|
||||
_, _ = fmt.Fprintf(&buf, "%d. %s", number, strings.Repeat(" ", le.Indent-2-digits(number)))
|
||||
} else {
|
||||
buf.WriteString("● ")
|
||||
}
|
||||
for j, row := range strings.Split(child.PlainText(), "\n") {
|
||||
if j != 0 {
|
||||
buf.WriteRune('\n')
|
||||
buf.WriteString(indent)
|
||||
}
|
||||
buf.WriteString(row)
|
||||
}
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func (le *ListEntity) String() string {
|
||||
return fmt.Sprintf("&html.ListEntity{Ordered=%t, Start=%d, Base=%s},\n", le.Ordered, le.Start, le.BaseEntity)
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ func (parser *htmlParser) basicFormatToEntity(node *html.Node) Entity {
|
||||
entity.AdjustStyle(AdjustStyleBold)
|
||||
case "i", "em":
|
||||
entity.AdjustStyle(AdjustStyleItalic)
|
||||
case "s", "del":
|
||||
case "s", "del", "strike":
|
||||
entity.AdjustStyle(AdjustStyleStrikethrough)
|
||||
case "u", "ins":
|
||||
entity.AdjustStyle(AdjustStyleUnderline)
|
||||
@ -237,7 +237,7 @@ func (parser *htmlParser) syntaxHighlight(text, language string) Entity {
|
||||
children := make([]Entity, len(tokens))
|
||||
for i, token := range tokens {
|
||||
if token.Value == "\n" {
|
||||
children[i] = &BaseEntity{Block: true, Tag: "br"}
|
||||
children[i] = NewBreakEntity()
|
||||
} else {
|
||||
children[i] = &BaseEntity{
|
||||
Tag: token.Type.String(),
|
||||
@ -282,7 +282,7 @@ func (parser *htmlParser) tagNodeToEntity(node *html.Node) Entity {
|
||||
return parser.headerToEntity(node)
|
||||
case "br":
|
||||
return NewBreakEntity()
|
||||
case "b", "strong", "i", "em", "s", "del", "u", "ins", "font":
|
||||
case "b", "strong", "i", "em", "s", "strike", "del", "u", "ins", "font":
|
||||
return parser.basicFormatToEntity(node)
|
||||
case "a":
|
||||
return parser.linkToEntity(node)
|
||||
@ -290,6 +290,10 @@ func (parser *htmlParser) tagNodeToEntity(node *html.Node) Entity {
|
||||
return parser.imageToEntity(node)
|
||||
case "pre":
|
||||
return parser.codeblockToEntity(node)
|
||||
case "hr":
|
||||
return NewHorizontalLineEntity()
|
||||
case "mx-reply":
|
||||
return nil
|
||||
default:
|
||||
return &BaseEntity{
|
||||
Tag: node.Data,
|
||||
|
@ -40,6 +40,14 @@ func NewHTMLMessage(event *mautrix.Event, displayname string, root html.Entity)
|
||||
}
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Clone() UIMessage {
|
||||
return &HTMLMessage{
|
||||
BaseMessage: hw.BaseMessage.clone(),
|
||||
Root: hw.Root.Clone(),
|
||||
FocusedBg: hw.FocusedBg,
|
||||
}
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Draw(screen mauview.Screen) {
|
||||
screen = hw.DrawReply(screen)
|
||||
if hw.focused {
|
||||
|
@ -53,6 +53,19 @@ func NewImageMessage(matrix ifc.MatrixContainer, event *mautrix.Event, displayna
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *ImageMessage) Clone() UIMessage {
|
||||
data := make([]byte, len(msg.data))
|
||||
copy(data, msg.data)
|
||||
return &ImageMessage{
|
||||
BaseMessage: msg.BaseMessage.clone(),
|
||||
Body: msg.Body,
|
||||
Homeserver: msg.Homeserver,
|
||||
FileID: msg.FileID,
|
||||
data: data,
|
||||
matrix: msg.matrix,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *ImageMessage) RegisterMatrix(matrix ifc.MatrixContainer) {
|
||||
msg.matrix = matrix
|
||||
|
||||
|
@ -43,6 +43,8 @@ type UIMessage interface {
|
||||
Height() int
|
||||
PlainText() string
|
||||
|
||||
Clone() UIMessage
|
||||
|
||||
RealSender() string
|
||||
RegisterMatrix(matrix ifc.MatrixContainer)
|
||||
}
|
||||
|
@ -31,7 +31,18 @@ import (
|
||||
"maunium.net/go/gomuks/ui/widget"
|
||||
)
|
||||
|
||||
func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
func getCachedEvent(mainView ifc.MainView, roomID, eventID string) UIMessage {
|
||||
if roomView := mainView.GetRoom(roomID); roomView != nil {
|
||||
if replyToIfcMsg := roomView.GetEvent(eventID); replyToIfcMsg != nil {
|
||||
if replyToMsg, ok := replyToIfcMsg.(UIMessage); ok && replyToMsg != nil {
|
||||
return replyToMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseEvent(matrix ifc.MatrixContainer, mainView ifc.MainView, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
msg := directParseEvent(matrix, room, evt)
|
||||
if msg == nil {
|
||||
return nil
|
||||
@ -41,10 +52,14 @@ func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event
|
||||
if len(evt.Content.RelatesTo.InReplyTo.RoomID) > 0 {
|
||||
replyToRoom = matrix.GetRoom(evt.Content.RelatesTo.InReplyTo.RoomID)
|
||||
}
|
||||
replyToEvt, _ := matrix.GetEvent(replyToRoom, evt.Content.GetReplyTo())
|
||||
if replyToEvt != nil {
|
||||
replyToMsg := directParseEvent(matrix, replyToRoom, replyToEvt)
|
||||
if replyToMsg != nil {
|
||||
|
||||
if replyToMsg := getCachedEvent(mainView, replyToRoom.ID, evt.Content.GetReplyTo()); replyToMsg != nil {
|
||||
debug.Print("Cloning cached UIMessage", replyToMsg)
|
||||
replyToMsg = replyToMsg.Clone()
|
||||
replyToMsg.SetReplyTo(nil)
|
||||
msg.SetReplyTo(replyToMsg)
|
||||
} else if replyToEvt, _ := matrix.GetEvent(replyToRoom, evt.Content.GetReplyTo()); replyToEvt != nil {
|
||||
if replyToMsg := directParseEvent(matrix, replyToRoom, replyToEvt); replyToMsg != nil {
|
||||
msg.SetReplyTo(replyToMsg)
|
||||
} else {
|
||||
// TODO add unrenderable reply header
|
||||
@ -68,6 +83,7 @@ func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix
|
||||
case mautrix.StateMember:
|
||||
return ParseMembershipEvent(room, evt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -43,15 +43,22 @@ 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,
|
||||
MsgSenderID: "*",
|
||||
MsgSender: "*",
|
||||
MsgTimestamp: time.Now(),
|
||||
MsgIsService: true,
|
||||
},
|
||||
MsgText: text,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *TextMessage) Clone() UIMessage {
|
||||
return &TextMessage{
|
||||
BaseMessage: msg.BaseMessage.clone(),
|
||||
MsgText: msg.MsgText,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *TextMessage) getCache() tstring.TString {
|
||||
if msg.cache == nil {
|
||||
switch msg.MsgType {
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/mattn/go-runewidth"
|
||||
|
||||
"maunium.net/go/mauview"
|
||||
|
||||
"maunium.net/go/tcell"
|
||||
@ -29,11 +30,11 @@ import (
|
||||
type TString []Cell
|
||||
|
||||
func NewBlankTString() TString {
|
||||
return make([]Cell, 0)
|
||||
return make(TString, 0)
|
||||
}
|
||||
|
||||
func NewTString(str string) TString {
|
||||
newStr := make([]Cell, len(str))
|
||||
newStr := make(TString, len(str))
|
||||
for i, char := range str {
|
||||
newStr[i] = NewCell(char)
|
||||
}
|
||||
@ -41,7 +42,7 @@ func NewTString(str string) TString {
|
||||
}
|
||||
|
||||
func NewColorTString(str string, color tcell.Color) TString {
|
||||
newStr := make([]Cell, len(str))
|
||||
newStr := make(TString, len(str))
|
||||
for i, char := range str {
|
||||
newStr[i] = NewColorCell(char, color)
|
||||
}
|
||||
@ -49,7 +50,7 @@ func NewColorTString(str string, color tcell.Color) TString {
|
||||
}
|
||||
|
||||
func NewStyleTString(str string, style tcell.Style) TString {
|
||||
newStr := make([]Cell, len(str))
|
||||
newStr := make(TString, len(str))
|
||||
for i, char := range str {
|
||||
newStr[i] = NewStyleCell(char, style)
|
||||
}
|
||||
@ -74,6 +75,12 @@ func Join(strings []TString, separator string) TString {
|
||||
return out
|
||||
}
|
||||
|
||||
func (str TString) Clone() TString {
|
||||
newStr := make(TString, len(str))
|
||||
copy(newStr, str)
|
||||
return newStr
|
||||
}
|
||||
|
||||
func (str TString) AppendTString(dataList ...TString) TString {
|
||||
newStr := str
|
||||
for _, data := range dataList {
|
||||
|
@ -445,5 +445,13 @@ func (view *RoomView) AddMessage(message ifc.Message) {
|
||||
}
|
||||
|
||||
func (view *RoomView) ParseEvent(evt *mautrix.Event) ifc.Message {
|
||||
return messages.ParseEvent(view.parent.matrix, view.Room, evt)
|
||||
return messages.ParseEvent(view.parent.matrix, view.parent, view.Room, evt)
|
||||
}
|
||||
|
||||
func (view *RoomView) GetEvent(eventID string) ifc.Message {
|
||||
message, ok := view.content.messageIDs[eventID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user