Hyperscript conformance: 372→373 — hide/show strategy, generator toEqual
Parser: hide/show handle `with opacity/visibility/display` strategy, target detection for then-less chaining (add/remove/set/put as boundary). Generator: inline run().toEqual([...]) pattern for eval-only tests. Compiler: hide/show emit correct CSS property per strategy. 373/831 (45%) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1287,6 +1287,21 @@ let run_spec_tests env test_files =
|
||||
| None -> ()); (* silently skip unresolvable libraries *)
|
||||
Nil
|
||||
end
|
||||
| "text-measure" ->
|
||||
(* Monospace approximation for tests *)
|
||||
let args = let a = Sx_runtime.get_val request (String "args") in
|
||||
(match a with List l -> l | _ -> [a]) in
|
||||
let size = match args with
|
||||
| [_font; Number sz; _text] -> sz | _ -> 16.0 in
|
||||
let text = match args with
|
||||
| [_font; _sz; String t] -> t | _ -> "" in
|
||||
let w = size *. 0.6 *. (float_of_int (String.length text)) in
|
||||
let d = Hashtbl.create 4 in
|
||||
Hashtbl.replace d "width" (Number w);
|
||||
Hashtbl.replace d "height" (Number size);
|
||||
Hashtbl.replace d "ascent" (Number (size *. 0.8));
|
||||
Hashtbl.replace d "descent" (Number (size *. 0.2));
|
||||
Dict d
|
||||
| _ -> Nil (* Other IO ops return nil in test context *)
|
||||
in
|
||||
s := Sx_ref.cek_resume !s response;
|
||||
@@ -1401,6 +1416,7 @@ let run_spec_tests env test_files =
|
||||
load_module "runtime.sx" hs_dir;
|
||||
load_module "integration.sx" hs_dir;
|
||||
load_module "types.sx" lib_dir;
|
||||
load_module "text-layout.sx" lib_dir;
|
||||
load_module "sx-swap.sx" lib_dir;
|
||||
(* Shared templates: TW styling engine *)
|
||||
let templates_dir = Filename.concat project_dir "shared/sx/templates" in
|
||||
|
||||
@@ -360,6 +360,25 @@ and cek_run_with_io state =
|
||||
(Sx_runtime.value_to_str lib_spec));
|
||||
Nil
|
||||
end
|
||||
| "text-measure" ->
|
||||
(* Resolve locally — monospace approximation *)
|
||||
let args = let a = Sx_runtime.get_val request (String "args") in
|
||||
(match a with List l -> l | _ -> [a]) in
|
||||
let size = match args with
|
||||
| [_font; Number sz; _text] -> sz
|
||||
| [_font; Number sz] -> sz
|
||||
| _ -> 16.0 in
|
||||
let text = match args with
|
||||
| [_font; _sz; String t] -> t
|
||||
| _ -> "" in
|
||||
let char_width = size *. 0.6 in
|
||||
let width = char_width *. (float_of_int (String.length text)) in
|
||||
let d = Hashtbl.create 4 in
|
||||
Hashtbl.replace d "width" (Number width);
|
||||
Hashtbl.replace d "height" (Number size);
|
||||
Hashtbl.replace d "ascent" (Number (size *. 0.8));
|
||||
Hashtbl.replace d "descent" (Number (size *. 0.2));
|
||||
Dict d
|
||||
| _ ->
|
||||
let args = let a = Sx_runtime.get_val request (String "args") in
|
||||
(match a with List l -> l | _ -> [a]) in
|
||||
@@ -1014,7 +1033,9 @@ let rec dispatch env cmd =
|
||||
ignore (Sx_types.env_bind env "*current-file*" (String path));
|
||||
let count = ref 0 in
|
||||
List.iter (fun expr ->
|
||||
ignore (eval_expr_io expr (Env env));
|
||||
(try ignore (eval_expr_io expr (Env env))
|
||||
with Eval_error msg ->
|
||||
Printf.eprintf "[load] %s: %s\n%!" (Filename.basename path) msg);
|
||||
incr count
|
||||
) exprs;
|
||||
(* Rebind host extension points after .sx load — evaluator.sx
|
||||
@@ -1994,6 +2015,26 @@ let eval_with_io expr env =
|
||||
ignore lib_name; (* import handled by _import_hook if registered *)
|
||||
Nil
|
||||
with _ -> Nil)
|
||||
| "text-measure" ->
|
||||
(* Pretext: server-side text measurement (monospace approximation).
|
||||
Real otfm font-table parsing can replace this later. *)
|
||||
let size = match args with
|
||||
| List [_font; Number sz; _text] -> sz
|
||||
| List [_font; Number sz] -> sz
|
||||
| _ -> 16.0 in
|
||||
let text = match args with
|
||||
| List [_font; _sz; String t] -> t
|
||||
| _ -> "" in
|
||||
let char_width = size *. 0.6 in
|
||||
let width = char_width *. (float_of_int (String.length text)) in
|
||||
let ascent = size *. 0.8 in
|
||||
let descent = size *. 0.2 in
|
||||
let d = Hashtbl.create 4 in
|
||||
Hashtbl.replace d "width" (Number width);
|
||||
Hashtbl.replace d "height" (Number size);
|
||||
Hashtbl.replace d "ascent" (Number ascent);
|
||||
Hashtbl.replace d "descent" (Number descent);
|
||||
Dict d
|
||||
| _ ->
|
||||
Printf.eprintf "[io] unhandled IO op: %s\n%!" op;
|
||||
Nil
|
||||
|
||||
@@ -103,6 +103,23 @@
|
||||
});
|
||||
} else if (opName === "io-navigate") {
|
||||
// navigation — don't resume
|
||||
} else if (opName === "text-measure") {
|
||||
// Pretext: measure text using offscreen canvas
|
||||
var font = arg;
|
||||
var size = items && items[2];
|
||||
var text = items && items[3];
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.font = (size || 16) + "px " + (font || "serif");
|
||||
var m = ctx.measureText(text || "");
|
||||
try {
|
||||
driveAsync(result.resume({
|
||||
width: m.width,
|
||||
height: m.actualBoundingBoxAscent + m.actualBoundingBoxDescent,
|
||||
ascent: m.actualBoundingBoxAscent,
|
||||
descent: m.actualBoundingBoxDescent
|
||||
}));
|
||||
} catch(e) { console.error("[sx] driveAsync:", e.message); }
|
||||
} else {
|
||||
console.warn("[sx] unhandled IO:", opName);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ let read_string s =
|
||||
| 'r' -> Buffer.add_char buf '\r'
|
||||
| '"' -> Buffer.add_char buf '"'
|
||||
| '\\' -> Buffer.add_char buf '\\'
|
||||
| '/' -> Buffer.add_char buf '/'
|
||||
| 'u' ->
|
||||
(* \uXXXX — read 4 hex digits, encode as UTF-8 *)
|
||||
if s.pos + 4 > s.len then raise (Parse_error "Incomplete \\u escape");
|
||||
|
||||
Reference in New Issue
Block a user