this repo has no description
at main 256 lines 7.1 kB view raw
1open! Compat 2open Types 3 4type out = Source.t 5 6module State = struct 7 type t = { 8 context : (out * Source.tag) Stack.t; 9 mutable current : out; 10 mutable ignore_all : int; 11 } 12 13 let create () = { context = Stack.create (); current = []; ignore_all = 0 } 14 15 let push state elt = 16 if state.ignore_all = 0 then state.current <- elt :: state.current 17 18 let push_ignore state = state.ignore_all <- state.ignore_all + 1 19 20 let pop_ignore state = 21 state.ignore_all <- 22 (if state.ignore_all > 0 then state.ignore_all - 1 else 0) 23 24 let enter state tag = 25 if state.ignore_all = 0 then ( 26 let previous_elt = state.current in 27 Stack.push (previous_elt, tag) state.context; 28 state.current <- []; 29 ()) 30 31 let leave state = 32 if state.ignore_all = 0 then ( 33 let current_elt = List.rev state.current in 34 let previous_elt, tag = Stack.pop state.context in 35 state.current <- Tag (tag, current_elt) :: previous_elt; 36 ()) 37 38 let rec flush state = 39 if Stack.is_empty state.context then List.rev state.current 40 else ( 41 leave state; 42 flush state) 43end 44 45let rec compute_length_source (t : Types.Source.t) : int = 46 let f (acc : int) = function 47 | Types.Source.Elt t -> acc + compute_length_inline t 48 | Types.Source.Tag (_, t) -> acc + compute_length_source t 49 in 50 List.fold_left f 0 t 51 52and compute_length_inline (t : Types.Inline.t) : int = 53 let f (acc : int) { Types.Inline.desc; _ } = 54 match desc with 55 | Text s -> acc + String.length s 56 | Entity _e -> acc + 1 57 | Linebreak -> 0 (* TODO *) 58 | Styled (_, t) | Link { content = t; _ } -> acc + compute_length_inline t 59 | Source s -> acc + compute_length_source s 60 | Math _ -> assert false 61 | Raw_markup _ -> assert false 62 (* TODO *) 63 in 64 List.fold_left f 0 t 65 66(** Modern implementation using semantic tags, Only for 4.08+ *) 67 68(* 69module Tag = struct 70 71 type Format.stag += 72 | Elt of Inline.t 73 | Tag of Source.tag 74 | Ignore 75 76 let setup_tags formatter state0 = 77 let stag_functions = 78 let mark_open_stag = function 79 | Elt elt -> State.push state0 (Elt elt); "" 80 | Tag tag -> State.enter state0 tag; "" 81 | Format.String_tag "" -> State.enter state0 None; "" 82 | Format.String_tag tag -> State.enter state0 (Some tag); "" 83 | Ignore -> State.push_ignore state0; "" 84 | _ -> "" 85 and mark_close_stag = function 86 | Elt _ -> "" 87 | Tag _ 88 | Format.String_tag _ -> State.leave state0; "" 89 | Ignore -> State.pop_ignore state0; "" 90 | _ -> "" 91 in {Format. 92 print_open_stag = (fun _ -> ()); 93 print_close_stag = (fun _ -> ()); 94 mark_open_stag; mark_close_stag; 95 } 96 in 97 Format.pp_set_tags formatter true; 98 Format.pp_set_formatter_stag_functions formatter stag_functions; 99 () 100 101 let elt ppf elt = 102 Format.pp_open_stag ppf (Elt elt); 103 Format.pp_print_as ppf (compute_length_inline elt) ""; 104 Format.pp_close_stag ppf () 105 106 let ignore ppf txt = 107 Format.pp_open_stag ppf Ignore; 108 Format.fprintf ppf "%t" txt; 109 Format.pp_close_stag ppf () 110end 111*) 112 113(** Ugly terrible implementation of Format Semantic tags for OCaml < 4.08. 114 Please get rid of it as soon as possible. *) 115module Tag = struct 116 let setup_tags formatter state0 = 117 let tag_functions = 118 let get_tag s = 119 let prefix_tag = "tag:" and prefix_ignore = "ignore-tag" in 120 let l = String.length prefix_tag in 121 if String.length s > l && String.sub s 0 l = prefix_tag then 122 let elt : Inline.t = Marshal.from_string s l in 123 `Elt elt 124 else if s = prefix_ignore then `Ignore 125 else `String s 126 in 127 let mark_open_tag s = 128 match get_tag s with 129 | `Ignore -> 130 State.push_ignore state0; 131 "" 132 | `Elt elt -> 133 State.push state0 (Elt elt); 134 "" 135 | `String "" -> 136 State.enter state0 None; 137 "" 138 | `String tag -> 139 State.enter state0 (Some tag); 140 "" 141 and mark_close_tag s = 142 match get_tag s with 143 | `Ignore -> 144 State.pop_ignore state0; 145 "" 146 | `Elt _ -> "" 147 | `String _ -> 148 State.leave state0; 149 "" 150 in 151 { 152 Format.print_open_tag = (fun _ -> ()); 153 print_close_tag = (fun _ -> ()); 154 mark_open_tag; 155 mark_close_tag; 156 } 157 in 158 Format.pp_set_tags formatter true; 159 Format.pp_set_formatter_tag_functions formatter tag_functions; 160 () 161 162 let elt ppf (elt : Inline.t) = 163 Format.fprintf ppf "@{<tag:%s>%t@}" (Marshal.to_string elt []) (fun fmt -> 164 Format.pp_print_as fmt (compute_length_inline elt) "") 165 166 let ignore ppf txt = Format.fprintf ppf "@{<ignore-tag>%t@}" txt 167end 168[@@alert "-deprecated--deprecated"] 169 170type t = Format.formatter -> unit 171 172let make () = 173 let open Inline in 174 let state0 = State.create () in 175 let push elt = State.push state0 (Elt elt) in 176 let push_text s = if state0.ignore_all = 0 then push [ inline @@ Text s ] in 177 178 let formatter = 179 let out_string s i j = push_text (String.sub s i j) in 180 let out_flush () = () in 181 Format.make_formatter out_string out_flush 182 in 183 184 (* out_functions is only available in OCaml>=4.06 *) 185 (* let out_functions = {Format. 186 * out_string = (fun i j s -> push_text @@ String.sub i j s ); 187 * out_flush = (fun () -> ()); 188 * out_newline = (fun () -> push [inline @@ Linebreak]); 189 * out_spaces = (fun n -> push_text (String.make n ' ')); 190 * out_indent = (fun n -> push_text (String.make n ' ')) 191 * } 192 * in 193 * let formatter = Format.formatter_of_out_functions out_functions in *) 194 Tag.setup_tags formatter state0; 195 Format.pp_set_margin formatter 80; 196 ( (fun () -> 197 Format.pp_print_flush formatter (); 198 State.flush state0), 199 formatter ) 200 201let spf fmt = 202 let flush, ppf = make () in 203 Format.kfprintf (fun _ -> flush ()) ppf fmt 204 205let pf = Format.fprintf 206 207let elt t ppf = Tag.elt ppf t 208 209let entity e ppf = elt [ inline @@ Inline.Entity e ] ppf 210 211let ignore t ppf = Tag.ignore ppf t 212 213let ( ++ ) f g ppf = 214 f ppf; 215 g ppf 216 217let span ?(attr = "") f ppf = pf ppf "@{<%s>%t@}" attr f 218 219let txt s ppf = Format.pp_print_string ppf s 220 221let noop (_ : Format.formatter) = () 222 223let break i j ppf = Format.pp_print_break ppf i j 224 225let cut = break 0 0 226 227let sp = break 1 0 228 229let rec list ?sep ~f = function 230 | [] -> noop 231 | [ x ] -> f x 232 | x :: xs -> ( 233 let hd = f x in 234 let tl = list ?sep ~f xs in 235 match sep with None -> hd ++ tl | Some sep -> hd ++ sep ++ tl) 236 237let box_hv t ppf = pf ppf "@[<hv 2>%t@]" t 238 239let box_hv_no_indent t ppf = pf ppf "@[<hv 0>%t@]" t 240 241let render f = spf "@[<hv 2>%t@]" (span f) 242 243let code ?attr f = [ inline ?attr @@ Inline.Source (render f) ] 244 245let documentedSrc f = [ DocumentedSrc.Code (render f) ] 246 247let codeblock ?attr f = 248 [ block ?attr @@ Block.Source (Comment.default_lang_tag, [], [], render f, []) ] 249 250let keyword keyword ppf = pf ppf "@{<keyword>%s@}" keyword 251 252let mode mode ppf = pf ppf "@{<mode>%s@}" mode 253 254module Infix = struct 255 let ( ++ ) = ( ++ ) 256end