More changes to do #91

This commit is contained in:
Tulir Asokan 2019-04-07 18:21:38 +03:00
parent 21b81ccb27
commit b0c4ef81e9
11 changed files with 158 additions and 86 deletions

View File

@ -76,12 +76,12 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
Gomuks: parent.gmx, Gomuks: parent.gmx,
}, },
aliases: map[string]*Alias{ aliases: map[string]*Alias{
"part": {"leave"}, "part": {"leave"},
"send": {"sendevent"}, "send": {"sendevent"},
"msend": {"msendevent"}, "msend": {"msendevent"},
"state": {"setstate"}, "state": {"setstate"},
"mstate":{"msetstate"}, "mstate": {"msetstate"},
"rb": {"rainbow"}, "rb": {"rainbow"},
}, },
commands: map[string]CommandHandler{ commands: map[string]CommandHandler{
"unknown-command": cmdUnknownCommand, "unknown-command": cmdUnknownCommand,
@ -102,6 +102,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor {
"msetstate": cmdMSetState, "msetstate": cmdMSetState,
"rainbow": cmdRainbow, "rainbow": cmdRainbow,
"invite": cmdInvite, "invite": cmdInvite,
"hprof": cmdHeapProfile,
}, },
} }
} }

View File

@ -19,6 +19,9 @@ package ui
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"runtime"
"runtime/pprof"
"strings" "strings"
"unicode" "unicode"
@ -69,6 +72,18 @@ var rainbow = GradientTable{
{colorful.LinearRgb(1, 0, 0.5), 1}, {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. // TODO this command definitely belongs in a plugin once we have a plugin system.
func cmdRainbow(cmd *Command) { func cmdRainbow(cmd *Command) {
text := strings.Join(cmd.Args, " ") text := strings.Join(cmd.Args, " ")

View File

@ -75,6 +75,7 @@ func NewMessageView(parent *RoomView) *MessageView {
textBuffer: make([]tstring.TString, 0), textBuffer: make([]tstring.TString, 0),
metaBuffer: make([]ifc.MessageMeta, 0), metaBuffer: make([]ifc.MessageMeta, 0),
width: 80,
widestSender: 5, widestSender: 5,
prevWidth: -1, prevWidth: -1,
prevHeight: -1, prevHeight: -1,
@ -159,8 +160,8 @@ func (view *MessageView) appendBuffer(message messages.UIMessage) {
} }
} }
view.textBuffer = append(view.textBuffer, message.Buffer()...) for i := 0; i < message.Height(); i++ {
for range message.Buffer() { view.textBuffer = append(view.textBuffer, nil)
view.metaBuffer = append(view.metaBuffer, message) view.metaBuffer = append(view.metaBuffer, message)
} }
view.prevMsgCount++ view.prevMsgCount++
@ -200,10 +201,15 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
end++ end++
} }
view.textBuffer = append(append(view.textBuffer[0:start], new.Buffer()...), view.textBuffer[end:]...) if new.Height() == 0 {
if len(new.Buffer()) != end-start { 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] metaBuffer := view.metaBuffer[0:start]
for range new.Buffer() { for i := 0; i < new.Height(); i++ {
metaBuffer = append(metaBuffer, new) metaBuffer = append(metaBuffer, new)
} }
view.metaBuffer = append(metaBuffer, view.metaBuffer[end:]...) view.metaBuffer = append(metaBuffer, view.metaBuffer[end:]...)
@ -504,16 +510,22 @@ func (view *MessageView) Draw(screen mauview.Screen) {
meta.SenderColor()) meta.SenderColor())
} }
prevMeta = meta 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
}
}
} }
text.Draw(screen, messageX, line) 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)
}
} }
} }

View File

