ludic ui-preview: ludic.ui components previewed for a studio over stdio (R5)
A prebuilt tool, bin/ludic-ui-preview (built by ludic-dev build, shipped beside ludic-lsp, run as `ludic ui-preview [--font DIR]`): ludic.ui with a backend that records every draw call as a line, and mock component classes the studio describes (load / model / calls). frame t runs ui_show at interface time t; text is measured on the CPU with the game's font.json metrics; locale goes through ludic.i18n; tree / box / rules inspect the frame. No game code, no GPU, no network. The wire protocol is frozen as tools/ui-preview/protocol-v1.md; smoke.txt is a transcript to run. ludic.ui gains, all additive: UiClass.make_of, UiBackend.said / emitted, UiRule.text / at (with comment line breaks kept so rule lines count true, and a class's styles read under its .lss path), and ui_root, ui_find, ui_rules_of, ui_rule_value, ui_building, ui_class, ui_class_load, ui_file_forget, ui_errors_clear; ui_nine_cuts_into exported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
28f7b4666b
commit
49b5e80af5
38 changed files with 1986 additions and 16 deletions
92
tools/ui-preview/line.ludic
Normal file
92
tools/ui-preview/line.ludic
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# line.ludic - a request: one line of stdin, cut into words. A word is a JSON value (a string, an
|
||||
# object or a list, read whole) or a run of anything but spaces (a name, a number)
|
||||
# the next line without its end (a \r before it is dropped too), or null at the end of the input
|
||||
@alloc_ok("a request read: the studio's input, never a frame")
|
||||
function pv_read_line(b: PvOut) -> string {
|
||||
b.n = 0
|
||||
var c = read_char()
|
||||
if c < 0 { return null }
|
||||
while c >= 0 and c != 10 {
|
||||
if c != 13 { pv_byte(b, c) }
|
||||
c = read_char()
|
||||
}
|
||||
var s: pointer = null
|
||||
unsafe {
|
||||
s = bytes(b.n + 1)
|
||||
for i in 0 .. b.n { s[i] = b.p[i] }
|
||||
s[b.n] = 0
|
||||
}
|
||||
return s
|
||||
}
|
||||
@alloc_ok("a request's words: one list kept, each word a slice of the line")
|
||||
function pv_words(s: string, out: []string) -> void {
|
||||
List.clear(out)
|
||||
let n = len(s)
|
||||
var i = 0
|
||||
while i < n {
|
||||
while i < n and (s[i] == 32 or s[i] == 9) { i += 1 }
|
||||
if i >= n { break }
|
||||
var j = i
|
||||
let c = s[i]
|
||||
if c == 34 or c == 123 or c == 91 { j = pv_json_end(s, i) } else {
|
||||
while j < n and s[j] != 32 and s[j] != 9 { j += 1 }
|
||||
}
|
||||
push(out, s[i..j])
|
||||
i = j
|
||||
}
|
||||
}
|
||||
# where the JSON value starting at i ends: its closing quote or bracket, strings and escapes skipped
|
||||
function pv_json_end(s: string, i: int) -> int {
|
||||
let n = len(s)
|
||||
var depth = 0
|
||||
var ins = false
|
||||
var j = i
|
||||
while j < n {
|
||||
let c = s[j]
|
||||
if ins {
|
||||
if c == 92 { j += 1 } else if c == 34 {
|
||||
ins = false
|
||||
if depth == 0 { return j + 1 }
|
||||
}
|
||||
} else if c == 34 { ins = true } else if c == 123 or c == 91 { depth += 1 } else if c == 125 or c == 93 {
|
||||
depth -= 1
|
||||
if depth == 0 { return j + 1 }
|
||||
}
|
||||
j += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
# a word as text: a JSON string unquoted, anything else as it stands
|
||||
@alloc_ok("a request's word read")
|
||||
function pv_text(w: string) -> string {
|
||||
if len(w) > 0 and w[0] == 34 { return Value.as_str(Json.parse(w)) }
|
||||
return w
|
||||
}
|
||||
# a word as a number (0 when it is not one)
|
||||
@alloc_ok("a request's word read")
|
||||
function pv_float(w: string) -> float {
|
||||
if len(w) == 0 { return 0.0 }
|
||||
let c = w[0]
|
||||
if not ((c >= 48 and c <= 57) or c == 45 or c == 46) { return 0.0 }
|
||||
return Value.as_float(Json.parse(w))
|
||||
}
|
||||
function pv_int_of(w: string) -> int { return int(pv_float(w)) }
|
||||
# a word as a JSON value (a bare word is a string)
|
||||
@alloc_ok("a request's word read")
|
||||
function pv_val(w: string) -> Val {
|
||||
if len(w) == 0 { return Value.null() }
|
||||
let c = w[0]
|
||||
if c == 34 or c == 123 or c == 91 or (c >= 48 and c <= 57) or c == 45 { return Json.parse(w) }
|
||||
if w == "true" { return Value.bool(1) }
|
||||
if w == "false" { return Value.bool(0) }
|
||||
if w == "null" { return Value.null() }
|
||||
return Value.str(w)
|
||||
}
|
||||
# whether s holds p at `at`, compared where it stands
|
||||
function pv_sat(s: string, at: int, p: string) -> bool {
|
||||
if at + len(p) > len(s) { return false }
|
||||
for i in 0 .. len(p) {
|
||||
if s[at + i] != p[i] { return false }
|
||||
}
|
||||
return true
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue