From c314f9cb575d5cf4714656e2a5d5b8b06323afec Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 17 Sep 2026 16:13:59 +0200 Subject: [PATCH] Enter every row a read pins before walking on, and skip a cell outside an entered ancestor's row --- README.md | 7 ++++--- draw.go | 32 ++++++++++++++++++++------------ table.go | 10 ++++++++++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index f021e85..16f3129 100644 --- a/README.md +++ b/README.md @@ -965,9 +965,10 @@ renamed or retyped line is a major. - **The rows of a table are alternatives.** Only one row renders, so a cell in one row and a cell in another never meet, and each may select its own row of another table; the cells of one row, and whatever they reach, do meet, and so does the - format beside them. The family fence replays the reads of each row apart, - together with the reads outside any row. A choice's items get no such treatment - yet: two items selecting different rows are still refused. + format beside them. The rule the fence applies is that two reads meet unless + they sit in two rows of one table, or in a row outside a selected ancestor's. A + choice's items get no such treatment yet: two items selecting different rows + are still refused. - **A path is walked once without drawing before it is walked for real.** A path that fails below its first level then moves no seeded stream, at the cost of one draw-free walk per call, which allocates nothing. diff --git a/draw.go b/draw.go index c148360..0b45d39 100644 --- a/draw.go +++ b/draw.go @@ -363,8 +363,7 @@ func (w *drawWalk) walk(n node, at drawAt) { } for _, e := range renderEdges(n) { if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil { - // A row already entered renders only its own cell of this column. - if r, in := at.alt.rowOf(cell.cellOf); in && r != cell.cellRow { + if at.alt.excludes(cell) { continue } w.edge(n, e, drawAt{at.group, at.route, at.alt.enter(cell.cellOf, cell.cellRow)}) @@ -374,22 +373,31 @@ func (w *drawWalk) walk(n node, at drawAt) { } } +// excludes reports whether a cell's row cannot render with the rows entered: another +// row of its table, or a row outside an entered ancestor's. +func (s rowSet) excludes(cell *template) bool { + for _, p := range s { + if p.t == cell.cellOf { + return p.row != cell.cellRow + } + if cell.cellOf.descends(p.t) && !cell.cellOf.under(cell.cellRow, p.t, p.row) { + return true + } + } + return false +} + +// edge records the reference an edge reads, then walks on with every row the read +// pins entered, so a selected row renders only its own cells. func (w *drawWalk) edge(from node, e renderEdge, at drawAt) { - var tr *tableRead if a, reads := refRead(from, e.label); reads { - tr = tableReadOf(from.(*template).fields[a.key], a, e.to) + tr := tableReadOf(from.(*template).fields[a.key], a, e.to) if k := (drawKey{at.group, a.path, at.alt.key()}); !w.read[k] { w.read[k] = true w.reads = append(w.reads, pathRead{at, a, tr}) } - } - // A read that pins the column's table renders that row's cell alone. - if c, isColumn := e.to.(*column); isColumn && tr != nil { - if r, pinned := tr.pins.pinned(c.t); pinned { - if cell := c.t.cellNode(r, c.i); cell != nil { - w.walk(cell, drawAt{at.group, at.route, at.alt.enter(c.t, r)}) - } - return + if tr != nil { + tr.pins.each(func(t *table, r int) { at.alt = at.alt.enter(t, r) }) } } w.walk(e.to, at) diff --git a/table.go b/table.go index d101c21..3f94851 100644 --- a/table.go +++ b/table.go @@ -465,6 +465,16 @@ func (t *table) descendant(name string) *table { // parentRow is the row of t's parent that row r links to. func (t *table) parentRow(r int) int { return t.parentT.byKey[t.cell(r, t.parent)] } +// descends reports whether a is an ancestor of t. +func (t *table) descends(a *table) bool { + for p := t.parentT; p != nil; p = p.parentT { + if p == a { + return true + } + } + return false +} + // under reports whether row r of t sits inside row pr of ancestor a. func (t *table) under(r int, a *table, pr int) bool { for c, row := t, r; c.parentT != nil; c, row = c.parentT, c.parentRow(row) {