package mdx
Executable code blocks inside markdown files
Install
Dune Dependency
Authors
Maintainers
Sources
mdx-2.2.1.tbz
sha256=f09ed733fe4461605f029773748a6353d01b95be65eb986bcce17d6ddaf509d8
sha512=5f918fbafcb55c3959f6cce69b8d8e640883dea5c21d159b5ebb6ead31230569100813555d2637f74028d51f79f23a226dc69811524d9cf1c2ca50b87a93dbf2
doc/src/mdx/toplevel.ml.html
Source file toplevel.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
(* * Copyright (c) 2018 Thomas Gazagnaire <thomas@gazagnaire.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) let src = Logs.Src.create "ocaml-mdx" module Log = (val Logs.src_log src : Logs.LOG) open Astring type t = { (* TODO: move vpad and hpad to `toplevel_tests` *) vpad : int; hpad : int; pos : Lexing.position; command : string list; output : Output.t list; } type toplevel_tests = { tests : t list; end_pad : string option } let dump_line ppf = function | #Output.t as o -> Output.dump ppf o | `Command (c, _) -> Fmt.pf ppf "`Command %a" Fmt.Dump.(list string) c let dump_lines = Fmt.Dump.list dump_line let dump ppf { vpad; hpad; command; output; _ } = Fmt.pf ppf "@[{vpad=%d;@ hpad=%d;@ command=%a;@ output=%a}@]" vpad hpad Fmt.Dump.(list string) command (Fmt.Dump.list Output.dump) output let dump_toplevel_tests ppf { tests; end_pad } = Fmt.pf ppf "@[{tests=%a;@ end_pad=%a}@]" Fmt.Dump.(list dump) tests Fmt.Dump.(option string) end_pad let pp_vpad ppf t = let rec aux = function | 0 -> () | i -> Fmt.pf ppf "\n"; aux (i - 1) in aux t.vpad (* somewhat idiosyncratic version of Fmt.list *) let rec pp_list_string_nonblank ~sep ~blank ppf = function | [] -> () | [ s ] -> Fmt.string ppf s | x :: y :: xs -> Fmt.string ppf x; let current_sep = match Util.String.all_blank y with true -> blank | false -> sep in current_sep ppf (); pp_list_string_nonblank ~sep ~blank ppf (y :: xs) let pp_command ppf (t : t) = match t.command with | [] -> () | l -> pp_vpad ppf t; let sep ppf () = Fmt.pf ppf "\n%a " Pp.pp_pad t.hpad in let blank = Fmt.any "\n" in Fmt.pf ppf "%a# %a" Pp.pp_pad t.hpad (pp_list_string_nonblank ~sep ~blank) l let pp ppf (t : t) = pp_command ppf t; Fmt.string ppf "\n"; Pp.pp_lines (Output.pp ~pad:t.vpad) ppf t.output let lexbuf ~(pos : Lexing.position) s = let lexbuf = Lexing.from_string s in lexbuf.lex_start_p <- pos; lexbuf.lex_curr_p <- pos; lexbuf let vpad_of_lines t = let rec aux i = function | `Output h :: t when Util.String.all_blank h -> aux (i + 1) t | t -> (i, t) in aux 0 t let rec end_pad_of_lines = function | [] -> ([], None) | [ x; end_pad ] when Util.String.all_blank end_pad -> ([ x ], Some end_pad) | x :: xs -> let xs, end_pad = end_pad_of_lines xs in (x :: xs, end_pad) let unpad hpad line = match Util.String.all_blank line with | true -> line | false -> if String.length line < hpad then Fmt.failwith "invalid padding: %S" line else String.with_index_range line ~first:hpad let rec hpad_of_lines = function | [] -> 0 | h :: hs -> ( match Util.String.all_blank h with | true -> hpad_of_lines hs | false -> let i = ref 0 in while !i < String.length h && h.[!i] = ' ' do incr i done; !i) let of_lines ~(loc : Location.t) t = let pos = loc.loc_start in (* Location.t considers the first line to be 1, whereas the tokenizer assumes lines start with 0. *) let pos = { pos with pos_lnum = pos.pos_lnum - 1 } in let hpad = hpad_of_lines t in let t, end_pad = end_pad_of_lines t in let lines = List.map (unpad hpad) t in let lines = String.concat ~sep:"\n" lines in let lxbuf = lexbuf ~pos lines in let lines = Lexer_top.token lxbuf in let vpad, lines = vpad_of_lines lines in Log.debug (fun l -> l "Toplevel.of_lines (vpad=%d, hpad=%d) %a" vpad hpad dump_lines lines); let mk vpad (command, (loc : Location.t)) output = { vpad; hpad; pos = loc.loc_start; command; output = List.rev output } in let rec aux vpad command_loc output acc = function | [] -> List.rev (mk vpad command_loc output :: acc) | (`Ellipsis as o) :: t -> aux vpad command_loc (o :: output) acc t | (`Output _ as o) :: t -> aux vpad command_loc (o :: output) acc t | `Command cmd :: t -> let vpad', output = vpad_of_lines output in aux vpad' cmd [] (mk vpad command_loc output :: acc) t in let tests = match lines with | `Command cmd :: t -> aux vpad cmd [] [] t | _ -> Fmt.failwith "invalid toplevel block: %a" Fmt.(Dump.list string) t in { tests; end_pad }
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>