File: layout.ml

package info (click to toggle)
coinst 1.9.3-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,904 kB
  • sloc: ml: 15,760; javascript: 10,468; makefile: 143; ansic: 52
file content (405 lines) | stat: -rw-r--r-- 12,510 bytes parent folder | download | duplicates (3)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

class type printer = object
  method start_doc : unit -> unit
  method end_doc : unit -> unit
  method text : string -> unit
  method start_code : unit -> unit
  method end_code : unit -> unit
  method change_p : unit -> unit
  method start_ul : string -> unit
  method li : unit -> unit
  method end_ul : unit -> unit
  method start_a : string -> unit
  method end_a : unit -> unit
  method start_dl : ?clss:string -> unit -> unit
  method dt : ?clss:string -> string option -> unit
  method dd : unit -> unit
  method end_dl : unit -> unit
  method start_div : ?clss:string -> unit -> unit
  method end_div : unit -> unit
  method start_span : ?clss:string -> unit -> unit
  method end_span : unit -> unit
  method start_pre : ?clss:string -> unit -> unit
  method end_pre : unit -> unit
  method start_heading : unit -> unit
  method end_heading : unit -> unit
  method start_section : ?clss:string -> unit -> unit
  method end_section : unit -> unit
  method start_footer : unit -> unit
  method end_footer : unit -> unit
  method raw_html : (unit -> string) -> unit
end

type +'a t = printer -> unit

let (&) f1 f2 p = f1 p; f2 p
let emp p = ()

(****)

type +'a flow
type +'a phras
type 'a phrasing = 'a phras flow

let s s p = p#text s
let i i p = p#text (string_of_int i)

let rec seq sep f l p =
  match l with
    []     -> ()
  | [v]    -> f v p
  | v :: r -> f v p; s sep p; seq sep f r p
