this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/cuetxtar: improve eq value formatter

- Add eqCompactThreshold: structs wider than
the threshold are formatted multi-line with
nested indentation; below it they stay
single-line.
- Fix list-kind guard in eqWriteValue: avoid
treating lists as structs even when the
vertex has arcs (e.g. closed lists).

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ia27d726fe05904ef911245ad98ff084aba0bb78d
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1235383
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+49 -13
+49 -13
internal/cuetxtar/inline_format.go
··· 89 89 return strings.Join(parts, " ") 90 90 } 91 91 92 + // eqCompactThreshold is the maximum byte length of a compact struct expression 93 + // before eqWriteValue switches to multi-line (one field per line) form. 94 + const eqCompactThreshold = 40 95 + 92 96 // formatValue returns a human-readable CUE string for a value. 93 - // Routes through the Vertex export path (via cue.Final()) to avoid internal 94 - // _#def wrapping, then re-enables optional fields (value?: T) so the 95 - // formatted expression round-trips through astCmp. 97 + // Short values are returned compact (single line). Struct values whose compact 98 + // form exceeds eqCompactThreshold are returned in multi-line form with 99 + // recursive indentation; eqFillAttrStr handles re-indentation relative to the 100 + // source attribute line. 96 101 func (r *inlineRunner) formatValue(v cue.Value) string { 97 102 var b strings.Builder 98 - eqWriteValue(value.OpContext(v), &b, v) 103 + eqWriteValue(value.OpContext(v), &b, v, "\t") 99 104 return b.String() 100 105 } 101 106 102 107 // eqWriteValue writes a CUE value to b in @test(eq, ...) body notation. 103 108 // 109 + // nestedIndent controls multi-line formatting for struct values: when non-empty, 110 + // a struct whose compact form exceeds eqCompactThreshold is written in 111 + // multi-line form — each field prefixed by "\n"+nestedIndent, the closing "}" 112 + // by "\n"+nestedIndent[:-1]. Nested struct values receive nestedIndent+"\t" so 113 + // every level of nesting gains one extra tab. When nestedIndent is empty the 114 + // value is always written compact (used internally for disjuncts, conjuncts, 115 + // and nested field values that already fit in the threshold). 116 + // 104 117 // Compared with v.Syntax() + cue.Final() + format.Node: 105 118 // - Hidden fields use _foo$pkg notation (matching astcmp.go conventions). 106 119 // - adt.Disjunction values are emitted as *d1 | d2 (with * for defaults) 107 120 // instead of being collapsed to the default by cue.Final(). 108 121 // - adt.Conjunction values are emitted as c1 & c2. 109 - func eqWriteValue(opCtx *adt.OpContext, b *strings.Builder, v cue.Value) { 122 + func eqWriteValue(opCtx *adt.OpContext, b *strings.Builder, v cue.Value, nestedIndent string) { 110 123 tv := v.Core() 111 124 vx := tv.V.DerefValue() 112 125 ··· 123 136 // latter handles error vertices that still carry child fields (e.g. a 124 137 // struct with one bad field: the parent vertex is _|_ but its arcs hold 125 138 // the successfully-evaluated sibling fields). 126 - if v.IncompleteKind() == cue.StructKind || len(vx.Arcs) > 0 { 127 - eqWriteStruct(opCtx, b, vx) 139 + // Lists also have arcs (integer-indexed elements) but must fall through 140 + // to the standard syntax formatter so they render as [v1, v2] not {0: v1}. 141 + k := v.IncompleteKind() 142 + if (k == cue.StructKind || len(vx.Arcs) > 0) && k != cue.ListKind { 143 + if nestedIndent != "" { 144 + // Multi-line mode: use compact if it fits, else recurse one level deeper. 145 + var compact strings.Builder 146 + eqWriteStruct(opCtx, &compact, vx, "") 147 + if compact.Len() <= eqCompactThreshold { 148 + b.WriteString(compact.String()) 149 + return 150 + } 151 + } 152 + eqWriteStruct(opCtx, b, vx, nestedIndent) 128 153 return 129 154 } 130 155 ··· 149 174 if i < dj.NumDefaults { 150 175 b.WriteByte('*') 151 176 } 152 - eqWriteValue(opCtx, b, value.Make(opCtx, v)) 177 + eqWriteValue(opCtx, b, value.Make(opCtx, v), "") 153 178 } 154 179 } 155 180 ··· 159 184 if i > 0 { 160 185 b.WriteString(" & ") 161 186 } 162 - eqWriteValue(opCtx, b, value.Make(opCtx, v)) 187 + eqWriteValue(opCtx, b, value.Make(opCtx, v), "") 163 188 } 164 189 } 165 190 166 - // eqWriteStruct emits a struct, using _foo$pkg notation for hidden-field labels. 167 - func eqWriteStruct(opCtx *adt.OpContext, b *strings.Builder, vx *adt.Vertex) { 191 + // eqWriteStruct emits a struct using _foo$pkg notation for hidden-field labels. 192 + // 193 + // nestedIndent controls layout: 194 + // - "" (compact): fields are separated by ", ". 195 + // - non-empty: each field is preceded by "\n"+nestedIndent; the closing "}" 196 + // is preceded by "\n"+nestedIndent[:-1] (one tab less). Field values 197 + // receive nestedIndent+"\t" so they can recurse one level deeper. 198 + func eqWriteStruct(opCtx *adt.OpContext, b *strings.Builder, vx *adt.Vertex, nestedIndent string) { 168 199 b.WriteByte('{') 169 200 first := true 170 201 for _, arc := range vx.Arcs { ··· 180 211 continue 181 212 } 182 213 } 183 - if !first { 214 + if nestedIndent != "" { 215 + b.WriteString("\n" + nestedIndent) 216 + } else if !first { 184 217 b.WriteString(", ") 185 218 } 186 219 first = false 187 220 eqWriteLabel(opCtx, b, arc.Label, arc.ArcType) 188 221 b.WriteString(": ") 189 - eqWriteValue(opCtx, b, value.Make(opCtx, arc)) 222 + eqWriteValue(opCtx, b, value.Make(opCtx, arc), nestedIndent+"\t") 223 + } 224 + if nestedIndent != "" && !first { 225 + b.WriteString("\n" + nestedIndent[:len(nestedIndent)-1]) 190 226 } 191 227 b.WriteByte('}') 192 228 }