More changes to do #91
This commit is contained in:
		| @@ -80,7 +80,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { | ||||
| 			"send":   {"sendevent"}, | ||||
| 			"msend":  {"msendevent"}, | ||||
| 			"state":  {"setstate"}, | ||||
| 			"mstate":{"msetstate"}, | ||||
| 			"mstate": {"msetstate"}, | ||||
| 			"rb":     {"rainbow"}, | ||||
| 		}, | ||||
| 		commands: map[string]CommandHandler{ | ||||
| @@ -102,6 +102,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { | ||||
| 			"msetstate":       cmdMSetState, | ||||
| 			"rainbow":         cmdRainbow, | ||||
| 			"invite":          cmdInvite, | ||||
| 			"hprof":           cmdHeapProfile, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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, " ") | ||||
|   | ||||
| @@ -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) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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" | ||||
| @@ -45,8 +45,6 @@ type BaseMessage struct { | ||||
| 	MsgIsService   bool | ||||
| 	buffer         []tstring.TString | ||||
| 	plainBuffer    []tstring.TString | ||||
| 	prevBufferWidth int | ||||
| 	prevPrefs       config.UserPreferences | ||||
| } | ||||
|  | ||||
| func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, timestamp time.Time) BaseMessage { | ||||
| @@ -57,7 +55,6 @@ func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, | ||||
| 		MsgSenderColor: widget.GetHashColor(sender), | ||||
| 		MsgType:        msgtype, | ||||
| 		MsgID:          id, | ||||
| 		prevBufferWidth: 0, | ||||
| 		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) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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) 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 { | ||||
| 		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 { | ||||
| 			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) | ||||
| 			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] == ' ' | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
| @@ -92,6 +92,4 @@ func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, te | ||||
| 			str = str[len(extract):] | ||||
| 		} | ||||
| 	} | ||||
| 	msg.prevBufferWidth = width | ||||
| 	msg.prevPrefs = prefs | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user