let rec seq2 sep sep' f l p =
  match l with
    []      -> ()
  | [v]     -> f v p
  | [v; v'] -> f v p; s sep' p; f v' p
  | v :: r  -> f v p; s sep p; seq2 sep sep' f r p

let buf = Buffer.create 16
let formatter = Format.formatter_of_buffer buf
let format f v p =
  Buffer.clear buf; f formatter v; Format.pp_print_flush formatter ();
  p#text (Buffer.contents buf)

let code contents p = p#start_code (); contents p; p#end_code ()

type in_anchor
type outside_anchor

let anchor link contents p = p#start_a link; contents p; p#end_a ()

let p pr = pr#change_p ()

let div ?clss contents p = p#start_div ?clss (); contents p; p#end_div ()

let span ?clss contents p = p#start_span ?clss (); contents p; p#end_span ()

let pre ?clss contents p = p#start_pre ?clss (); contents p; p#end_pre ()

let heading contents p = p#start_heading (); contents p; p#end_heading ()

let section ?clss contents p =
  p#start_section ?clss (); contents p; p#end_section ()

let footer contents p = p#start_footer (); contents p; p#end_footer ()

let raw_html f pr = pr#raw_html f

(****)

type +'a lst
let rec list f l p = List.iter (fun v -> f v p) l

type u
let ul ?(prefix="* ") lst p = p#start_ul prefix; lst p; p#end_ul ()
let li contents p = p#li (); contents p

type d
let dl ?clss lst p = p#start_dl ?clss (); lst p; p#end_dl ()
let dli ?id key desc (p : #printer) = p#dt id; key p; p#dd (); desc p
let dt ?clss key p = p#dt ?clss None; key p
let dd desc p = p#dd (); desc p

(****)

let print p doc = p#start_doc (); doc p; p#end_doc ()

let html_escape s =
  let s = Bytes.of_string s in
  let l = Bytes.length s in
  let n = ref 0 in
  for i = 0 to l - 1 do
    match Bytes.unsafe_get s i with
      '<' | '>' -> n := !n + 3
    | '&'       -> n := !n + 4
    | '\''      -> n := !n + 5
    | _         -> ()
  done;
  if !n = 0 then Bytes.to_string s else
  let s' = Bytes.create (l + !n) in
  n := 0;
  for i = 0 to l - 1 do
    match Bytes.unsafe_get s i with
      '<' ->
        Bytes.unsafe_set s' !n '&'; incr n;
        Bytes.unsafe_set s' !n 'l'; incr n;
        Bytes.unsafe_set s' !n 't'; incr n;
        Bytes.unsafe_set s' !n ';'; incr n
    | '>' ->
        Bytes.unsafe_set s' !n '&'; incr n;
        Bytes.unsafe_set s' !n 'g'; incr n;
        Bytes.unsafe_set s' !n 't'; incr n;
        Bytes.unsafe_set s' !n ';'; incr n
    | '&' ->
        Bytes.unsafe_set s' !n '&'; incr n;
        Bytes.unsafe_set s' !n 'a'; incr n;
        Bytes.unsafe_set s' !n 'm'; incr n;
        Bytes.unsafe_set s' !n 'p'; incr n;
        Bytes.unsafe_set s' !n ';'; incr n
    | '\'' ->
        Bytes.unsafe_set s' !n '&'; incr n;
        Bytes.unsafe_set s' !n 'a'; incr n;
        Bytes.unsafe_set s' !n 'p'; incr n;
        Bytes.unsafe_set s' !n 'o'; incr n;
        Bytes.unsafe_set s' !n 's'; incr n;
        Bytes.unsafe_set s' !n ';'; incr n
    | c ->
        Bytes.unsafe_set s' !n c; incr n
  done;
  Bytes.to_string s'

class html_printer ch ?stylesheet ?(style="") ?(scripts=[]) title : printer =
object (self)
  val mutable in_p = false
  val mutable need_break = false
  val mutable at_list_start = None
  method private break () = if need_break then output_char ch '\n'
  method start_doc () =
    output_string ch
      "<!DOCTYPE html>\n<meta charset='utf-8'>\n<title>";
    output_string ch (html_escape title);
    output_string ch "</title>\n";
    begin match stylesheet with
      Some url ->
        output_string ch "<link rel='stylesheet' href='";
        output_string ch (html_escape url);
        output_string ch "'>\n";
    | None ->
        ()
    end;
    if style <> "" then begin
      output_string ch "<style type='text/css'>\n";
      output_string ch (html_escape style);
      output_string ch "</style>\n"
    end;
    List.iter
      (fun url ->
         output_string ch "<script src='";
         output_string ch (html_escape url);
         output_string ch "'></script>\n")
      scripts
  method end_doc () = ()
  method text s =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    output_string ch (html_escape s); need_break <- true
  method change_p () = in_p <- false
  method start_ul _ = at_list_start <- Some ""
  method li () =
    begin match at_list_start with
      Some clss ->
        self#break (); output_string ch "<ul";
        if clss <> "" then
          output_string ch (" class='" ^ html_escape clss ^ "'");
        output_string ch ">";
        at_list_start <- None
    | None ->
        ()
    end;
    self#break (); output_string ch "<li>"; in_p <- false
  method end_ul () =
    if at_list_start = None then begin
      self#break (); output_string ch "</ul>";
      self#break (); need_break <- false;
      in_p <- false
    end;
    at_list_start <- None
  method start_a l =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    output_string ch ("<a href='" ^ html_escape l ^ "'>")
  method end_a () = output_string ch "</a>"
  method start_code () =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    output_string ch ("<code>")
  method end_code () = output_string ch "</code>"
  method start_dl ?(clss = "") () = at_list_start <- Some clss
  method dt ?clss id =
    begin match at_list_start with
      Some clss ->
        self#break (); output_string ch "<dl";
        if clss <> "" then
          output_string ch (" class='" ^ html_escape clss ^ "'");
        output_string ch ">";
        self#break (); need_break <- false;
        at_list_start <- None
    | None ->
        ()
    end;
    self#break (); output_string ch "<dt";
    begin match clss with
      None      -> ()
    | Some clss -> output_string ch (" class='" ^ clss ^ "'")
    end;
    begin match id with
      None    -> ()
    | Some id -> output_string ch (" id='" ^ id ^ "'")
    end;
    output_string ch ">";
    in_p <- true
  method dd () =
    begin match at_list_start with
      Some clss ->
        self#break (); output_string ch "<dl";
        if clss <> "" then
          output_string ch (" class='" ^ html_escape clss ^ "'");
        output_string ch ">";
        self#break (); need_break <- false;
        at_list_start <- None
    | None ->
        ()
    end;
    self#break (); output_string ch "<dd>"; in_p <- false
  method end_dl () =
    if at_list_start = None then begin
      self#break (); output_string ch "</dl>";
      self#break (); need_break <- false;
      in_p <- false
    end;
    at_list_start <- None
  method start_div ?clss () =
    self#break ();
    begin match clss with
      Some clss -> output_string ch ("<div class='" ^ html_escape clss ^ "'>")
    | None      -> output_string ch "<div>"
    end;
    need_break <- true; in_p <- false
  method end_div () =
    self#break (); output_string ch "</div>"; need_break <- true; in_p <- false
  method start_span ?clss () =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    begin match clss with
      Some clss -> output_string ch ("<span class='" ^ html_escape clss ^ "'>")
    | None      -> output_string ch "<span>"
    end
  method end_span () = output_string ch "</span>";
  method start_pre ?clss () =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    begin match clss with
      Some clss -> output_string ch ("<pre class='" ^ html_escape clss ^ "'>")
    | None      -> output_string ch "<pre>"
    end
  method end_pre () = output_string ch "</pre>";
  method start_heading () =
    self#break ();
    output_string ch "<h1>";
    need_break <- true; in_p <- true
  method end_heading () =
    self#break (); output_string ch "</h1>"; need_break <- true; in_p <- false
  method start_section ?clss  () =
    self#break ();
    begin match clss with
      Some clss ->
        output_string ch ("<section class='" ^ html_escape clss ^ "'>")
    | None ->
        output_string ch "<section>"
    end;
    need_break <- true; in_p <- false
  method end_section () =
    self#break (); output_string ch "</section>";
    need_break <- true; in_p <- false
  method start_footer () =
    self#break ();
    output_string ch "<footer>";
    need_break <- true; in_p <- false
  method end_footer () =
    self#break (); output_string ch "</footer>";
    need_break <- true; in_p <- false
  method raw_html f =
    if not in_p then begin
      self#break (); output_string ch "<p>"; in_p <- true
    end;
    output_string ch (f ());
    need_break <- true
end

let space = Str.regexp " "

(*XXX recognize non-breaking spaces and replace them with spaces (?) *)
(*Unicode bullets? • *)

class format_printer f : printer = object
  val mutable at_flow_start = true
  val mutable in_p = false
  val mutable at_list_start = false
  val mutable ul_prefixes = []
  method start_doc () =
    Format.fprintf f "@[<v>";
    at_flow_start <- true; in_p <- false; ul_prefixes <- []
  method end_doc () =
    if in_p then Format.fprintf f "@]";
    Format.fprintf f "@]@."
  method text s =
    if not in_p then begin
      if not at_flow_start then Format.fprintf f "@ ";
      Format.fprintf f "@[";
    end;
    at_flow_start <- false; in_p <- true;
    List.iter
      (fun e ->
         match e with
           Str.Delim _ -> Format.fprintf f "@ "
         | Str.Text s  -> Format.fprintf f "%s" s)
      (Str.full_split space s)
  method change_p () =
    if in_p then Format.fprintf f "@]";
    in_p <- false
  method start_ul prefix =
    ul_prefixes <- prefix :: ul_prefixes;
    if in_p then Format.fprintf f "@]";
    at_list_start <- true; in_p <- false
  method li () =
    if at_list_start then begin
      if not at_flow_start then Format.fprintf f "@ ";
      Format.fprintf f "@[<v>";
    end else begin
      if in_p then Format.fprintf f "@]";
      Format.fprintf f "@]@ "
    end;
    Format.fprintf f "@[<v2>%s" (List.hd ul_prefixes);
    in_p <- false; at_list_start <- false; at_flow_start <- true
  method end_ul () =
    ul_prefixes <- List.tl ul_prefixes;
    if not at_list_start then begin
      if in_p then Format.fprintf f "@]";
      Format.fprintf f "@]@]";
      at_flow_start <- false
    end;
    at_list_start <- false; in_p <- false
  method start_a l = ()
  method end_a l = ()
  method start_code l = ()
  method end_code l = ()
  method start_dl ?clss () = at_list_start <- true; assert false
  method dt ?clss id =
    if at_list_start then begin
      Format.fprintf f "@[<v>"; at_list_start <- false
    end else
      Format.fprintf f "@]@]@ ";
    Format.fprintf f "@[<v2>* @["
  method dd () = Format.fprintf f "@]@ @["
  method end_dl () =
    if not at_list_start then Format.fprintf f "@]"
  method start_div ?clss () = ()
  method end_div () = ()
  method start_span ?clss () = ()
  method end_span () = ()
  method start_pre ?clss () = ()
  method end_pre () = ()
  method start_heading () = ()
  method end_heading () = ()
  method start_section ?clss () = ()
  method end_section () = ()
  method start_footer () = ()
  method end_footer () = ()
  method raw_html f = ()
end