From db0e24ccc268d0a9c7575d660a9397e53747894b Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 10 Apr 2019 21:06:19 +0300 Subject: Use already parsed events for replies if possible --- ui/messages/html/blockquote.go | 32 ++++++++++++++++++++++ ui/messages/html/break.go | 12 ++++++++ ui/messages/html/codeblock.go | 7 +++++ ui/messages/html/entity.go | 11 +++++--- ui/messages/html/horizontalline.go | 56 ++++++++++++++++++++++++++++++++++++++ ui/messages/html/list.go | 33 ++++++++++++++++++++++ ui/messages/html/parser.go | 10 +++++-- 7 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 ui/messages/html/horizontalline.go (limited to 'ui/messages/html') diff --git a/ui/messages/html/blockquote.go b/ui/messages/html/blockquote.go index 30ce52e..17799a2 100644 --- a/ui/messages/html/blockquote.go +++ b/ui/messages/html/blockquote.go @@ -18,6 +18,7 @@ package html import ( "fmt" + "strings" "maunium.net/go/mauview" ) @@ -37,6 +38,10 @@ func NewBlockquoteEntity(children []Entity) *BlockquoteEntity { }} } +func (be *BlockquoteEntity) Clone() Entity { + return &BlockquoteEntity{BaseEntity: be.BaseEntity.Clone().(*BaseEntity)} +} + func (be *BlockquoteEntity) Draw(screen mauview.Screen) { be.BaseEntity.Draw(screen) for y := 0; y < be.height; y++ { @@ -44,6 +49,33 @@ func (be *BlockquoteEntity) Draw(screen mauview.Screen) { } } +func (be *BlockquoteEntity) PlainText() string { + if len(be.Children) == 0 { + return "" + } + var buf strings.Builder + newlined := false + for i, child := range be.Children { + if i != 0 && child.IsBlock() && !newlined { + buf.WriteRune('\n') + } + newlined = false + for i, row := range strings.Split(child.PlainText(), "\n") { + if i != 0 { + buf.WriteRune('\n') + } + buf.WriteRune('>') + buf.WriteRune(' ') + buf.WriteString(row) + } + if child.IsBlock() { + buf.WriteRune('\n') + newlined = true + } + } + return strings.TrimSpace(buf.String()) +} + func (be *BlockquoteEntity) String() string { return fmt.Sprintf("&html.BlockquoteEntity{%s},\n", be.BaseEntity) } diff --git a/ui/messages/html/break.go b/ui/messages/html/break.go index d400f00..ea67ead 100644 --- a/ui/messages/html/break.go +++ b/ui/messages/html/break.go @@ -26,3 +26,15 @@ func NewBreakEntity() *BreakEntity { Block: true, }} } + +func (be *BreakEntity) Clone() Entity { + return NewBreakEntity() +} + +func (be *BreakEntity) PlainText() string { + return "\n" +} + +func (be *BreakEntity) String() string { + return "&html.BreakEntity{},\n" +} diff --git a/ui/messages/html/codeblock.go b/ui/messages/html/codeblock.go index ec6181d..4a0766c 100644 --- a/ui/messages/html/codeblock.go +++ b/ui/messages/html/codeblock.go @@ -37,6 +37,13 @@ func NewCodeBlockEntity(children []Entity, background tcell.Style) *CodeBlockEnt } } +func (ce *CodeBlockEntity) Clone() Entity { + return &CodeBlockEntity{ + BaseEntity: ce.BaseEntity.Clone().(*BaseEntity), + Background: ce.Background, + } +} + func (ce *CodeBlockEntity) Draw(screen mauview.Screen) { screen.Fill(' ', ce.Background) ce.BaseEntity.Draw(screen) diff --git a/ui/messages/html/entity.go b/ui/messages/html/entity.go index 2ce37a8..be58d61 100644 --- a/ui/messages/html/entity.go +++ b/ui/messages/html/entity.go @@ -165,17 +165,20 @@ func (he *BaseEntity) PlainText() string { buf.WriteString(he.Text) newlined := false for _, child := range he.Children { - if child.IsBlock() && !newlined { + text := child.PlainText() + if !strings.HasPrefix(text, "\n") && child.IsBlock() && !newlined { buf.WriteRune('\n') } newlined = false - buf.WriteString(child.PlainText()) + buf.WriteString(text) if child.IsBlock() { - buf.WriteRune('\n') + if !strings.HasSuffix(text, "\n") { + buf.WriteRune('\n') + } newlined = true } } - return buf.String() + return strings.TrimSpace(buf.String()) } // Draw draws this entity onto the given mauview Screen. diff --git a/ui/messages/html/horizontalline.go b/ui/messages/html/horizontalline.go new file mode 100644 index 0000000..32761aa --- /dev/null +++ b/ui/messages/html/horizontalline.go @@ -0,0 +1,56 @@ +// gomuks - A terminal Matrix client written in Go. +// Copyright (C) 2019 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 html + +import ( + "strings" + + "maunium.net/go/mauview" +) + +type HorizontalLineEntity struct { + *BaseEntity +} + +const HorizontalLineChar = '━' + +func NewHorizontalLineEntity() *HorizontalLineEntity { + return &HorizontalLineEntity{&BaseEntity{ + Tag: "hr", + Block: true, + DefaultHeight: 1, + }} +} + +func (he *HorizontalLineEntity) Clone() Entity { + return NewHorizontalLineEntity() +} + +func (he *HorizontalLineEntity) Draw(screen mauview.Screen) { + width, _ := screen.Size() + for x := 0; x < width; x++ { + screen.SetContent(x, 0, HorizontalLineChar, nil, he.Style) + } +} + +func (he *HorizontalLineEntity) PlainText() string { + return strings.Repeat(string(HorizontalLineChar), 5) +} + +func (he *HorizontalLineEntity) String() string { + return "&html.HorizontalLineEntity{},\n" +} diff --git a/ui/messages/html/list.go b/ui/messages/html/list.go index 9f45b92..c611e66 100644 --- a/ui/messages/html/list.go +++ b/ui/messages/html/list.go @@ -56,6 +56,14 @@ func NewListEntity(ordered bool, start int, children []Entity) *ListEntity { return entity } +func (le *ListEntity) Clone() Entity { + return &ListEntity{ + BaseEntity: le.BaseEntity.Clone().(*BaseEntity), + Ordered: le.Ordered, + Start: le.Start, + } +} + func (le *ListEntity) Draw(screen mauview.Screen) { width, _ := screen.Size() @@ -75,6 +83,31 @@ func (le *ListEntity) Draw(screen mauview.Screen) { } } +func (le *ListEntity) PlainText() string { + if len(le.Children) == 0 { + return "" + } + var buf strings.Builder + for i, child := range le.Children { + indent := strings.Repeat(" ", le.Indent) + if le.Ordered { + number := le.Start + i + _, _ = fmt.Fprintf(&buf, "%d. %s", number, strings.Repeat(" ", le.Indent-2-digits(number))) + } else { + buf.WriteString("● ") + } + for j, row := range strings.Split(child.PlainText(), "\n") { + if j != 0 { + buf.WriteRune('\n') + buf.WriteString(indent) + } + buf.WriteString(row) + } + buf.WriteRune('\n') + } + return strings.TrimSpace(buf.String()) +} + func (le *ListEntity) String() string { return fmt.Sprintf("&html.ListEntity{Ordered=%t, Start=%d, Base=%s},\n", le.Ordered, le.Start, le.BaseEntity) } diff --git a/ui/messages/html/parser.go b/ui/messages/html/parser.go index 0bdf483..9e08ab7 100644 --- a/ui/messages/html/parser.go +++ b/ui/messages/html/parser.go @@ -111,7 +111,7 @@ func (parser *htmlParser) basicFormatToEntity(node *html.Node) Entity { entity.AdjustStyle(AdjustStyleBold) case "i", "em": entity.AdjustStyle(AdjustStyleItalic) - case "s", "del": + case "s", "del", "strike": entity.AdjustStyle(AdjustStyleStrikethrough) case "u", "ins": entity.AdjustStyle(AdjustStyleUnderline) @@ -237,7 +237,7 @@ func (parser *htmlParser) syntaxHighlight(text, language string) Entity { children := make([]Entity, len(tokens)) for i, token := range tokens { if token.Value == "\n" { - children[i] = &BaseEntity{Block: true, Tag: "br"} + children[i] = NewBreakEntity() } else { children[i] = &BaseEntity{ Tag: token.Type.String(), @@ -282,7 +282,7 @@ func (parser *htmlParser) tagNodeToEntity(node *html.Node) Entity { return parser.headerToEntity(node) case "br": return NewBreakEntity() - case "b", "strong", "i", "em", "s", "del", "u", "ins", "font": + case "b", "strong", "i", "em", "s", "strike", "del", "u", "ins", "font": return parser.basicFormatToEntity(node) case "a": return parser.linkToEntity(node) @@ -290,6 +290,10 @@ func (parser *htmlParser) tagNodeToEntity(node *html.Node) Entity { return parser.imageToEntity(node) case "pre": return parser.codeblockToEntity(node) + case "hr": + return NewHorizontalLineEntity() + case "mx-reply": + return nil default: return &BaseEntity{ Tag: node.Data, -- cgit v1.2.3