From 66233721a2ec4f10b4ffa2682aaeb84886e209d9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 15 Apr 2022 23:28:23 +0300 Subject: [PATCH] Get rid of special-cased plaintext rendering. Fixes #273 --- ui/messages/html/parser.go | 54 ++++++++-------- ui/messages/parser.go | 2 +- ui/messages/textmessage.go | 125 ------------------------------------- 3 files changed, 30 insertions(+), 151 deletions(-) delete mode 100644 ui/messages/textmessage.go diff --git a/ui/messages/html/parser.go b/ui/messages/html/parser.go index e68b7aa..554f4fa 100644 --- a/ui/messages/html/parser.go +++ b/ui/messages/html/parser.go @@ -383,6 +383,34 @@ func (parser *htmlParser) tagNodeToEntity(node *html.Node) Entity { var spaces = regexp.MustCompile("\\s+") var links = regexp.MustCompile(`https?://\S+`) +func TextToEntity(text string, eventID id.EventID) Entity { + if len(text) == 0 { + return nil + } + indices := links.FindAllStringIndex(text, -1) + if len(indices) == 0 { + return NewTextEntity(text) + } + ent := &ContainerEntity{ + BaseEntity: &BaseEntity{Tag: "span"}, + } + var lastEnd int + for i, item := range indices { + start, end := item[0], item[1] + if start > lastEnd { + ent.Children = append(ent.Children, NewTextEntity(text[lastEnd:start])) + } + link := text[start:end] + linkID := fmt.Sprintf("%s-%d", eventID, i) + ent.Children = append(ent.Children, NewTextEntity(link).AdjustStyle(AdjustStyleLink(link, linkID), AdjustStyleReasonNormal)) + lastEnd = end + } + if lastEnd < len(text) { + ent.Children = append(ent.Children, NewTextEntity(text[lastEnd:])) + } + return ent +} + func (parser *htmlParser) singleNodeToEntity(node *html.Node) Entity { switch node.Type { case html.TextNode: @@ -390,31 +418,7 @@ func (parser *htmlParser) singleNodeToEntity(node *html.Node) Entity { node.Data = strings.ReplaceAll(node.Data, "\n", "") node.Data = spaces.ReplaceAllLiteralString(node.Data, " ") } - if len(node.Data) == 0 { - return nil - } - indices := links.FindAllStringIndex(node.Data, -1) - if len(indices) == 0 { - return NewTextEntity(node.Data) - } - ent := &ContainerEntity{ - BaseEntity: &BaseEntity{Tag: "span"}, - } - var lastEnd int - for i, item := range indices { - start, end := item[0], item[1] - if start > lastEnd { - ent.Children = append(ent.Children, NewTextEntity(node.Data[lastEnd:start])) - } - link := node.Data[start:end] - linkID := fmt.Sprintf("%s-%d", parser.evt.ID, i) - ent.Children = append(ent.Children, NewTextEntity(link).AdjustStyle(AdjustStyleLink(link, linkID), AdjustStyleReasonNormal)) - lastEnd = end - } - if lastEnd < len(node.Data) { - ent.Children = append(ent.Children, NewTextEntity(node.Data[lastEnd:])) - } - return ent + return TextToEntity(node.Data, parser.evt.ID) case html.ElementNode: parsed := parser.tagNodeToEntity(node) if parsed != nil && !parsed.IsBlock() && parsed.IsEmpty() { diff --git a/ui/messages/parser.go b/ui/messages/parser.go index 2800701..c609032 100644 --- a/ui/messages/parser.go +++ b/ui/messages/parser.go @@ -208,7 +208,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *muksevt.Eve return NewHTMLMessage(evt, displayname, html.Parse(matrix.Preferences(), room, content, evt, displayname)) } content.Body = strings.Replace(content.Body, "\t", " ", -1) - return NewTextMessage(evt, displayname, content.Body) + return NewHTMLMessage(evt, displayname, html.TextToEntity(content.Body, evt.ID)) case event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile: msg := NewFileMessage(matrix, evt, displayname) if !matrix.Preferences().DisableDownloads { diff --git a/ui/messages/textmessage.go b/ui/messages/textmessage.go deleted file mode 100644 index a986366..0000000 --- a/ui/messages/textmessage.go +++ /dev/null @@ -1,125 +0,0 @@ -// gomuks - A terminal Matrix client written in Go. -// Copyright (C) 2020 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 . - -package messages - -import ( - "fmt" - "regexp" - "time" - - "go.mau.fi/mauview" - "go.mau.fi/tcell" - "maunium.net/go/mautrix/id" - - "maunium.net/go/gomuks/config" - "maunium.net/go/gomuks/matrix/muksevt" - "maunium.net/go/gomuks/ui/messages/tstring" -) - -type TextMessage struct { - cache tstring.TString - buffer []tstring.TString - isHighlight bool - eventID id.EventID - Text string -} - -// NewTextMessage creates a new UITextMessage object with the provided values and the default state. -func NewTextMessage(evt *muksevt.Event, displayname string, text string) *UIMessage { - return newUIMessage(evt, displayname, &TextMessage{ - eventID: evt.ID, - Text: text, - }) -} - -func NewServiceMessage(text string) *UIMessage { - return &UIMessage{ - SenderID: "*", - SenderName: "*", - Timestamp: time.Now(), - IsService: true, - Renderer: &TextMessage{ - Text: text, - }, - } -} - -func (msg *TextMessage) Clone() MessageRenderer { - return &TextMessage{ - Text: msg.Text, - } -} - -var linkRegex = regexp.MustCompile(`https?://\S+`) - -func (msg *TextMessage) getCache(uiMsg *UIMessage) tstring.TString { - if msg.cache == nil { - var content = tstring.NewBlankTString() - indices := linkRegex.FindAllStringIndex(msg.Text, -1) - var lastEnd int - for i, item := range indices { - start, end := item[0], item[1] - link := msg.Text[start:end] - linkID := fmt.Sprintf("%s-%d", msg.eventID, i) - content = content. - Append(msg.Text[lastEnd:start]). - AppendTString(tstring.NewStyleTString(link, tcell.StyleDefault.Hyperlink(link, linkID))) - lastEnd = end - } - if lastEnd < len(msg.Text) { - content = content.Append(msg.Text[lastEnd:]) - } - switch uiMsg.Type { - case "m.emote": - prefix := tstring.NewTString("* ") - name := tstring.NewColorTString(uiMsg.SenderName, uiMsg.SenderColor()) - msg.cache = prefix.AppendTString(name, tstring.NewTString(" "), content) - default: - msg.cache = content - } - } - return msg.cache -} - -func (msg *TextMessage) NotificationContent() string { - return msg.Text -} - -func (msg *TextMessage) PlainText() string { - return msg.Text -} - -func (msg *TextMessage) String() string { - return fmt.Sprintf(`&messages.TextMessage{Text="%s"}`, msg.Text) -} - -func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int, uiMsg *UIMessage) { - if uiMsg.IsHighlight != msg.isHighlight { - msg.cache = nil - } - msg.buffer = calculateBufferWithText(prefs, msg.getCache(uiMsg), width, uiMsg) -} - -func (msg *TextMessage) Height() int { - return len(msg.buffer) -} - -func (msg *TextMessage) Draw(screen mauview.Screen, _ *UIMessage) { - for y, line := range msg.buffer { - line.Draw(screen, 0, y) - } -}