@ -21,9 +21,9 @@ import (
"time" "time"
"maunium.net/go/mautrix" "maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell" "maunium.net/go/tcell"
"maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/interface" "maunium.net/go/gomuks/interface"
"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"
@ -34,33 +34,30 @@ func init() {
} }
type BaseMessage struct { type BaseMessage struct {
MsgID string MsgID string
MsgType mautrix.MessageType MsgType mautrix.MessageType
MsgSenderID string MsgSenderID string
MsgSender string MsgSender string
MsgSenderColor tcell.Color MsgSenderColor tcell.Color
MsgTimestamp time.Time MsgTimestamp time.Time
MsgState ifc.MessageState MsgState ifc.MessageState
MsgIsHighlight bool MsgIsHighlight bool
MsgIsService bool MsgIsService bool
buffer []tstring.TString buffer []tstring.TString
plainBuffer []tstring.TString plainBuffer []tstring.TString
prevBufferWidth int
prevPrefs config.UserPreferences
} }
func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, timestamp time.Time) BaseMessage { func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, timestamp time.Time) BaseMessage {
return BaseMessage{ return BaseMessage{
MsgSenderID: sender, MsgSenderID: sender,
MsgSender: displayname, MsgSender: displayname,
MsgTimestamp: timestamp, MsgTimestamp: timestamp,
MsgSenderColor: widget.GetHashColor(sender), MsgSenderColor: widget.GetHashColor(sender),
MsgType: msgtype, MsgType: msgtype,
MsgID: id, MsgID: id,
prevBufferWidth: 0, MsgState: ifc.MessageStateDefault,
MsgState: ifc.MessageStateDefault, MsgIsHighlight: false,
MsgIsHighlight: false, MsgIsService: false,
MsgIsService: false,
} }
} }
@ -227,3 +224,9 @@ func (msg *BaseMessage) IsService() bool {
func (msg *BaseMessage) SetIsService(isService bool) { func (msg *BaseMessage) SetIsService(isService bool) {
msg.MsgIsService = isService msg.MsgIsService = isService
} }
func (msg *BaseMessage) Draw(screen mauview.Screen) {
for y, line := range msg.buffer {
line.Draw(screen, 0, y)
}
}

View File

@ -58,8 +58,3 @@ func (msg *ExpandedTextMessage) PlainText() string {
func (msg *ExpandedTextMessage) CalculateBuffer(prefs config.UserPreferences, width int) { func (msg *ExpandedTextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.calculateBufferWithText(prefs, msg.MsgText, width) 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)
}

View File

@ -17,6 +17,8 @@
package messages package messages
import ( import (
"fmt"
"strings"
"time" "time"
"github.com/mattn/go-runewidth" "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) { 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 // TODO account for bare messages in initial startX
startX := 0 startX := 0
hw.Root.calculateBuffer(width, startX, preferences.BareMessageView) hw.Root.calculateBuffer(width, startX, preferences.BareMessageView)
//debug.Print(hw.Root.String())
} }
func (hw *HTMLMessage) Height() int { func (hw *HTMLMessage) Height() int {
@ -109,8 +115,8 @@ func (he *HTMLEntity) Draw(screen mauview.Screen) {
} }
if len(he.Children) > 0 { if len(he.Children) > 0 {
proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: he.Indent, Width: width - he.Indent} proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: he.Indent, Width: width - he.Indent}
for _, entity := range he.Children { for i, entity := range he.Children {
if entity.Block { if i != 0 && entity.startX == 0 {
proxyScreen.OffsetY++ proxyScreen.OffsetY++
} }
proxyScreen.Height = entity.height proxyScreen.Height = entity.height
@ -120,38 +126,87 @@ func (he *HTMLEntity) Draw(screen mauview.Screen) {
} }
} }
func (he *HTMLEntity) calculateBuffer(width, startX int, bare bool) int { 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 { if len(he.Children) > 0 {
childStartX := 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 := he.startX
for _, entity := range he.Children { for _, entity := range he.Children {
if entity.Block || childStartX == 0 || he.height == 0 {
he.height++
}
childStartX = entity.calculateBuffer(width-he.Indent, childStartX, bare) childStartX = entity.calculateBuffer(width-he.Indent, childStartX, bare)
he.height += entity.height - 1 he.height += entity.height - 1
} }
} if len(he.Text) == 0 && !he.Block {
if len(he.Text) > 0 && width != he.prevWidth { return childStartX
he.prevWidth = width
he.buffer = make([]string, 0, 1)
text := he.Text
if !he.Block {
he.startX = startX
} else {
startX = 0
} }
}
if len(he.Text) > 0 {
he.prevWidth = width
if he.buffer == nil {
he.buffer = []string{}
}
bufPtr := 0
text := he.Text
textStartX := he.startX
for { for {
extract := runewidth.Truncate(text, width-startX, "") extract := runewidth.Truncate(text, width-textStartX, "")
extract = trim(extract, text, bare) extract, wordWrapped := trim(extract, text, bare)
he.buffer = append(he.buffer, extract) 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):] text = text[len(extract):]
startX = 0
if len(text) == 0 { if len(text) == 0 {
he.buffer = he.buffer[:bufPtr]
he.height += len(he.buffer) he.height += len(he.buffer)
// This entity is over, return the startX for the next entity // This entity is over, return the startX for the next entity
if he.Block { if he.Block {
// ...except if it's a block entity // ...except if it's a block entity
return 0 return 0
} }
return runewidth.StringWidth(extract) return textStartX + runewidth.StringWidth(extract)
} }
textStartX = 0
} }
} }
return 0 return 0
@ -164,12 +219,13 @@ func (he *HTMLEntity) calculateBuffer(width, startX int, bare bool) int {
spacePattern = regexp.MustCompile(`\s+`) 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) { if len(extract) == len(full) {
return extract return extract, true
} }
if spaces := spacePattern.FindStringIndex(full[len(extract):]); spaces != nil && spaces[0] == 0 { if spaces := spacePattern.FindStringIndex(full[len(extract):]); spaces != nil && spaces[0] == 0 {
extract = full[:len(extract)+spaces[1]] extract = full[:len(extract)+spaces[1]]
//return extract, true
} }
regex := boundaryPattern regex := boundaryPattern
if bare { if bare {
@ -180,8 +236,9 @@ func trim(extract, full string, bare bool) string {
if match := matches[len(matches)-1]; len(match) >= 2 { if match := matches[len(matches)-1]; len(match) >= 2 {
if until := match[1]; until < len(extract) { if until := match[1]; until < len(extract) {
extract = extract[:until] extract = extract[:until]
return extract, true
} }
} }
} }
return extract return extract, len(extract) > 0 && extract[len(extract)-1] == ' '
} }

