shithub: mycel

Download patch

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&nbsp;-ac&nbsp;/dist/plan9front&nbsp;/</tt>
+				</span>
+			</p>
+			<p>
+				<span>
+					<tt>git/pull&nbsp;-u&nbsp;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