Gather the family fence in family.go
This commit is contained in:
-131
@@ -6,33 +6,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// drawGroupOf reads a template's "drawGroup" (default ""), which a repeat cannot carry: each
|
||||
// iteration renders in no draw group.
|
||||
func drawGroupOf(m map[string]any, repeat int) (string, error) {
|
||||
v, ok := m["drawGroup"]
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
name, ok := v.(string)
|
||||
switch {
|
||||
case !ok:
|
||||
return "", fmt.Errorf("drawGroup must be a string, got %T", v)
|
||||
case name == "":
|
||||
return "", fmt.Errorf(`drawGroup "" is the default, so it has no effect; drop it`)
|
||||
case repeat > 1:
|
||||
return "", fmt.Errorf("drawGroup %q on a repeat names nothing, since each iteration is a render of its own; drop it", name)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// keyDrawGroup keys t's draw group by the category t sits in, "" for an inline template, so a name
|
||||
// is local to its category.
|
||||
func (t *template) keyDrawGroup(category string) {
|
||||
if t.drawGroup != "" {
|
||||
t.drawGroupKey = category + "/" + t.drawGroup
|
||||
}
|
||||
}
|
||||
|
||||
// checkNestedDrawGroup refuses a template beneath one drawing in group that names group again,
|
||||
// short of a repeat or another draw group.
|
||||
func checkNestedDrawGroup(fields map[string]node, group string) error {
|
||||
@@ -104,43 +77,6 @@ func (c *drawCheck) checkDraws(path string, n node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkOwnFamily refuses a table's format or cell that reads, however many templates
|
||||
// away and through a repeat or a draw group too, a table of its own family: a row
|
||||
// rendered whole draws its row without pinning it, so the family would draw apart
|
||||
// from the row being rendered, whichever draws the reaching template holds.
|
||||
func checkOwnFamily(t *template) error {
|
||||
own := t.table
|
||||
if own == nil {
|
||||
own = t.cellOf
|
||||
}
|
||||
if own == nil {
|
||||
return nil
|
||||
}
|
||||
seen := map[node]bool{}
|
||||
var find func(n node) (renderEdge, *table, bool)
|
||||
find = func(n node) (renderEdge, *table, bool) {
|
||||
if seen[n] {
|
||||
return renderEdge{}, nil, false
|
||||
}
|
||||
seen[n] = true
|
||||
for _, e := range renderEdges(n) {
|
||||
if a, isRef := refRead(n, e.label); isRef {
|
||||
if head, isTable := n.(*template).fields[a.key].(*table); isTable && head.family() == own.family() {
|
||||
return e, head, true
|
||||
}
|
||||
}
|
||||
if e, head, found := find(e.to); found {
|
||||
return e, head, true
|
||||
}
|
||||
}
|
||||
return renderEdge{}, nil, false
|
||||
}
|
||||
if e, head, found := find(t); found {
|
||||
return fmt.Errorf("%s reads %s, a table of its own family, which a row of %s rendered whole would draw apart from; read the family from a template beside it, or add the value as a column", e.reached(), head.category, own.category)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkRecordDraws fences the columns of a record — a template compiled at the top without a
|
||||
// repeat — so a load proves the record view of it as well as the string view.
|
||||
func (c *drawCheck) checkRecordDraws(path string, n node) error {
|
||||
@@ -248,59 +184,6 @@ type drawAt struct {
|
||||
drawn *table // left out of the visit keys: only this table's own cells compare against it, which the own-family fence keeps true
|
||||
}
|
||||
|
||||
// rowSet stands in at load for the rows (*hold).pin holds at render: a path read enters a row with
|
||||
// its ancestors, a whole read enters the drawn row alone.
|
||||
type rowSet []tablePin
|
||||
|
||||
func (s rowSet) rowOf(t *table) (int, bool) {
|
||||
for _, p := range s {
|
||||
if p.t == t {
|
||||
return p.row, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// enter is s with row r of t, and with t's ancestors where the render pins that row rather than
|
||||
// drawing it; the set is copied, since walks branch.
|
||||
func (s rowSet) enter(t *table, r int, pins bool) rowSet {
|
||||
if _, in := s.rowOf(t); in {
|
||||
return s
|
||||
}
|
||||
out := append(make(rowSet, 0, len(s)+1), s...)
|
||||
for {
|
||||
out = append(out, tablePin{t, r})
|
||||
if !pins || t.parentT == nil {
|
||||
break
|
||||
}
|
||||
t, r = t.parentT, t.parentRow(r)
|
||||
if _, in := out.rowOf(t); in {
|
||||
break
|
||||
}
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].t.path < out[j].t.path })
|
||||
return out
|
||||
}
|
||||
|
||||
// key spells the set for a map, by the tables' identities.
|
||||
func (s rowSet) key() string {
|
||||
var b strings.Builder
|
||||
for _, p := range s {
|
||||
fmt.Fprintf(&b, "%p[%d]", p.t, p.row)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// alternatives reports whether two reads sit in different rows of one table.
|
||||
func alternatives(a, b drawAt) bool {
|
||||
for _, p := range a.alt {
|
||||
if r, in := b.alt.rowOf(p.t); in && r != p.row {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// drawRoute is how a render reaches a draw: as its author spells it, and the root edge's label.
|
||||
type drawRoute struct{ spelling, label string }
|
||||
|
||||
@@ -358,20 +241,6 @@ 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) {
|
||||
|
||||
Reference in New Issue
Block a user