View File

@ -112,11 +112,4 @@ func (msg *ImageMessage) CalculateBuffer(prefs config.UserPreferences, width int
} }
msg.buffer = image.Render() 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)
} }

View File

@ -19,7 +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/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. // 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 ifc.Message
CalculateBuffer(preferences config.UserPreferences, width int) CalculateBuffer(preferences config.UserPreferences, width int)
Buffer() []tstring.TString Draw(screen mauview.Screen)
Height() int Height() int
PlainText() string PlainText() string

View File

@ -266,6 +266,9 @@ func (parser *htmlParser) singleNodeToEntity(node *html.Node, stripLinebreak boo
case html.ElementNode: case html.ElementNode:
return parser.tagNodeToEntity(node, stripLinebreak) return parser.tagNodeToEntity(node, stripLinebreak)
case html.DocumentNode: case html.DocumentNode:
if node.FirstChild.Data == "html" && node.FirstChild.NextSibling == nil {
return parser.singleNodeToEntity(node.FirstChild, stripLinebreak)
}
return &messages.HTMLEntity{ return &messages.HTMLEntity{
Tag: "html", Tag: "html",
Children: parser.nodeToEntities(node.FirstChild, stripLinebreak), Children: parser.nodeToEntities(node.FirstChild, stripLinebreak),

View File

@ -92,6 +92,4 @@ func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, te
str = str[len(extract):] str = str[len(extract):]
} }
} }
msg.prevBufferWidth = width
msg.prevPrefs = prefs
} }

View File

@ -90,8 +90,3 @@ func (msg *TextMessage) PlainText() string {
func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int) { func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.calculateBufferWithText(prefs, msg.getCache(), width) 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)
}