aboutsummaryrefslogtreecommitdiff
path: root/ui/messages/htmlmessage.go
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2019-04-09 18:42:49 +0300
committerTulir Asokan <tulir@maunium.net>2019-04-09 18:42:49 +0300
commit2b6c435e5020535a916e23b09d47608d788eaf05 (patch)
treee18d7a90b5119bd9dec0b07265b518eef654458d /ui/messages/htmlmessage.go
parent927be9bdcd15d77bb44280c6b8de2f72b6a47254 (diff)
Refactor message parsing things
Diffstat (limited to 'ui/messages/htmlmessage.go')
-rw-r--r--ui/messages/htmlmessage.go381
1 files changed, 9 insertions, 372 deletions
diff --git a/ui/messages/htmlmessage.go b/ui/messages/htmlmessage.go
index eac0841..ed8b7c1 100644
--- a/ui/messages/htmlmessage.go
+++ b/ui/messages/htmlmessage.go
@@ -17,40 +17,33 @@
package messages
import (
- "fmt"
- "math"
- "strings"
- "time"
-
- "github.com/mattn/go-runewidth"
+ "maunium.net/go/gomuks/ui/messages/html"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell"
"maunium.net/go/gomuks/config"
- "maunium.net/go/gomuks/ui/widget"
)
type HTMLMessage struct {
BaseMessage
- Root HTMLEntity
-
- FocusedBackground tcell.Color
-
- focused bool
+ Root html.Entity
+ FocusedBg tcell.Color
+ focused bool
}
-func NewHTMLMessage(id, sender, displayname string, msgtype mautrix.MessageType, root HTMLEntity, timestamp time.Time) UIMessage {
+func NewHTMLMessage(event *mautrix.Event, displayname string, root html.Entity) UIMessage {
return &HTMLMessage{
- BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
+ BaseMessage: newBaseMessage(event.ID, event.Sender, displayname, event.Content.MsgType, unixToTime(event.Timestamp)),
Root: root,
}
}
+
func (hw *HTMLMessage) Draw(screen mauview.Screen) {
if hw.focused {
- screen.SetStyle(tcell.StyleDefault.Background(hw.FocusedBackground))
+ screen.SetStyle(tcell.StyleDefault.Background(hw.FocusedBg))
}
screen.Clear()
hw.Root.Draw(screen)
@@ -82,7 +75,7 @@ func (hw *HTMLMessage) CalculateBuffer(preferences config.UserPreferences, width
}
// TODO account for bare messages in initial startX
startX := 0
- hw.Root.calculateBuffer(width, startX, preferences.BareMessageView)
+ hw.Root.CalculateBuffer(width, startX, preferences.BareMessageView)
}
func (hw *HTMLMessage) Height() int {
@@ -96,359 +89,3 @@ func (hw *HTMLMessage) PlainText() string {
func (hw *HTMLMessage) NotificationContent() string {
return hw.Root.PlainText()
}
-
-type AdjustStyleFunc func(tcell.Style) tcell.Style
-
-type HTMLEntity interface {
- AdjustStyle(AdjustStyleFunc) HTMLEntity
- Draw(screen mauview.Screen)
- IsBlock() bool
- GetTag() string
- PlainText() string
- String() string
- Height() int
-
- calculateBuffer(width, startX int, bare bool) int
- getStartX() int
-}
-
-type BlockquoteEntity struct {
- *BaseHTMLEntity
-}
-
-func NewBlockquoteEntity(children []HTMLEntity) *BlockquoteEntity {
- return &BlockquoteEntity{&BaseHTMLEntity{
- Tag: "blockquote",
- Children: children,
- Block: true,
- Indent: 2,
- }}
-}
-
-func (be *BlockquoteEntity) Draw(screen mauview.Screen) {
- be.BaseHTMLEntity.Draw(screen)
- for y := 0; y < be.height; y++ {
- screen.SetContent(0, y, '>', nil, be.Style)
- }
-}
-
-func (be *BlockquoteEntity) String() string {
- return fmt.Sprintf("&BlockquoteEntity{%s},\n", be.BaseHTMLEntity)
-}
-
-type ListEntity struct {
- *BaseHTMLEntity
- Ordered bool
- Start int
-}
-
-func digits(num int) int {
- if num <= 0 {
- return 0
- }
- return int(math.Floor(math.Log10(float64(num))) + 1)
-}
-
-func NewListEntity(ordered bool, start int, children []HTMLEntity) *ListEntity {
- entity := &ListEntity{
- BaseHTMLEntity: &BaseHTMLEntity{
- Tag: "ul",
- Children: children,
- Block: true,
- Indent: 2,
- },
- Ordered: ordered,
- Start: start,
- }
- if ordered {
- entity.Tag = "ol"
- entity.Indent += digits(start + len(children) - 1)
- }
- return entity
-}
-
-func (le *ListEntity) Draw(screen mauview.Screen) {
- width, _ := screen.Size()
-
- proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: le.Indent, Width: width - le.Indent, Style: le.Style}
- for i, entity := range le.Children {
- proxyScreen.Height = entity.Height()
- if le.Ordered {
- number := le.Start + i
- line := fmt.Sprintf("%d. %s", number, strings.Repeat(" ", le.Indent-2-digits(number)))
- widget.WriteLine(screen, mauview.AlignLeft, line, 0, proxyScreen.OffsetY, le.Indent, le.Style)
- } else {
- screen.SetContent(0, proxyScreen.OffsetY, '●', nil, le.Style)
- }
- entity.Draw(proxyScreen)
- proxyScreen.SetStyle(le.Style)
- proxyScreen.OffsetY += entity.Height()
- }
-}
-
-func (le *ListEntity) String() string {
- return fmt.Sprintf("&ListEntity{Ordered=%t, Start=%d, Base=%s},\n", le.Ordered, le.Start, le.BaseHTMLEntity)
-}
-
-type CodeBlockEntity struct {
- *BaseHTMLEntity
- Background tcell.Style
-}
-
-func NewCodeBlockEntity(children []HTMLEntity, background tcell.Style) *CodeBlockEntity {
- return &CodeBlockEntity{
- BaseHTMLEntity: &BaseHTMLEntity{
- Tag: "pre",
- Block: true,
- Children: children,
- },
- Background: background,
- }
-}
-
-func (ce *CodeBlockEntity) Draw(screen mauview.Screen) {
- screen.Fill(' ', ce.Background)
- ce.BaseHTMLEntity.Draw(screen)
-}
-
-func (ce *CodeBlockEntity) AdjustStyle(fn AdjustStyleFunc) HTMLEntity {
- return ce
-}
-
-type BreakEntity struct {
- *BaseHTMLEntity
-}
-
-func NewBreakEntity() *BreakEntity {
- return &BreakEntity{&BaseHTMLEntity{
- Tag: "br",
- Block: true,
- }}
-}
-
-type BaseHTMLEntity struct {
- // Permanent variables
- Tag string
- Text string
- Style tcell.Style
- Children []HTMLEntity
- Block bool
- Indent int
-
- DefaultHeight int
-
- // Non-permanent variables (calculated buffer data)
- buffer []string
- prevWidth int
- startX int
- height int
-}
-
-func NewHTMLTextEntity(text string) *BaseHTMLEntity {
- return &BaseHTMLEntity{
- Tag: "text",
- Text: text,
- }
-}
-
-func NewHTMLEntity(tag string, children []HTMLEntity, block bool) *BaseHTMLEntity {
- return &BaseHTMLEntity{
- Tag: tag,
- Children: children,
- Block: block,
- }
-}
-
-func (he *BaseHTMLEntity) AdjustStyle(fn AdjustStyleFunc) HTMLEntity {
- for _, child := range he.Children {
- child.AdjustStyle(fn)
- }
- he.Style = fn(he.Style)
- return he
-}
-
-func (he *BaseHTMLEntity) IsBlock() bool {
- return he.Block
-}
-
-func (he *BaseHTMLEntity) GetTag() string {
- return he.Tag
-}
-
-func (he *BaseHTMLEntity) Height() int {
- return he.height
-}
-
-func (he *BaseHTMLEntity) getStartX() int {
- return he.startX
-}
-
-func (he *BaseHTMLEntity) String() string {
- var buf strings.Builder
- buf.WriteString("&BaseHTMLEntity{\n")
- _, _ = fmt.Fprintf(&buf, ` Tag="%s", Style=%d, Block=%t, Indent=%d, startX=%d, height=%d,`,
- he.Tag, he.Style, he.Block, he.Indent, he.startX, he.height)
- buf.WriteRune('\n')
- _, _ = 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 *BaseHTMLEntity) PlainText() string {
- if len(he.Children) == 0 {
- return he.Text
- }
- var buf strings.Builder
- buf.WriteString(he.Text)
- newlined := false
- for _, child := range he.Children {
- if child.IsBlock() && !newlined {
- buf.WriteRune('\n')
- }
- newlined = false
- buf.WriteString(child.PlainText())
- if child.IsBlock() {
- buf.WriteRune('\n')
- newlined = true
- }
- }
- return buf.String()
-}
-
-func (he *BaseHTMLEntity) Draw(screen mauview.Screen) {
- width, _ := screen.Size()
- if len(he.buffer) > 0 {
- x := he.startX
- for y, line := range he.buffer {
- widget.WriteLine(screen, mauview.AlignLeft, line, x, y, width, he.Style)
- x = 0
- }
- }
- if len(he.Children) > 0 {
- prevBreak := false
- proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: he.Indent, Width: width - he.Indent, Style: he.Style}
- for i, entity := range he.Children {
- if i != 0 && entity.getStartX() == 0 {
- proxyScreen.OffsetY++
- }
- proxyScreen.Height = entity.Height()
- entity.Draw(proxyScreen)
- proxyScreen.SetStyle(he.Style)
- proxyScreen.OffsetY += entity.Height() - 1
- _, isBreak := entity.(*BreakEntity)
- if prevBreak && isBreak {
- proxyScreen.OffsetY++
- }
- prevBreak = isBreak
- }
- }
-}
-
-func (he *BaseHTMLEntity) 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
- prevBreak := false
- for _, entity := range he.Children {
- if entity.IsBlock() || childStartX == 0 || he.height == 0 {
- he.height++
- }
- childStartX = entity.calculateBuffer(width-he.Indent, childStartX, bare)
- he.height += entity.Height() - 1
- _, isBreak := entity.(*BreakEntity)
- if prevBreak && isBreak {
- he.height++
- }
- prevBreak = isBreak
- }
- if len(he.Text) == 0 && !he.Block {
- return childStartX
- }
- }
- if len(he.Text) > 0 {
- he.prevWidth = width
- if he.buffer == nil {
- he.buffer = []string{}
- }
- bufPtr := 0
- text := he.Text
- textStartX := he.startX
- for {
- // TODO add option no wrap and character wrap options
- 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):]
- 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 textStartX + runewidth.StringWidth(extract)
- }
- textStartX = 0
- }
- }
- if len(he.Text) == 0 && len(he.Children) == 0 {
- he.height = he.DefaultHeight
- }
- return he.startX
-}
-
-func trim(extract, full string, bare bool) (string, bool) {
- if len(extract) == len(full) {
- return extract, true
- }
- if spaces := spacePattern.FindStringIndex(full[len(extract):]); spaces != nil && spaces[0] == 0 {
- extract = full[:len(extract)+spaces[1]]
- }
- regex := boundaryPattern
- if bare {
- regex = bareBoundaryPattern
- }
- matches := regex.FindAllStringIndex(extract, -1)
- if len(matches) > 0 {
- if match := matches[len(matches)-1]; len(match) >= 2 {
- if until := match[1]; until < len(extract) {
- extract = extract[:until]
- return extract, true
- }
- }
- }
- return extract, len(extract) > 0 && extract[len(extract)-1] == ' '
-}