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
--
⑨