package cascade
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
CSS generation and manipulation library for OCaml
Install
dune-project
Dependency
Authors
Maintainers
Sources
cascade-1.2.1.tbz
sha256=1cf5079b3797cd6e70fbced8dc2631074f357d36fcdea8597c7ba17ac2903f6e
sha512=43f5e6a3986f8f43ce948b8f1d59f6f00e1047f5707c5449b6323b683d2ecd51a0fb34793aad9c48904a67b0f7268d7379ab9baf29917c25a962064bfa3ab694
doc/src/cascade/source_index.ml.html
Source file source_index.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(** See {!Source_index}. *) type block = { body : string; next : int } (** A [{ ... }] or [( ... )] body, and the offset just past its close. *) type header = { prelude : string; brace : int; block : block } (** An [@name PRELUDE { ... }] header: what stands between the at-keyword and the [{], where that [{] is, and the block it opens. *) type statement = { prelude : string; next : int } (** A blockless at-rule's prelude and the offset after its semicolon. When a closing brace terminates it, [next] points at that brace. *) type t = { call : (int, string * block) Hashtbl.t; (** function-token offset -> the name it calls and its arguments *) at : (int, string * header) Hashtbl.t; (** at-keyword offset -> its at-name and its header *) statement : (int, string * statement) Hashtbl.t; (** at-keyword offset -> its at-name and blockless statement *) } (* Where the contents of a group end. One the source left open ends with the source, which is where the parser ends it too. *) let inner_end ~closed (loc : Loc.t) = if closed then loc.end_pos - 1 else loc.end_pos let group css ~from ~upto ~next = { body = String.sub css from (upto - from); next } let block_of css (b : Component.block Component.node) = let upto = inner_end ~closed:b.node.closed b.loc in group css ~from:(b.loc.start_pos + 1) ~upto ~next:b.loc.end_pos (* A call's arguments start where its first one does; one that takes none has an empty body against its own closer. *) let call_of css (f : Component.func Component.node) = let upto = inner_end ~closed:f.node.terminated f.loc in let from = match f.node.arguments with | argument :: _ -> (Component.source_loc argument).start_pos | [] -> upto in group css ~from ~upto ~next:f.loc.end_pos (* The [{] an at-rule's prelude leads to. A group in the prelude is a single component, so a [;] inside one does not end the at-rule. *) let rec brace_of = function | [] -> None | Component.Block ({ node = { opening = Token.Curly; _ }; _ } as b) :: _ -> Some b | Component.Preserved { kind = Token.Semicolon | Token.Close _; _ } :: _ -> None | _ :: rest -> brace_of rest (* The semicolon or enclosing closer that terminates a blockless at-rule. *) let rec statement_end ~closer = function | [] -> (closer, closer) | Component.Preserved { kind = Token.Semicolon; loc; _ } :: _ -> (loc.start_pos, loc.end_pos) | Component.Preserved { kind = Token.Close Token.Curly; loc; _ } :: _ -> (loc.start_pos, loc.start_pos) | _ :: rest -> statement_end ~closer rest let v css = let t = { call = Hashtbl.create 16; at = Hashtbl.create 16; statement = Hashtbl.create 16; } in let header name (at : Loc.t) rest = match brace_of rest with | None -> () | Some b -> let brace = b.Component.loc.start_pos in let prelude = String.trim (String.sub css at.end_pos (brace - at.end_pos)) in Hashtbl.replace t.at at.start_pos (name, { prelude; brace; block = block_of css b }) in let statement ~closer name (at : Loc.t) rest = let upto, next = statement_end ~closer rest in let prelude = String.sub css at.end_pos (upto - at.end_pos) in Hashtbl.replace t.statement at.start_pos (name, { prelude; next }) in let rec walk ~closer = function | [] -> () | item :: rest -> (match item with | Component.Preserved { kind = Token.At_keyword name; loc; _ } -> ( (* An at-rule is one or the other. [brace_of] stops at the terminator, so finding no brace is exactly "blockless", and registering both would answer [at_statement] for a blockful rule with a prelude running to the end of the source. *) match brace_of rest with | Some _ -> header name loc rest | None -> statement ~closer name loc rest) | Component.Preserved _ -> () | Component.Block b -> walk ~closer:(inner_end ~closed:b.node.closed b.loc) b.node.value | Component.Func f -> Hashtbl.replace t.call f.loc.start_pos (f.node.name, call_of css f); walk ~closer:(inner_end ~closed:f.node.terminated f.loc) f.node.arguments); walk ~closer rest in let parsed = Parser.list_of_component_values (Reader.of_string css) in walk ~closer:(String.length css) parsed.value; t (* [name( ... )] starting at [i]. *) let call t ~name i = match Hashtbl.find_opt t.call i with | Some (n, block) when n = name -> Some block | _ -> None (* [@name PRELUDE { ... }] starting at [i]. An at-rule with no block of its own is not one of these. *) let at_rule t ~name i = match Hashtbl.find_opt t.at i with | Some (n, header) when "@" ^ n = name -> Some header | _ -> None (* A blockless [@name PRELUDE;] starting at [i]. *) let at_statement t ~name i = match Hashtbl.find_opt t.statement i with | Some (n, statement) when "@" ^ n = name -> Some statement | _ -> None (* Every [name( ... )] in the source, with the offset each starts at. *) let calls t ~name = Hashtbl.fold (fun i (n, block) acc -> if n = name then (i, block) :: acc else acc) t.call [] (* Every blockless [@name PRELUDE;], the same way. *) let at_statements t ~name = Hashtbl.fold (fun i (n, s) acc -> if "@" ^ n = name then (i, s) :: acc else acc) t.statement []
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>