package tiny_languages
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Small languages from scratch: Scheme, Lisp, Smalltalk-80, Pascal, BASIC, JavaScript, HTML, CSS and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_languages.lang_html/Line_mode.ml.html
Source file Line_mode.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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Line_mode.mli *) type t = { lines : string list; links : string list } (*****************************************************************************) (* The printer's state *) (*****************************************************************************) (* the lines so far (the last first), the paragraph being gathered (its * words, the last first, and the word being read), where it goes *) type printer = { width : int; mutable lines : string list; mutable words : string list; word : Buffer.t; mutable indent : int; mutable marker : string; (* before the paragraph's first line: "* ", "2. " *) mutable centred : bool; mutable links : string list; (* the last first *) } (* a UTF-8 string's characters, not its bytes: what a terminal counts *) let length (s : string) : int = let n = ref 0 in String.iter (fun c -> if Char.code c land 0xC0 <> 0x80 then incr n) s; !n let end_word (p : printer) : unit = if Buffer.length p.word > 0 then ( p.words <- Buffer.contents p.word :: p.words; Buffer.clear p.word) let add_line (p : printer) (line : string) : unit = p.lines <- line :: p.lines (* the words gathered, broken into lines, greedily *) let flush (p : printer) : unit = end_word p; if p.words <> [] then ( let first = String.make p.indent ' ' ^ p.marker in let others = String.make (length first) ' ' in let room = max 1 (p.width - length first) in let lines = ref [] and current = ref "" in List.iter (fun w -> if !current = "" then current := w else if length !current + 1 + length w <= room then current := !current ^ " " ^ w else ( lines := !current :: !lines; current := w)) (List.rev p.words); lines := !current :: !lines; List.iteri (fun i line -> if p.centred then add_line p (String.make (max 0 ((p.width - length line) / 2)) ' ' ^ line) else add_line p ((if i = 0 then first else others) ^ line)) (List.rev !lines); p.words <- []; p.marker <- "") (* a blank line, unless at the top or after one already *) let blank (p : printer) : unit = flush p; match p.lines with [] | "" :: _ -> () | _ -> add_line p "" (* text outside <pre>: its spaces end words *) let add_text (p : printer) (s : string) : unit = String.iter (fun c -> if c = ' ' || c = '\n' || c = '\t' then end_word p else Buffer.add_char p.word c) s (* stuck to what is before it: "recipes[1]" *) let glue (p : printer) (s : string) : unit = if Buffer.length p.word > 0 then Buffer.add_string p.word s else match p.words with w :: rest -> p.words <- (w ^ s) :: rest | [] -> Buffer.add_string p.word s (*****************************************************************************) (* The tree *) (*****************************************************************************) let rec element (p : printer) ~(pre : bool) (e : Dom.element) : unit = let children ?(pre = pre) () = List.iter (fun (n : Dom.node) -> match n with Element c -> element p ~pre c | Text s -> if pre then pre_text p s else add_text p s) e.children in let indented by f = p.indent <- p.indent + by; f (); flush p; p.indent <- p.indent - by in match e.name with | "head" | "script" | "style" | "title" -> () | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" -> blank p; p.centred <- true; children (); flush p; p.centred <- false | "p" | "address" -> blank p; children (); flush p | "br" -> flush p | "hr" -> blank p; add_line p (String.make p.width '-') | "pre" -> blank p; children ~pre:true (); flush p | "ul" | "ol" | "dir" | "menu" -> blank p; indented 2 (fun () -> let n = ref 0 in List.iter (fun (c : Dom.node) -> match c with | Element ({ name = "li"; _ } as li) -> incr n; flush p; p.marker <- (if e.name = "ol" then Printf.sprintf "%d. " !n else "* "); element p ~pre li; flush p | Element c -> element p ~pre c | Text s -> add_text p s) e.children) | "dl" -> blank p; children () | "dt" -> flush p; children (); flush p | "dd" -> indented 4 children | "blockquote" -> blank p; indented 4 children | "a" when Dom.attribute "href" e <> None -> children (); p.links <- Option.get (Dom.attribute "href" e) :: p.links; glue p (Printf.sprintf "[%d]" (List.length p.links)) | "img" -> add_text p (match Dom.attribute "alt" e with Some alt -> alt | None -> "[IMAGE]") | _ -> children () (* inside <pre>: its newlines end lines, its spaces are kept *) and pre_text (p : printer) (s : string) : unit = let parts = String.split_on_char '\n' s in List.iteri (fun i part -> if i > 0 then ( end_word p; add_line p (String.make p.indent ' ' ^ String.concat " " (List.rev p.words)); p.words <- []); Buffer.add_string p.word part) parts let render ?(width = 80) (root : Dom.element) : t = let p = { width; lines = []; words = []; word = Buffer.create 32; indent = 0; marker = ""; centred = false; links = [] } in element p ~pre:false root; flush p; (* no blank lines at the end *) let rec trim lines = match lines with "" :: rest -> trim rest | _ -> lines in { lines = List.rev (trim p.lines); links = List.rev p.links }
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>