change api for Html.nary'; better newlines in output

This commit is contained in:
Simon Cruanes 2022-03-18 21:32:11 -04:00
parent 030d71ad72
commit 4aba0654b0
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
6 changed files with 102 additions and 177 deletions

View file

@ -104,63 +104,64 @@ let html_list_dir (module VFS:VFS) ~prefix ~parent d : Html.elt =
Array.sort String.compare entries; Array.sort String.compare entries;
let open Html in let open Html in
html'[] @@ fun out ->
(* TODO: breadcrumbs for the path, each element a link to the given ancestor dir *) (* TODO: breadcrumbs for the path, each element a link to the given ancestor dir *)
out @< head[][ let head =
head[][
title[][txtf "list directory %S" VFS.descr]; title[][txtf "list directory %S" VFS.descr];
meta[A.charset "utf-8"]; meta[A.charset "utf-8"];
]; ] in
out @< body'[] @@ fun out ->
out @< h2[][txtf "Index of %S" d];
begin match parent with
| None -> ()
| Some p ->
out @< a[A.href (encode_path ("/" // prefix // p))][txt"(parent directory)"];
end;
out @< ul'[] @@ fun out ->
let n_hidden = ref 0 in let n_hidden = ref 0 in
Array.iter (fun f -> if is_hidden f then incr n_hidden) entries; Array.iter (fun f -> if is_hidden f then incr n_hidden) entries;
let emit_file f out : unit = let file_to_elt f : elt option =
if not @@ contains_dot_dot (d // f) then ( if not @@ contains_dot_dot (d // f) then (
let fpath = d // f in let fpath = d // f in
if not @@ VFS.contains fpath then ( if not @@ VFS.contains fpath then (
out @< li[][txtf "%s [invalid file]" f]; Some (li[][txtf "%s [invalid file]" f])
) else ( ) else (
let size = let size =
match VFS.file_size fpath with match VFS.file_size fpath with
| Some f -> Printf.sprintf " (%s)" @@ human_size f | Some f -> Printf.sprintf " (%s)" @@ human_size f
| None -> "" | None -> ""
in in
out @< li'[] @@ fun out -> Some (li'[] [
out @< a[A.href ("/" // prefix // fpath)][txt f]; sub_e @@ a[A.href ("/" // prefix // fpath)][txt f];
if VFS.is_directory fpath then out @< txt"[dir]"; (if VFS.is_directory fpath then sub_e @@ txt "[dir]" else sub_empty);
out @< txt size; sub_e @@ txt size;
); ])
) )
) else None
in in
if !n_hidden>0 then ( let body = body'[] [
out @< details'[] @@ fun out -> sub_e @@ h2[][txtf "Index of %S" d];
out @< summary[][txtf "(%d hidden files)" !n_hidden]; begin match parent with
| None -> sub_empty
| Some p ->
sub_e @@
a[A.href (encode_path ("/" // prefix // p))][txt"(parent directory)"]
end;
Array.iter sub_e @@ ul' [] [
(fun f -> if !n_hidden>0 then
if is_hidden f then ( sub_e @@ details'[][
emit_file f out; sub_e @@ summary[][txtf "(%d hidden files)" !n_hidden];
)) sub_seq (
entries; seq_of_array entries
|> Seq.filter_map
(fun f -> if is_hidden f then file_to_elt f else None)
); );
] else sub_empty;
Array.iter sub_seq (
(fun f -> seq_of_array entries
if not @@ is_hidden f then emit_file f out) |> Seq.filter_map (fun f ->
entries; if not (is_hidden f) then file_to_elt f else None)
() )
];
]
in
html [][head; body]
let finally_ ~h x f = let finally_ ~h x f =
try try

View file

@ -303,8 +303,8 @@ end = struct
let clear self = Buffer.clear self.buf; self.fmt_nl <- true let clear self = Buffer.clear self.buf; self.fmt_nl <- true
let[@inline] add_char self c = Buffer.add_char self.buf c let[@inline] add_char self c = Buffer.add_char self.buf c
let[@inline] add_string self s = Buffer.add_string self.buf s let[@inline] add_string self s = Buffer.add_string self.buf s
let to_string self = Buffer.contents self.buf
let add_format_nl self = if self.fmt_nl then add_char self '\n' let add_format_nl self = if self.fmt_nl then add_char self '\n'
let to_string self = add_format_nl self; Buffer.contents self.buf
let with_no_format_nl self f = let with_no_format_nl self f =
if self.fmt_nl then ( if self.fmt_nl then (
self.fmt_nl <- false; self.fmt_nl <- false;
@ -326,11 +326,13 @@ type nary = ?if_:bool -> attribute list -> elt list -> elt
(** Element with children, represented as a list. (** Element with children, represented as a list.
@param if_ if false, do not print anything (default true) *) @param if_ if false, do not print anything (default true) *)
type nary' = ?if_:bool -> attribute list -> (Out.t -> unit) -> elt (** A chunk of sub-elements, possibly empty.
(** Element with children, represented as a continuation. @inline *)
@param if_ if false, do not print anything (default true) *) type sub_elt = [ `E of elt | `L of elt list | `S of elt Seq.t | `Nil]
let (@<) (out:Out.t) (elt:elt) : unit = elt out type nary' = ?if_:bool -> attribute list -> sub_elt list -> elt
(** Element with children, represented as a list of {!sub_elt} to be flattened
@param if_ if false, do not print anything (default true) *)
(** Escape string so it can be safely embedded in HTML text. *) (** Escape string so it can be safely embedded in HTML text. *)
let _str_escape (out:Out.t) (s:string) : unit = let _str_escape (out:Out.t) (s:string) : unit =
@ -359,6 +361,20 @@ let _write_attrs (out:Out.t ) (l:attribute list) : unit =
_attr_escape out v) _attr_escape out v)
l l
(** Write sub-elements of a {!nary'} element, returns [true] iff
at least one sub-element was written. *)
let _write_subs (out:Out.t) (l:sub_elt list) : bool =
let has_sub = ref false in
let prepend_white () = has_sub := true; Out.add_format_nl out; in
let emit1 = function
| `E x -> prepend_white(); x out
| `L l -> List.iter (fun e -> prepend_white(); e out) l
| `S l -> Seq.iter (fun e -> prepend_white(); e out) l
| `Nil -> ()
in
List.iter emit1 l;
!has_sub
(** Write a tag, with its attributes. (** Write a tag, with its attributes.
@param void if true, end with "/>", otherwise end with ">" *) @param void if true, end with "/>", otherwise end with ">" *)
let _write_tag_attrs ~void (out:Out.t) (tag:string) (attrs:attribute list) : unit = let _write_tag_attrs ~void (out:Out.t) (tag:string) (attrs:attribute list) : unit =
@ -367,6 +383,20 @@ let _write_tag_attrs ~void (out:Out.t) (tag:string) (attrs:attribute list) : uni
_write_attrs out attrs; _write_attrs out attrs;
if void then Out.add_string out "/>" else Out.add_string out ">" if void then Out.add_string out "/>" else Out.add_string out ">"
let[@inline] sub_e (elt:elt) : sub_elt = `E elt
let[@inline] sub_l (l:elt list) : sub_elt = `L l
let[@inline] sub_seq (l:elt Seq.t) : sub_elt = `S l
let seq_of_array (a:_ array) : _ Seq.t =
let rec loop i () =
if i=Array.length a then Seq.Nil
else Seq.Cons (a.(i), loop (i+1))
in loop 0
let sub_empty : sub_elt = `Nil
(** Emit a string value, which will be escaped. *) (** Emit a string value, which will be escaped. *)
let txt (txt:string) : elt = fun out -> _str_escape out txt let txt (txt:string) : elt = fun out -> _str_escape out txt
@ -411,24 +441,22 @@ let emit_normal name =
(* for <pre>, newlines actually matter *) (* for <pre>, newlines actually matter *)
if name="pre" then pf " Out.with_no_format_nl out @@ fun () ->\n"; if name="pre" then pf " Out.with_no_format_nl out @@ fun () ->\n";
pf " _write_tag_attrs ~void:false out %S attrs;\n" name; pf " _write_tag_attrs ~void:false out %S attrs;\n" name;
pf " Out.add_format_nl out;\n"; pf " List.iter (fun sub -> Out.add_format_nl out; sub out) sub;\n";
pf " List.iter (fun sub -> sub out; Out.add_format_nl out) sub;\n"; pf " if sub <> [] then Out.add_format_nl out;\n";
pf " Out.add_string out \"</%s>\";" name; pf " Out.add_string out \"</%s>\")" name;
pf " Out.add_format_nl out)\n";
pf "\n\n"; pf "\n\n";
(* block version *) (* block version *)
let oname = oname ^ "'" in let oname = oname ^ "'" in
pf "(** tag %S, see {{:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/%s} mdn} *)\n" pf "(** tag %S, see {{:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/%s} mdn} *)\n"
name name; name name;
pf "let %s : nary' = fun ?(if_=true) attrs f out ->\n" oname; pf "let %s : nary' = fun ?(if_=true) attrs l out ->\n" oname;
pf " if if_ then (\n"; pf " if if_ then (\n";
if name="pre" then pf " Out.with_no_format_nl out @@ fun () ->\n"; if name="pre" then pf " Out.with_no_format_nl out @@ fun () ->\n";
pf " _write_tag_attrs ~void:false out %S attrs;\n" name; pf " _write_tag_attrs ~void:false out %S attrs;\n" name;
pf " Out.add_format_nl out;\n"; pf " let has_sub = _write_subs out l in\n";
pf " f out;\n"; pf " if has_sub then Out.add_format_nl out;\n";
pf " Out.add_string out \"</%s>\";" name; pf " Out.add_string out \"</%s>\")" name;
pf " Out.add_format_nl out)\n";
pf "\n\n"; pf "\n\n";

View file

@ -13,7 +13,6 @@ echo:
<title> <title>
list directory &quot;Embedded_fs&quot; list directory &quot;Embedded_fs&quot;
</title> </title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
</head> </head>
<body> <body>
@ -25,27 +24,33 @@ Index of &quot;&quot;
<a href="/vfs/a.txt"> <a href="/vfs/a.txt">
a.txt a.txt
</a> </a>
(12b)</li> (12b)
</li>
<li> <li>
<a href="/vfs/example_dot_com"> <a href="/vfs/example_dot_com">
example_dot_com example_dot_com
</a> </a>
(1.12k)</li> (1.12k)
</li>
<li> <li>
<a href="/vfs/foo.html"> <a href="/vfs/foo.html">
foo.html foo.html
</a> </a>
(214b)</li> (214b)
</li>
<li> <li>
<a href="/vfs/sub"> <a href="/vfs/sub">
sub sub
</a> </a>
[dir]</li> [dir]
</li>
<li> <li>
<a href="/vfs/test_out.txt"> <a href="/vfs/test_out.txt">
test_out.txt test_out.txt
</a> </a>
(209b)</li> (209b)
</li>
</ul> </ul>
</body> </body>
</html> </html>

View file

@ -18,11 +18,10 @@ let t2() =
head [] []; head [] [];
pre [] [txt "a"; txt "b"]; pre [] [txt "a"; txt "b"];
body [] [ body [] [
ul' [A.style "list-style: circle"] (fun out -> ul' [A.style "list-style: circle"] [
for i=0 to 99 do sub_l @@ List.init 100 @@ fun i ->
li ~if_:(i<> 42) [A.id (spf "l%d" i)] [txt (spf "item %d" i)] out li ~if_:(i<> 42) [A.id (spf "l%d" i)] [txt (spf "item %d" i)]
done ]
)
] ]
] ]

