this repo has no description
at main 238 lines 6.8 kB view raw
1(** Raw latex primitives: 2 - macro definitions 3 - env defitions 4 - text escaping *) 5 6type pr = Format.formatter -> unit 7 8type 'a with_options = ?options:pr list -> 'a 9 10type ('a, 'b) tr = 'a Fmt.t -> 'b Fmt.t 11 12type 'a t = ('a, 'a) tr 13 14module Escape = struct 15 let text ~code_hyphenation = 16 let b = Buffer.create 17 in 17 fun s -> 18 for i = 0 to String.length s - 1 do 19 match s.[i] with 20 | '{' -> Buffer.add_string b "\\{" 21 | '}' -> Buffer.add_string b "\\}" 22 | '\\' -> Buffer.add_string b "\\textbackslash{}" 23 | '%' -> Buffer.add_string b "\\%" 24 | '~' -> Buffer.add_string b "\\textasciitilde{}" 25 | '^' -> Buffer.add_string b "\\textasciicircum{}" 26 | '_' -> 27 if code_hyphenation then Buffer.add_string b {|\_\allowbreak{}|} 28 else Buffer.add_string b {|\_|} 29 | '.' when code_hyphenation -> Buffer.add_string b {|.\allowbreak{}|} 30 | ';' when code_hyphenation -> Buffer.add_string b {|;\allowbreak{}|} 31 | ',' when code_hyphenation -> Buffer.add_string b {|,\allowbreak{}|} 32 | '&' -> Buffer.add_string b "\\&" 33 | '#' -> Buffer.add_string b "\\#" 34 | '$' -> Buffer.add_string b "\\$" 35 | c -> Buffer.add_char b c 36 done; 37 let s = Buffer.contents b in 38 Buffer.reset b; 39 s 40 41 let pp ~code_hyphenation ppf x = 42 Format.pp_print_string ppf (text ~code_hyphenation x) 43 44 let ref ppf s = 45 for i = 0 to String.length s - 1 do 46 match s.[i] with 47 | '~' -> Fmt.pf ppf "+t+" 48 | '&' -> Fmt.pf ppf "+a+" 49 | '^' -> Fmt.pf ppf "+c+" 50 | '%' -> Fmt.pf ppf "+p+" 51 | '{' -> Fmt.pf ppf "+ob+" 52 | '}' -> Fmt.pf ppf "+cb+" 53 | '+' -> Fmt.pf ppf "+++" 54 | c -> Fmt.pf ppf "%c" c 55 done 56end 57 58let option ppf pp = Fmt.pf ppf "[%t]" pp 59 60let create name ?(options = []) pp ppf content = 61 Fmt.pf ppf {|\%s%a{%a}|} name (Fmt.list option) options pp content 62 63let math name ppf = Fmt.pf ppf {|$\%s$|} name 64 65let create2 name ?(options = []) pp_x pp_y ppf x y = 66 Fmt.pf ppf {|\%s%a{%a}{%a}|} name (Fmt.list option) options pp_x x pp_y y 67 68let bind pp x ppf = pp ppf x 69 70let label ppf = create "label" Escape.ref ppf 71 72let mbegin ?options = create "begin" ?options Fmt.string 73 74let mend = create "end" Fmt.string 75 76let code_fragment pp = create "ocamlcodefragment" pp 77 78let break ppf level = 79 let pre : _ format6 = 80 match level with 81 | Types.Aesthetic -> "%%" 82 | Line -> {|\\|} 83 | Separation -> {|\medbreak|} 84 | _ -> "" 85 in 86 let post : _ format6 = 87 match level with 88 | Types.Line | Separation | Aesthetic | Simple -> "" 89 | Paragraph -> "@," 90 in 91 Fmt.pf ppf (pre ^^ "@," ^^ post) 92 93let env name pp ?(with_break = false) ?(opts = []) ?(args = []) ppf content = 94 mbegin ppf name; 95 List.iter (Fmt.pf ppf "[%t]") opts; 96 List.iter (Fmt.pf ppf "{%t}") args; 97 pp ppf content; 98 mend ppf name; 99 break ppf (if with_break then Simple else Aesthetic) 100 101let indent pp ppf x = env "ocamlindent" pp ppf x 102 103let inline_code pp = create "ocamlinlinecode" pp 104 105let verbatim ppf x = env "verbatim" Fmt.string ppf x 106 107let pageref_star x = create "pageref*" Escape.ref x 108 109let hyperref s = create "hyperref" ~options:[ bind Escape.ref s ] 110 111let ref x = create "ref" Escape.ref x 112 113let emph pp = create "emph" pp 114 115let bold pp = create "bold" pp 116 117let subscript pp = create "textsubscript" pp 118 119let superscript pp = create "textsuperscript" pp 120 121let code_block pp ppf x = 122 let name = "ocamlcodeblock" in 123 mbegin ppf name; 124 Fmt.cut ppf (); 125 pp ppf x; 126 Fmt.cut ppf (); 127 mend ppf name 128 129let includegraphics pp = create "includegraphics" pp 130 131let section pp = create "section" pp 132 133let subsection pp = create "subsection" pp 134 135let subsubsection pp = create "subsubsection" pp 136 137let paragraph pp = create "paragraph" pp 138 139let enumerate pp ppf x = env "enumerate" pp ppf x 140 141let itemize pp ppf x = env "itemize" pp ppf x 142 143let raw_description pp ppf x = env "description" pp ppf x 144 145let href x pp ppf y = 146 create2 "href" (Escape.pp ~code_hyphenation:false) pp ppf x y 147 148let item ?options = create "item" ?options 149 150let description pp ppf x = 151 (* printing description inside a group make them more robust *) 152 let group_printer d ppf = Fmt.pf ppf "{%a}" pp d in 153 let elt ppf (d, elt) = item ~options:[ group_printer d ] pp ppf elt in 154 let all ppf x = 155 Fmt.pf ppf 156 {|\kern-\topsep 157\makeatletter\advance\%@topsepadd-\topsep\makeatother%% topsep is hardcoded 158|}; 159 Fmt.list ~sep:(fun ppf () -> break ppf Aesthetic) elt ppf x 160 in 161 match x with 162 | [] -> () (* empty description are not supported *) 163 | _ :: _ -> raw_description all ppf x 164 165let url ppf s = 166 create "url" Fmt.string ppf (Escape.text ~code_hyphenation:false s) 167 168let footnote x = create "footnote" url x 169 170let rightarrow ppf = math "rightarrow" ppf 171 172(** Latex uses forward slash even on Windows. *) 173let latex_path ppf path = 174 let path_s = String.concat "/" (Fpath.segs path) in 175 Fmt.string ppf path_s 176 177let input ppf x = create "input" latex_path ppf x 178 179let ocamltabular ~column_desc pp ppf x = 180 env "ocamltabular" ~args:[ column_desc ] pp ppf x 181 182let small_table pp ppf (alignment, tbl) = 183 let columns = match tbl with [] -> 1 | _ -> List.length (List.hd tbl) in 184 let row ppf x = 185 let ampersand ppf () = Fmt.pf ppf "& " in 186 Fmt.list ~sep:ampersand pp ppf x; 187 break ppf Line 188 in 189 let matrix ppf m = List.iter (row ppf) m in 190 let column_desc = 191 let pp_alignment ppf align = 192 match align with 193 | Odoc_document.Types.Table.Default -> Fmt.pf ppf "p" 194 | Left -> Fmt.pf ppf "w{l}" 195 | Right -> Fmt.pf ppf "w{r}" 196 | Center -> Fmt.pf ppf "w{c}" 197 in 198 let cell ppf align = 199 Fmt.pf ppf "%a{%.3f\\textwidth}" pp_alignment align 200 (1.0 /. float_of_int columns) 201 in 202 match alignment with 203 | None -> 204 let rec repeat n s ppf = 205 if n = 0 then () else Fmt.pf ppf "%t%t" s (repeat (n - 1) s) 206 in 207 repeat columns (fun ppf -> cell ppf Default) 208 | Some alignment -> fun ppf -> List.iter (cell ppf) alignment 209 in 210 let table ppf tbl = ocamltabular ~column_desc matrix ppf tbl in 211 (* we add line breaks to never insert tables between delimiters, 212 to avoid rendering: 213 | `A 214 [ | `B ] 215 | `C 216 or 217 field_1: int; 218 { field_2: int; } 219 field_3: int; 220 *) 221 break ppf Line; 222 table ppf tbl; 223 break ppf Line 224 225let ocamltag tag pp ppf x = create2 "ocamltag" Fmt.string pp ppf tag x 226 227let math ppf x = Fmt.pf ppf {|$%s$|} x 228 229let equation ppf x = 230 let name = "equation*" in 231 mbegin ppf name; 232 Fmt.cut ppf (); 233 (* A blank line before \end{equation*} is a latex error, 234 we trim on the right the user input to avoid any surprise *) 235 let x = Astring.String.drop ~rev:true ~sat:Astring.Char.Ascii.is_white x in 236 Fmt.string ppf x; 237 Fmt.cut ppf (); 238 mend ppf name