Hold every whole draw's row a walk is in, so a nested whole draw keeps the outer one's

This commit is contained in:
2026-09-25 08:31:25 +02:00
committed by Lillem4n
parent b0889faa14
commit 3500f8e1c3
4 changed files with 21 additions and 25 deletions
+3 -3
View File
@@ -412,9 +412,9 @@ another never meet, and each may select its own row of another table; the cells
row, and whatever they reach, do meet, and so does the format beside them. The rule the
fence applies is that two reads meet unless they sit in rows that never render together:
rows falling under different rows of a table a path pinned, two rows of that table
itself included. A table read whole draws its row apart from every pin, so its rows
are alternatives only to each other, and a cell of one meets a read pinning a region
the row is not in. A choice's items get no such treatment yet: two items selecting
itself included. A table read whole draws its row apart from every pin, so the rows of
one whole read are alternatives only to each other, and a cell of one meets a read
pinning an ancestor row the row is not under. A choice's items get no such treatment yet: two items selecting
different rows are still refused.
## A table never reaches its own family, by any route
+6 -10
View File
@@ -179,14 +179,14 @@ type drawWalk struct {
}
// drawAt is where a walk stands: the draw group it draws in, how the render's root reached it, the
// table rows it pinned, the table a whole read draws a row of, and the row of it whose cells the
// walk is in.
// table rows it pinned, the table a whole read draws a row of, and the rows of whole draws whose
// cells the walk is in.
type drawAt struct {
group string
route drawRoute
alt pinSet
drawn *table // left out of the visit keys: only this table's own cells compare against it, which the own-family fence keeps true
whole tablePin
whole pinSet
}
// drawRoute is how a render reaches a draw: as its author spells it, and the root edge's label.
@@ -239,7 +239,8 @@ func (w *drawWalk) walk(n node, at drawAt) {
w.edge(n, e, at)
case cell.cellOf == at.drawn:
in := at
in.whole = tablePin{cell.cellOf, cell.cellRow}
in.whole = at.whole.clone()
in.whole.add(cell.cellOf, cell.cellRow)
w.edge(n, e, in)
case at.alt.clash(cell.cellOf, cell.cellRow) == nil:
in := at
@@ -250,12 +251,7 @@ func (w *drawWalk) walk(n node, at drawAt) {
}
// rowsKey spells the rows the walk stands in, pinned and whole, for a map.
func (at drawAt) rowsKey() string {
if at.whole.t == nil {
return at.alt.key()
}
return fmt.Sprintf("%s%p{%d}", at.alt.key(), at.whole.t, at.whole.row)
}
func (at drawAt) rowsKey() string { return at.alt.key() + "|" + at.whole.key() }
// 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.
+1 -12
View File
@@ -219,15 +219,4 @@ func checkOwnFamily(t *template) error {
// alternatives reports whether two reads sit in different rows of one table: rows the walks pinned,
// or rows of one whole draw.
// docs/decisions.md#the-rows-of-a-table-are-alternatives
func alternatives(a, b drawAt) bool {
if a.whole.t != nil && a.whole.t == b.whole.t && a.whole.row != b.whole.row {
return true
}
found := false
a.alt.each(func(t *table, r int) {
if br, in := b.alt.pinned(t); in && br != r {
found = true
}
})
return found
}
func alternatives(a, b drawAt) bool { return a.alt.differs(&b.alt) || a.whole.differs(&b.whole) }
+11
View File
@@ -153,6 +153,17 @@ func (p pinSet) entered(t *table, r int) pinSet {
return p
}
// differs reports whether p and q hold different rows of one table.
func (p *pinSet) differs(q *pinSet) bool {
found := false
p.each(func(t *table, r int) {
if qr, in := q.pinned(t); in && qr != r {
found = true
}
})
return found
}
// key spells the set for a map, by the tables' identities in path order.
func (p *pinSet) key() string {
var pins []tablePin