aboutsummaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/command-processor.go13
-rw-r--r--ui/commands.go15
-rw-r--r--ui/message-view.go38
-rw-r--r--ui/messages/base.go51
-rw-r--r--ui/messages/expandedtextmessage.go5
-rw-r--r--ui/messages/htmlmessage.go93
-rw-r--r--ui/messages/imagemessage.go7
-rw-r--r--ui/messages/message.go4
-rw-r--r--ui/messages/parser/htmlparser.go3
-rw-r--r--ui/messages/textbase.go2
-rw-r--r--ui/messages/textmessage.go5
11 files changed, 154 insertions, 82 deletions
diff --git a/ui/command-processor.go b/ui/command-processor.go
index 77a7b3d..7a4c2c1 100644
--- a/ui/command-processor.go
+++ b/ui/command-processor.go
@@ -76,12 +76,12 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
Gomuks: parent.gmx,
},
aliases: map[string]*Alias{
- "part": {"leave"},
- "send": {"sendevent"},
- "msend": {"msendevent"},
- "state": {"setstate"},
- "mstate":{"msetstate"},
- "rb": {"rainbow"},
+ "part": {"leave"},
+ "send": {"sendevent"},
+ "msend": {"msendevent"},
+ "state": {"setstate"},
+ "mstate": {"msetstate"},
+ "rb": {"rainbow"},
},
commands: map[string]CommandHandler{
"unknown-command": cmdUnknownCommand,
@@ -102,6 +102,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
"msetstate": cmdMSetState,
"rainbow": cmdRainbow,
"invite": cmdInvite,
+ "hprof": cmdHeapProfile,
},
}
}
diff --git a/ui/commands.go b/ui/commands.go
index a8b1faa..a652518 100644
--- a/ui/commands.go
+++ b/ui/commands.go
@@ -19,6 +19,9 @@ package ui
import (
"encoding/json"
"fmt"
+ "os"
+ "runtime"
+ "runtime/pprof"
"strings"
"unicode"
@@ -69,6 +72,18 @@ var rainbow = GradientTable{
{colorful.LinearRgb(1, 0, 0.5), 1},
}
+func cmdHeapProfile(cmd *Command) {
+ runtime.GC()
+ memProfile, err := os.Create("gomuks.prof")
+ if err != nil {
+ debug.Print(err)
+ }
+ defer memProfile.Close()
+ if err := pprof.WriteHeapProfile(memProfile); err != nil {
+ debug.Print(err)
+ }
+}
+
// TODO this command definitely belongs in a plugin once we have a plugin system.
func cmdRainbow(cmd *Command) {
text := strings.Join(cmd.Args, " ")
diff --git a/ui/message-view.go b/ui/message-view.go
index f2c7260..20831f1 100644
--- a/ui/message-view.go
+++ b/ui/message-view.go
@@ -75,6 +75,7 @@ func NewMessageView(parent *RoomView) *MessageView {
textBuffer: make([]tstring.TString, 0),
metaBuffer: make([]ifc.MessageMeta, 0),
+ width: 80,
widestSender: 5,
prevWidth: -1,
prevHeight: -1,
@@ -159,8 +160,8 @@ func (view *MessageView) appendBuffer(message messages.UIMessage) {
}
}
- view.textBuffer = append(view.textBuffer, message.Buffer()...)
- for range message.Buffer() {
+ for i := 0; i < message.Height(); i++ {
+ view.textBuffer = append(view.textBuffer, nil)
view.metaBuffer = append(view.metaBuffer, message)
}
view.prevMsgCount++
@@ -200,10 +201,15 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
end++
}
- view.textBuffer = append(append(view.textBuffer[0:start], new.Buffer()...), view.textBuffer[end:]...)
- if len(new.Buffer()) != end-start {
+ if new.Height() == 0 {
+ new.CalculateBuffer(view.prevPrefs, view.prevWidth)
+ }
+
+ textBuf := make([]tstring.TString, new.Height())
+ view.textBuffer = append(append(view.textBuffer[0:start], textBuf...), view.textBuffer[end:]...)
+ if new.Height() != end-start {
metaBuffer := view.metaBuffer[0:start]
- for range new.Buffer() {
+ for i := 0; i < new.Height(); i++ {
metaBuffer = append(metaBuffer, new)
}
view.metaBuffer = append(metaBuffer, view.metaBuffer[end:]...)
@@ -504,16 +510,22 @@ func (view *MessageView) Draw(screen mauview.Screen) {
meta.SenderColor())
}
prevMeta = meta
- htmlMessage, ok := meta.(*messages.HTMLMessage)
- if ok {
- htmlMessage.Draw(mauview.NewProxyScreen(screen, 0, line, view.width, htmlMessage.Height()))
- if ok {
- line += htmlMessage.Height()
- continue
+ }
+
+ message, ok := meta.(messages.UIMessage)
+ if ok {
+ for i := index - 1; i >= 0 && view.metaBuffer[i] == meta; i-- {
+ line--
+ }
+ message.Draw(mauview.NewProxyScreen(screen, messageX, line, view.width-messageX, message.Height()))
+ if !bareMode {
+ for i := line; i < line+message.Height(); i++ {
+ screen.SetContent(separatorX, i, borderChar, nil, borderStyle)
}
}
+ line += message.Height() - 1
+ } else {
+ text.Draw(screen, messageX, line)
}
-
- text.Draw(screen, messageX, line)
}
}
diff --git a/ui/messages/base.go b/ui/messages/base.go
index ba1902d..d045e42 100644
--- a/ui/messages/base.go
+++ b/ui/messages/base.go
@@ -21,9 +21,9 @@ import (
"time"
"maunium.net/go/mautrix"
+ "maunium.net/go/mauview"
"maunium.net/go/tcell"
- "maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/interface"
"maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/gomuks/ui/widget"
@@ -34,33 +34,30 @@ func init() {
}
type BaseMessage struct {
- MsgID string
- MsgType mautrix.MessageType
- MsgSenderID string
- MsgSender string
- MsgSenderColor tcell.Color
- MsgTimestamp time.Time
- MsgState ifc.MessageState
- MsgIsHighlight bool
- MsgIsService bool
- buffer []tstring.TString
- plainBuffer []tstring.TString
- prevBufferWidth int
- prevPrefs config.UserPreferences
+ MsgID string
+ MsgType mautrix.MessageType
+ MsgSenderID string
+ MsgSender string
+ MsgSenderColor tcell.Color
+ MsgTimestamp time.Time
+ MsgState ifc.MessageState
+ MsgIsHighlight bool
+ MsgIsService bool
+ buffer []tstring.TString
+ plainBuffer []tstring.TString
}
func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, timestamp time.Time) BaseMessage {
return BaseMessage{
- MsgSenderID: sender,
- MsgSender: displayname,
- MsgTimestamp: timestamp,
- MsgSenderColor: widget.GetHashColor(sender),
- MsgType: msgtype,
- MsgID: id,
- prevBufferWidth: 0,
- MsgState: ifc.MessageStateDefault,
- MsgIsHighlight: false,
- MsgIsService: false,
+ MsgSenderID: sender,
+ MsgSender: displayname,
+ MsgTimestamp: timestamp,
+ MsgSenderColor: widget.GetHashColor(sender),
+ MsgType: msgtype,
+ MsgID: id,
+ MsgState: ifc.MessageStateDefault,
+ MsgIsHighlight: false,
+ MsgIsService: false,
}
}
@@ -227,3 +224,9 @@ func (msg *BaseMessage) IsService() bool {
func (msg *BaseMessage) SetIsService(isService bool) {
msg.MsgIsService = isService
}
+
+func (msg *BaseMessage) Draw(screen mauview.Screen) {
+ for y, line := range msg.buffer {
+ line.Draw(screen, 0, y)
+ }
+}
diff --git a/ui/messages/expandedtextmessage.go b/ui/messages/expandedtextmessage.go
index d889771..044613f 100644
--- a/ui/messages/expandedtextmessage.go
+++ b/ui/messages/expandedtextmessage.go
@@ -58,8 +58,3 @@ func (msg *ExpandedTextMessage) PlainText() string {
func (msg *ExpandedTextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.calculateBufferWithText(prefs, msg.MsgText, width)
}
-
-// RecalculateBuffer calculates the buffer again with the previously provided width.
-func (msg *ExpandedTextMessage) RecalculateBuffer() {
- msg.CalculateBuffer(msg.prevPrefs, msg.prevBufferWidth)
-}
diff --git a/ui/messages/htmlmessage.go b/ui/messages/htmlmessage.go
index de4b30c..33e4d87 100644
--- a/ui/messages/htmlmessage.go
+++ b/ui/messages/htmlmessage.go
@@ -17,6 +17,8 @@
package messages
import (
+ "fmt"
+ "strings"
"time"
"github.com/mattn/go-runewidth"
@@ -57,9 +59,13 @@ func (hw *HTMLMessage) OnPasteEvent(event mauview.PasteEvent) bool {
}
func (hw *HTMLMessage) CalculateBuffer(preferences config.UserPreferences, width int) {
+ if width <= 0 {
+ panic("Negative width in CalculateBuffer")
+ }
// TODO account for bare messages in initial startX
startX := 0
hw.Root.calculateBuffer(width, startX, preferences.BareMessageView)
+ //debug.Print(hw.Root.String())
}
func (hw *HTMLMessage) Height() int {
@@ -109,8 +115,8 @@ func (he *HTMLEntity) Draw(screen mauview.Screen) {
}
if len(he.Children) > 0 {
proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: he.Indent, Width: width - he.Indent}
- for _, entity := range he.Children {
- if entity.Block {
+ for i, entity := range he.Children {
+ if i != 0 && entity.startX == 0 {
proxyScreen.OffsetY++
}
proxyScreen.Height = entity.height
@@ -120,38 +126,87 @@ func (he *HTMLEntity) Draw(screen mauview.Screen) {
}
}
+func (he *HTMLEntity) String() string {
+ var buf strings.Builder
+ buf.WriteString("&HTMLEntity{\n")
+ _, _ = fmt.Fprintf(&buf, ` Tag="%s", Style=%d, Block=%t, Indent=%d, startX=%d, height=%d,\n`,
+ he.Tag, he.Style, he.Block, he.Indent, he.startX, he.height)
+ _, _ = fmt.Fprintf(&buf, ` Buffer=["%s"]`, strings.Join(he.buffer, "\", \""))
+ if len(he.Text) > 0 {
+ buf.WriteString(",\n")
+ _, _ = fmt.Fprintf(&buf, ` Text="%s"`, he.Text)
+ }
+ if len(he.Children) > 0 {
+ buf.WriteString(",\n")
+ buf.WriteString(" Children={")
+ for _, child := range he.Children {
+ buf.WriteString("\n ")
+ buf.WriteString(strings.Join(strings.Split(strings.TrimRight(child.String(), "\n"), "\n"), "\n "))
+ }
+ buf.WriteString("\n },")
+ }
+ buf.WriteString("\n},\n")
+ return buf.String()
+}
+
func (he *HTMLEntity) calculateBuffer(width, startX int, bare bool) int {
+ he.startX = startX
+ if he.Block {
+ he.startX = 0
+ }
+ he.height = 0
if len(he.Children) > 0 {
- childStartX := 0
+ childStartX := he.startX
for _, entity := range he.Children {
+ if entity.Block || childStartX == 0 || he.height == 0 {
+ he.height++
+ }
childStartX = entity.calculateBuffer(width-he.Indent, childStartX, bare)
he.height += entity.height - 1
}
+ if len(he.Text) == 0 && !he.Block {
+ return childStartX
+ }
}
- if len(he.Text) > 0 && width != he.prevWidth {
+ if len(he.Text) > 0 {
he.prevWidth = width
- he.buffer = make([]string, 0, 1)
- text := he.Text
- if !he.Block {
- he.startX = startX
- } else {
- startX = 0
+ if he.buffer == nil {
+ he.buffer = []string{}
}
+ bufPtr := 0
+ text := he.Text
+ textStartX := he.startX
for {
- extract := runewidth.Truncate(text, width-startX, "")
- extract = trim(extract, text, bare)
- he.buffer = append(he.buffer, extract)
+ extract := runewidth.Truncate(text, width-textStartX, "")
+ extract, wordWrapped := trim(extract, text, bare)
+ if !wordWrapped && textStartX > 0 {
+ if bufPtr < len(he.buffer) {
+ he.buffer[bufPtr] = ""
+ } else {
+ he.buffer = append(he.buffer, "")
+ }
+ bufPtr++
+ textStartX = 0
+ continue
+ }
+ if bufPtr < len(he.buffer) {
+ he.buffer[bufPtr] = extract
+ } else {
+ he.buffer = append(he.buffer, extract)
+ }
+ bufPtr++
text = text[len(extract):]
- startX = 0
if len(text) == 0 {
+ he.buffer = he.buffer[:bufPtr]
he.height += len(he.buffer)
// This entity is over, return the startX for the next entity
if he.Block {
// ...except if it's a block entity
return 0
}
- return runewidth.StringWidth(extract)
+ return textStartX + runewidth.StringWidth(extract)
}
+ textStartX = 0
}
}
return 0
@@ -164,12 +219,13 @@ func (he *HTMLEntity) calculateBuffer(width, startX int, bare bool) int {
spacePattern = regexp.MustCompile(`\s+`)
)*/
-func trim(extract, full string, bare bool) string {
+func trim(extract, full string, bare bool) (string, bool) {
if len(extract) == len(full) {
- return extract
+ return extract, true
}
if spaces := spacePattern.FindStringIndex(full[len(extract):]); spaces != nil && spaces[0] == 0 {
extract = full[:len(extract)+spaces[1]]
+ //return extract, true
}
regex := boundaryPattern
if bare {
@@ -180,8 +236,9 @@ func trim(extract, full string, bare bool) string {
if match := matches[len(matches)-1]; len(match) >= 2 {
if until := match[1]; until < len(extract) {
extract = extract[:until]
+ return extract, true
}
}
}
- return extract
+ return extract, len(extract) > 0 && extract[len(extract)-1] == ' '
}
diff --git a/ui/messages/imagemessage.go b/ui/messages/imagemessage.go
index cad76a4..968f29e 100644
--- a/ui/messages/imagemessage.go
+++ b/ui/messages/imagemessage.go
@@ -112,11 +112,4 @@ func (msg *ImageMessage) CalculateBuffer(prefs config.UserPreferences, width int
}
msg.buffer = image.Render()
- msg.prevBufferWidth = width
- msg.prevPrefs = prefs
-}
-
-// RecalculateBuffer calculates the buffer again with the previously provided width.
-func (msg *ImageMessage) RecalculateBuffer() {
- msg.CalculateBuffer(msg.prevPrefs, msg.prevBufferWidth)
}
diff --git a/ui/messages/message.go b/ui/messages/message.go
index e1888e6..db93879 100644
--- a/ui/messages/message.go
+++ b/ui/messages/message.go
@@ -19,7 +19,7 @@ package messages
import (
"maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/interface"
- "maunium.net/go/gomuks/ui/messages/tstring"
+ "maunium.net/go/mauview"
)
// UIMessage is a wrapper for the content and metadata of a Matrix message intended to be displayed.
@@ -27,7 +27,7 @@ type UIMessage interface {
ifc.Message
CalculateBuffer(preferences config.UserPreferences, width int)
- Buffer() []tstring.TString
+ Draw(screen mauview.Screen)
Height() int
PlainText() string
diff --git a/ui/messages/parser/htmlparser.go b/ui/messages/parser/htmlparser.go
index 3d1548b..9a9c2d1 100644
--- a/ui/messages/parser/htmlparser.go
+++ b/ui/messages/parser/htmlparser.go
@@ -266,6 +266,9 @@ func (parser *htmlParser) singleNodeToEntity(node *html.Node, stripLinebreak boo
case html.ElementNode:
return parser.tagNodeToEntity(node, stripLinebreak)
case html.DocumentNode:
+ if node.FirstChild.Data == "html" && node.FirstChild.NextSibling == nil {
+ return parser.singleNodeToEntity(node.FirstChild, stripLinebreak)
+ }
return &messages.HTMLEntity{
Tag: "html",
Children: parser.nodeToEntities(node.FirstChild, stripLinebreak),
diff --git a/ui/messages/textbase.go b/ui/messages/textbase.go
index 01e7b5c..321d998 100644
--- a/ui/messages/textbase.go
+++ b/ui/messages/textbase.go
@@ -92,6 +92,4 @@ func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, te
str = str[len(extract):]
}
}
- msg.prevBufferWidth = width
- msg.prevPrefs = prefs
}
diff --git a/ui/messages/textmessage.go b/ui/messages/textmessage.go
index 8ce9482..6364659 100644
--- a/ui/messages/textmessage.go
+++ b/ui/messages/textmessage.go
@@ -90,8 +90,3 @@ func (msg *TextMessage) PlainText() string {
func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.calculateBufferWithText(prefs, msg.getCache(), width)
}
-
-// RecalculateBuffer calculates the buffer again with the previously provided width.
-func (msg *TextMessage) RecalculateBuffer() {
- msg.CalculateBuffer(msg.prevPrefs, msg.prevBufferWidth)
-}