ref: 925c60a4e2ecf694943317b43b42a18d74982386
parent: cbdef50e06f13d95fc2dc4d8a6ea6df9b6628856
author: Philip Silva <philip.silva@protonmail.com>
date: Sat Jul 24 10:33:57 EDT 2021
Keep display:block elements - so the rows structure stays - work-around cascadia compile panic
--- a/README.md
+++ b/README.md
@@ -19,17 +19,10 @@
## Plan 9
-Setup TLS:
-
-```
-hget https://curl.haxx.se/ca/cacert.pem > /sys/lib/tls/ca.pem
-```
-
-Create mountpoint (only needed on 9legacy):
-
-```
-mkdir /mnt/opossum
-```
+ # Setup TLS
+ hget https://curl.haxx.se/ca/cacert.pem > /sys/lib/tls/ca.pem
+ # Create mountpoint (only needed on 9legacy)
+ mkdir /mnt/opossum
### Binary
--- a/browser/browser.go
+++ b/browser/browser.go
@@ -35,10 +35,11 @@
)
const (
- debugPrintHtml = false
EnterKey = 10
)
+var debugPrintHtml = false
+
// cursor based on Clipart from Francesco 'Architetto' Rollandin
// OpenClipart SVG ID: 163773 from OCAL 0.18 release 16/11/2019
// https://freesvg.org/topo-architetto-francesc-01
@@ -1226,8 +1227,21 @@
}
fallthrough
default:
- // Internal node object
- return InnerNodesToBox(r+1, b, n)
+ if !n.IsInline() {
+ // Explicitly keep block elements to preserve rows from
+ // getting squashed
+ innerContent := InnerNodesToBox(r+1, b, n)
+ if innerContent == nil {
+ return nil
+ }
+ if innerContent.n == n {
+ return innerContent
+ }
+ return NewElement(innerContent, n)
+ } else {
+ // Internal node object
+ return InnerNodesToBox(r+1, b, n)
+ }
}
} else if n.Type() == html.TextNode {
// Leaf text object
@@ -1264,7 +1278,7 @@
if isWrapped(c) {
ls := NewText(c.Content(false), c)
els = append(els, ls...)
- } else if nodes.IsPureTextContent(*n) {
+ } else if nodes.IsPureTextContent(*n) && n.IsInline() {
// Handle text wrapped in unwrappable tags like p, div, ...
ls := NewText(c.Content(false), items[0])
if len(ls) == 0 {
--- a/browser/browser_test.go
+++ b/browser/browser_test.go
@@ -18,6 +18,7 @@
)
func init() {
+ debugPrintHtml = false
log.Debug = true
style.Init(nil)
}
@@ -249,6 +250,10 @@
// 2. Elements are row-like
kids, ok := explodeRow(boxed)
+ if !ok || len(kids) != 1 {
+ t.Errorf("boxed: %+v", boxed)
+ }
+ kids, ok = explodeRow(kids[0].UI.(*Element))
if !ok || len(kids) != 2 {
t.Errorf("boxed: %+v", boxed)
}
@@ -257,7 +262,8 @@
if bel.n.Data() != "(" {
t.Errorf("bel: %+v", bel)
}
- if ael.n.Data() != "span" {
+ if ael.n.Data() != "a" {
+ ael.n.PrintTree()
t.Errorf("ael: %+v %+v '%v'", ael, ael.n, ael.n.Data())
}
if !ael.IsLink || ael.Click == nil {
@@ -296,6 +302,10 @@
// 2. Elements are row-like
kids, ok := explodeRow(boxed)
+ if !ok || len(kids) != 1 {
+ t.Errorf("boxed: %+v, kids: %+v", boxed, kids)
+ }
+ kids, ok = explodeRow(kids[0].UI.(*Element))
if !ok || len(kids) != 3 {
t.Errorf("boxed: %+v, kids: %+v", boxed, kids)
}
@@ -304,11 +314,61 @@
if sel.n.Data() != "span" {
t.Errorf("sel: %+v", sel)
}
- if ael.n.Data() != "edit" {
+ if ael.n.Data() != "a" {
+ ael.n.PrintTree()
t.Errorf("ael: %+v %+v", ael, ael.n)
}
if !ael.IsLink || ael.Click == nil {
t.Errorf("ael: %+v %+v", ael, ael.n)
+ }
+}
+
+func TestInlining3(t *testing.T) {
+ htm := `
+ <body>
+ <p>
+ <span>
+ <tt>bind -ac /dist/plan9front /</tt>
+ </span>
+ </p>
+ <p>
+ <span>
+ <tt>git/pull -u gits://git.9front.org/plan9front/plan9front</tt>
+ </span>
+ </p>
+ </body>
+ `
+ nt, boxed, err := digestHtm(htm)
+ if err != nil {
+ t.Fatalf("digest: %v", err)
+ }
+
+ // 1. nodes are 2 rows
+ ps := nt.FindAll("p")
+ if len(ps) != 2 || ps[0].IsInline() || ps[1].IsInline() {
+ t.Fail()
+ }
+ // 1a. nodes' children are inline
+ for i := 0; i < 2; i++ {
+ p := ps[i]
+ span := p.Find("span")
+ tt := span.Find("tt")
+ if !span.IsInline() || !tt.IsInline() {
+ t.Fail()
+ }
+ }
+
+ PrintTree(boxed)
+ // 2. Elements are 2 rows
+
+ kids, ok := explodeRow(boxed)
+ if !ok || len(kids) != 1 {
+ t.Errorf("boxed: %+v, kids: %+v", boxed, kids)
+ }
+
+ g := kids[0].UI.(*duitx.Grid)
+ if g.Columns != 1 || len(g.Kids) != 2 {
+ t.Fail()
}
}
--- a/nodes/nodes.go
+++ b/nodes/nodes.go
@@ -10,8 +10,6 @@
"strings"
)
-// Node represents a node at the render stage. It
-// represents a subTree or just a single html node.
type Node struct {
DomSubtree *html.Node `json:"-"`
Text string
@@ -369,4 +367,36 @@
n.Children[0].DomSubtree.Data = t
return
+}
+
+func (n *Node) PrintTree() {
+ n.printTree(0)
+}
+
+func (n *Node) printTree(r int) {
+ for i := 0; i < r; i++ {
+ fmt.Printf(" ")
+ }
+ if n.Type() == html.ElementNode {
+ sty := ""
+ if len(n.Map.Declarations) > 0 {
+ l := make([]string, 0, 2)
+ for k, d := range n.Map.Declarations {
+ s := fmt.Sprintf("%v=%v", k, d.Value)
+ if d.Important {
+ s += "!"
+ }
+ l = append(l, s)
+ }
+ sty += ` style="` + strings.Join(l, " ") + `"`
+ }
+ fmt.Printf("<%v%v>\n", n.Data(), sty)
+ } else if n.Type() == html.TextNode {
+ fmt.Printf("\"%v\"\n", strings.TrimSpace(n.Data()))
+ } else {
+ fmt.Printf("%v\n", n.Data())
+ }
+ for _, c := range n.Children {
+ c.printTree(r+1)
+ }
}
--- a/style/stylesheets.go
+++ b/style/stylesheets.go
@@ -131,6 +131,19 @@
return dd.Important
}
+func compile(v string) (cs cascadia.Selector, err error) {
+ l := strings.Split(v, " ")
+ for _, s := range l {
+ s = strings.TrimSpace(s)
+ if strings.HasSuffix(s, ":") {
+ // TODO: selectors like .selector: would crash otherwise
+ err = fmt.Errorf("unsupported selector: %v", s)
+ return
+ }
+ }
+ return cascadia.Compile(v)
+}
+
func FetchNodeRules(doc *html.Node, cssText string, windowWidth int) (m map[*html.Node][]*css.Rule, err error) {
m = make(map[*html.Node][]*css.Rule)
s, err := parser.Parse(cssText)
@@ -139,7 +152,7 @@
}
processRule := func(m map[*html.Node][]*css.Rule, r *css.Rule) (err error) {
for _, sel := range r.Selectors {
- cs, err := cascadia.Compile(sel.Value)
+ cs, err := compile(sel.Value)
if err != nil {
log.Printf("cssSel compile %v: %v", sel.Value, err)
continue