View file

@ -1,417 +1,312 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head></head>
</head>
<body> <body>
<ul style="list-style: circle"> <ul style="list-style: circle">
<li> <li>
<pre>a<pre>cd</pre>b</pre> <pre>a<pre>cd</pre>b</pre>
</li> </li>
<li id="l0"> <li id="l0">
item 0 item 0
</li> </li>
<li id="l1"> <li id="l1">
item 1 item 1
</li> </li>
<li id="l2"> <li id="l2">
item 2 item 2
</li> </li>
<li id="l3"> <li id="l3">
item 3 item 3
</li> </li>
<li id="l4"> <li id="l4">
item 4 item 4
</li> </li>
<li id="l5"> <li id="l5">
item 5 item 5
</li> </li>
<li id="l6"> <li id="l6">
item 6 item 6
</li> </li>
<li id="l7"> <li id="l7">
item 7 item 7
</li> </li>
<li id="l8"> <li id="l8">
item 8 item 8
</li> </li>
<li id="l9"> <li id="l9">
item 9 item 9
</li> </li>
<li id="l10"> <li id="l10">
item 10 item 10
</li> </li>
<li id="l11"> <li id="l11">
item 11 item 11
</li> </li>
<li id="l12"> <li id="l12">
item 12 item 12
</li> </li>
<li id="l13"> <li id="l13">
item 13 item 13
</li> </li>
<li id="l14"> <li id="l14">
item 14 item 14
</li> </li>
<li id="l15"> <li id="l15">
item 15 item 15
</li> </li>
<li id="l16"> <li id="l16">
item 16 item 16
</li> </li>
<li id="l17"> <li id="l17">
item 17 item 17
</li> </li>
<li id="l18"> <li id="l18">
item 18 item 18
</li> </li>
<li id="l19"> <li id="l19">
item 19 item 19
</li> </li>
<li id="l20"> <li id="l20">
item 20 item 20
</li> </li>
<li id="l21"> <li id="l21">
item 21 item 21
</li> </li>
<li id="l22"> <li id="l22">
item 22 item 22
</li> </li>
<li id="l23"> <li id="l23">
item 23 item 23
</li> </li>
<li id="l24"> <li id="l24">
item 24 item 24
</li> </li>
<li id="l25"> <li id="l25">
item 25 item 25
</li> </li>
<li id="l26"> <li id="l26">
item 26 item 26
</li> </li>
<li id="l27"> <li id="l27">
item 27 item 27
</li> </li>
<li id="l28"> <li id="l28">
item 28 item 28
</li> </li>
<li id="l29"> <li id="l29">
item 29 item 29
</li> </li>
<li id="l30"> <li id="l30">
item 30 item 30
</li> </li>
<li id="l31"> <li id="l31">
item 31 item 31
</li> </li>
<li id="l32"> <li id="l32">
item 32 item 32
</li> </li>
<li id="l33"> <li id="l33">
item 33 item 33
</li> </li>
<li id="l34"> <li id="l34">
item 34 item 34
</li> </li>
<li id="l35"> <li id="l35">
item 35 item 35
</li> </li>
<li id="l36"> <li id="l36">
item 36 item 36
</li> </li>
<li id="l37"> <li id="l37">
item 37 item 37
</li> </li>
<li id="l38"> <li id="l38">
item 38 item 38
</li> </li>
<li id="l39"> <li id="l39">
item 39 item 39
</li> </li>
<li id="l40"> <li id="l40">
item 40 item 40
</li> </li>
<li id="l41"> <li id="l41">
item 41 item 41
</li> </li>
<li id="l42"> <li id="l42">
item 42 item 42
</li> </li>
<li id="l43"> <li id="l43">
item 43 item 43
</li> </li>
<li id="l44"> <li id="l44">
item 44 item 44
</li> </li>
<li id="l45"> <li id="l45">
item 45 item 45
</li> </li>
<li id="l46"> <li id="l46">
item 46 item 46
</li> </li>
<li id="l47"> <li id="l47">
item 47 item 47
</li> </li>
<li id="l48"> <li id="l48">
item 48 item 48
</li> </li>
<li id="l49"> <li id="l49">
item 49 item 49
</li> </li>
<li id="l50"> <li id="l50">
item 50 item 50
</li> </li>
<li id="l51"> <li id="l51">
item 51 item 51
</li> </li>
<li id="l52"> <li id="l52">
item 52 item 52
</li> </li>
<li id="l53"> <li id="l53">
item 53 item 53
</li> </li>
<li id="l54"> <li id="l54">
item 54 item 54
</li> </li>
<li id="l55"> <li id="l55">
item 55 item 55
</li> </li>
<li id="l56"> <li id="l56">
item 56 item 56
</li> </li>
<li id="l57"> <li id="l57">
item 57 item 57
</li> </li>
<li id="l58"> <li id="l58">
item 58 item 58
</li> </li>
<li id="l59"> <li id="l59">
item 59 item 59
</li> </li>
<li id="l60"> <li id="l60">
item 60 item 60
</li> </li>
<li id="l61"> <li id="l61">
item 61 item 61
</li> </li>
<li id="l62"> <li id="l62">
item 62 item 62
</li> </li>
<li id="l63"> <li id="l63">
item 63 item 63
</li> </li>
<li id="l64"> <li id="l64">
item 64 item 64
</li> </li>
<li id="l65"> <li id="l65">
item 65 item 65
</li> </li>
<li id="l66"> <li id="l66">
item 66 item 66
</li> </li>
<li id="l67"> <li id="l67">
item 67 item 67
</li> </li>
<li id="l68"> <li id="l68">
item 68 item 68
</li> </li>
<li id="l69"> <li id="l69">
item 69 item 69
</li> </li>
<li id="l70"> <li id="l70">
item 70 item 70
</li> </li>
<li id="l71"> <li id="l71">
item 71 item 71
</li> </li>
<li id="l72"> <li id="l72">
item 72 item 72
</li> </li>
<li id="l73"> <li id="l73">
item 73 item 73
</li> </li>
<li id="l74"> <li id="l74">
item 74 item 74
</li> </li>
<li id="l75"> <li id="l75">
item 75 item 75
</li> </li>
<li id="l76"> <li id="l76">
item 76 item 76
</li> </li>
<li id="l77"> <li id="l77">
item 77 item 77
</li> </li>
<li id="l78"> <li id="l78">
item 78 item 78
</li> </li>
<li id="l79"> <li id="l79">
item 79 item 79
</li> </li>
<li id="l80"> <li id="l80">
item 80 item 80
</li> </li>
<li id="l81"> <li id="l81">
item 81 item 81
</li> </li>
<li id="l82"> <li id="l82">
item 82 item 82
</li> </li>
<li id="l83"> <li id="l83">
item 83 item 83
</li> </li>
<li id="l84"> <li id="l84">
item 84 item 84
</li> </li>
<li id="l85"> <li id="l85">
item 85 item 85
</li> </li>
<li id="l86"> <li id="l86">
item 86 item 86
</li> </li>
<li id="l87"> <li id="l87">
item 87 item 87
</li> </li>
<li id="l88"> <li id="l88">
item 88 item 88
</li> </li>
<li id="l89"> <li id="l89">
item 89 item 89
</li> </li>
<li id="l90"> <li id="l90">
item 90 item 90
</li> </li>
<li id="l91"> <li id="l91">
item 91 item 91
</li> </li>
<li id="l92"> <li id="l92">
item 92 item 92
</li> </li>
<li id="l93"> <li id="l93">
item 93 item 93
</li> </li>
<li id="l94"> <li id="l94">
item 94 item 94
</li> </li>
<li id="l95"> <li id="l95">
item 95 item 95
</li> </li>
<li id="l96"> <li id="l96">
item 96 item 96
</li> </li>
<li id="l97"> <li id="l97">
item 97 item 97
</li> </li>
<li id="l98"> <li id="l98">
item 98 item 98
</li> </li>
<li id="l99"> <li id="l99">
item 99 item 99
</li> </li>
</ul> </ul>
</body> </body>
</html> </html>

View file

@ -1,8 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head></head>
</head>
<pre>ab</pre> <pre>ab</pre>
<body> <body>
<ul style="list-style: circle"> <ul style="list-style: circle">
@ -132,6 +130,7 @@ item 40
<li id="l41"> <li id="l41">
item 41 item 41
</li> </li>
<li id="l43"> <li id="l43">
item 43 item 43
</li> </li>
@ -304,8 +303,6 @@ item 98
item 99 item 99
</li> </li>
</ul> </ul>
</body> </body>
</html> </html>