site.cd 15.9 KB
Newer Older
1
2
(* This CDuce script produces CDuce web site. *)

3
4
(** Command line **)

5
let input =
6
  match argv [] with
7
  | [ s ] -> s
8
  | _ -> raise "Please use --arg to specify an input file on the command line"
9

10
(** Output types **)
11

12
using H = "xhtml"
13

14
15
(** Input types **)

16
type Site = <site>[ <title>String Page ]
17
type Page =  <page name=Latin1 url=?String new=?"">[ <title>String <banner>[InlineText*]? Item* ]
18
type External = <external {|href=String; title=String; name=String |}>[]
19
20

type Item = 
21
   <box ({| title=String; link=String; short=?String |} | {| |})>Content
22
23
 | <meta>Content
 | <left>Content
24
 | <footnotes>[]
25
 | Page
26
 | External
27

28
type Author = <author presenter=?("yes"|"no")>String
29
type Paper = 
30
  <paper file=?String old=?"">[ 
31
     <title>String Author+ <comment>[InlineText*] <abstract>Content ]
32
33

type Slides = 
34
  <slides file=String>[ <title>String Author+ <comment>[InlineText*] ]
35
36

type Link =
37
  <link url=String title=String>[ InlineText* ]
38
39

type Content =      
40
   [ ( <p {|style=?String|}>[InlineText*]
41
     | <ul {||}>[<li {||}>Content *]
42
     | <ol {|style=?String|}>[<li {||}>Content *]
43
     | <section title=String>Content
44
     | <sample highlight=?"true"|"false">String
45
     | <xmlsample highlight=?"true"|"false">String
46
     | <sessionsample highlight=?"true"|"false">String
47
     | H:Xtable
48
     | Paper | Slides | Link
49
50
     | <boxes-toc short=?"" sections=?"">[]
     | <pages-toc sections=?"">[]
51
52
     | <site-toc>[]
     | <local-links href=String>[]
53
     | <two-columns>[ <left>Content <right>Content ]
54
     | <note title=?String> Content
55
     | <footnotes>[]
56
     | InlineText
57
     )* ]
58
59
60

type InlineText =
     Char
61
   | <(`b|`i|`tt|`em) {| style=?String |}>[InlineText*]
62
   | <code>String
63
   | <local href=String>String
64
   | <footnote>[InlineText*]
65
66
67
68
69
70
   | H:Xa | H:Ximg | H:Xbr
   | <thumbnail href=String width=?IntStr height=?IntStr>[]
   | <thumbnails href=String width=?IntStr height=?IntStr>[ PCDATA ]

type IntStr = ['0'--'9'+]

71

72
73
74
75
(** Generic purpose functions **)

(* Recursive inclusion of XML files and verbatim text files *)

76
let load_include (Latin1 -> [Any*])
77
 name ->
78
(*   let _ = print [ 'Loading ' !name '... \n' ] in *)
79
   xtransform [ (load_xml name) ] with 
80
81
   | <include file=(s & Latin1)>[] -> load_include s
   | <include-verbatim file=(s & Latin1)>[] -> load_file s 
82

83
(* Highlighting text between {{...}} *)
84

85
86
87
let highlight (String -> [ (Char | H:Xstrong | H:Xi)* ] )
 | [ '{{%%' h ::(Char *?) '%%}}' ; rest ] -> 
          [ <strong class="highlight">[<i>h]; highlight rest ]
88
 | [ '{{' h ::(Char *?) '}}' ; rest ] -> 
89
          [ <strong class="highlight">h; highlight rest ]
90
91
92
93
 | [ '$$%%' h ::(Char *?) '%%$$' ; rest ] -> 
          [ <strong class="ocaml">[<i>h]; highlight rest ]
 | [ '$$' h ::(Char *?) '$$' ; rest ] -> 
          [ <strong class="ocaml">h; highlight rest ]
94
 | [ '%%' h ::(Char *?) '%%' ; rest ] ->
95
          [ <i>h; highlight rest ] 
96
 | [ c; rest ] -> [ c; highlight rest ]
97
 | [] -> []
98

99
100
(* Split a comma-separated string *)

101
let split_comma (String -> [String*])
102
 | [ x::(Char*?) ',' ; rest ] -> (x, split_comma rest)
103
 | s -> [ s ]
104

105
106
107
108
109
110
111
112
type wschar = ' ' | '\n' | '\t' | '\r'

let split_thumbnails (String -> [(String,String)*])
 | [ wschar* x::(Char\wschar\':')+ ':' y::_*? '.'; rest ] -> 
        ((x,y), split_thumbnails rest)
 | [ wschar* x::(Char\wschar)+; rest ] -> 
        ((x,""), split_thumbnails rest)
 | [ wschar* ] -> []
113

114
(** Internal types **)
115

116
type Path = [ { url = String; title = String }* ]
117
type Tree = { name = String; url = String; title = String; 
118
              children = [Tree*]; boxes = [H:Xul?] } 
119

120
121
122
let url_of_page (Page -> String)
 | <page url=u>_ -> u
 | <page name=n>_ -> n @ ".html"
123

124
125
126
127
128
129
130
let render(a : String)(p : {presenter=?"yes"|"no"}) : H:Flow =
         (match p with  {presenter="yes"} -> [<strong class="ocaml">a] | _ -> a)

let authors ([Author+] -> H:Flow)
 | [ <author (p)>a ] -> render a p
 | [ <author (p1)>a1 <author (p2)>a2 ] -> (render a1 p1) @ ", and " @ (render a2 p2)
 | [ <author (p)>a; rem ] -> (render a p)@ ", " @ authors rem
131

132
let find_local_link (sitemap : [Tree*], l : String) : Tree =
133
134
match sitemap with
 | (h,t) ->
135
   if (h . name = l) then h
136
137
138
   else 
    (try find_local_link (t,l) with `Not_found -> 
         find_local_link (h . children,l))
139
 | [] -> raise `Not_found
140

141
let local_link (sitemap : Tree, l : String, txt : String) : H:Inline =
142
143
144
145
 try 
  let h = find_local_link ([sitemap],l)  in
  let txt = if txt = "" then h . title else txt in
  <a href=(h . url)>txt
146
 with `Not_found -> raise [ 'Local link not found: ' !l ]
147
 
148
let compute_sitemap ((Page|External) -> Tree)
149
 | <page name=name>[ <title>title (c::(Page|External) | _)* ] & p ->
150
   let children = map c with p -> compute_sitemap p in
151
   { name = name; url = (url_of_page p); title = title; 
152
     children = children; boxes = (boxes_of p) }
153
 | <external name=name href=h title=t>[] ->
154
   { name = name; url = h; title = t; children = []; boxes = [] }
155

156
157
let ul([H:Xli*] -> [H:Xul?]) [] -> [] | l -> [ <ul>l ]

158
159
160
161
162
let ol(([H:Xli*],{|style=?String|}) -> [H:Xol?]) 
      ([],_) -> [] 
    | (l,s&{|style=?String|}) -> [ <ol (s)>l ] 


163

164
let display_sitemap (h : Tree) :  H:Xli =
165
  let ch = map h . children with x -> display_sitemap x in
166
  <li>[ <a href=(h . url)>[ '[' !(h . title) ']' ] !(h . boxes); (ul ch) ]
167

168

169
let boxes_of (Page -> [H:Xul?])
170
<page>[ (items::Item | _)*] & p ->
171
 let toc = transform items with 
172
 | <box title=t link=l>_ -> [ <li>[ <a href=[ !(url_of_page p) '#' !l ]>t ] ] 
173
174
175
 in
 ul toc

176
let link_to (<page>[<title>t ; _ ] & p : Page) : H:Xa =
177
178
179
 let t = match p with
 | <_ new="">_ -> t @ [ <img src="img/new.gif" alt="(new)" style="border:0">[]]
 | _ -> t in
180
 <a href=(url_of_page p)>t
181

182
let small_box (x : H:Flow) : H:Block =
183
 <table cellpadding="2" 
184
185
    style="font-size:11px ; font-family:arial,sans-serif;
           border: solid 2px black; background: #ffffff" width="100%">
186
187
   [ <tr> [<td>x] ]

188
let meta (x : H:Flow) : H:Block =
189
 <table cellpadding="2" 
190
    style="border: solid 1px #b0b0b0; background: #e0e0e0; font-size: 80%"  
191
192
193
    width="100%">
   [ <tr> [<td>x] ]

194
let box_title (x : H:Flow, a : String, t : String) : H:Block =
195
196
 <table cellpadding="5" 
    style="border: solid 2px black; background: #ffffff" width="100%">
197
198
199
200
   [ <tr>[ 
       <td style="background: #fff0f0; color: #0000ff; font: bold 100%
                  helvetica">[<a name=a>t] ] 
     <tr> [<td>x] ]
201

202
203
204
205
206
let box (x : H:Flow) : H:Block =
 <table cellpadding="5" 
    style="border: solid 2px black; background: #ffffff" width="100%">
   [ <tr> [<td>x] ]

207
208
209
210
211
212
let style = "
a:link:hover, a:visited:hover {
  text-decoration: none;
  background: #FFFFD0;
  color: #FF0000;
}
213
214
215
216
217
218
219
220
a.old, a.old:hover, a.old:visited:hover { text-decoration: line-through; }
p { text-align: justify; margin: 1ex 1em 0 1em; }
pre { margin: 1ex 1em 0 1em; }
strong.ocaml{ color: #333b8e; }
strong.highlight { color: #FF0000; }
img.icon { border: 0; }
div.code { background: #E0E0E0; margin: 0.5ex 0.5em 0 0.5em; padding: 0.2ex; }
div.xmlcode { background:#ebefa2; margin: 0.5ex 0.5em 0 0.5em; padding: 0.2ex;}
221

222
div.abstract { 
223
  font: bold helvetica;
224
225
226
227
  margin: 1ex 1em 1ex 1em;
  padding: 1ex 1em 1ex 1em;
  background: #F0F0F0;
}
228
229

div.note { 
230
  text-align: justify;
231
232
233
234
235
236
  font: bold helvetica;
  margin: 1ex 3em 1ex 3em;
  padding: 1ex 1em 1ex 1em;
  background: #D0E2D2;
}

237
238
239
240
241
242
243
244
div.session
 { 
  font: bold 80% helvetica;
  margin: 1ex 1em 1ex 1em;
  padding: 1ex 1em 1ex 1em;
  border: solid .5px grey;
}

245
div.abstract p { font: sans-serif; }
246
247
"

248
249
type PageO = Page | []

250
251
(* Main transformation function *)

252
(* returns the last page of the descendance *)
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

let thumbnail(w : String, h : String)
 (url : String)(title : String) : H:Inlines =
 [ <a href=url>[ 
   <img src=url width=w height=h alt="Click to enlarge" title=title>[] ] ]

let thumbwh({ width =? IntStr; height =? IntStr} -> 
   (String -> String ->H:Inlines))
  | { width = w; height = h } ->
      let w = int_of w in let h = int_of h in
      (match h with
       | 0 -> raise "Thumbnail height = 0"
       | h -> let w = string_of ((w * 200) div h) in thumbnail (w,"200"))
  | _ -> thumbnail ("266","200")

268
269
let gen_page (site : String,
              prev : PageO, page : Page, next : PageO, 
270
271
              path : Path, sitemap : Tree) : PageO = 
match page with 
272
<page name=name>[ 
273
 <title>title <banner>banner | <title>(title & banner); items ] ->
274

275
 let footnote_counter = ref Int 0 in 
276
 let footnotes = ref H:Flow [] in
277

278
 let text (t : [InlineText*]) : H:Inlines =
279
280
  transform t with
   | <code>x -> [ <b>[ <tt>(highlight x) ] ]
281
282
   | <local href=l>txt -> 
	[ (local_link (sitemap,l,txt)) ]
283
   | <(tag & (`b|`i|`tt|`em)) (attr)>x -> [ <(tag) (attr)>(text x) ]
284
285
286
287
288
   | <footnote nocount=_>_ -> 
      let n = string_of !footnote_counter in
      [ <a name=[ 'bnote' !n ]>[]
        <a href=[ '#note' !n ]>[ '[' !n ']' ] ]

289
290
291
292
293
294
295
296
297
298
299
   | <footnote>c -> 
      footnote_counter := !footnote_counter + 1;
      let n = string_of !footnote_counter in
      let fn = !footnotes in
      footnotes := [];
      let c = <p>[ <a name=[ 'note' !n ]>[] 
                   <a href=[ '#bnote' !n ]>[ '[' !n ']' ]
		   ' ' ; text c ] in
      footnotes := fn @ [ c ] @ !footnotes;
      [ <a name=[ 'bnote' !n ]>[]
        <a href=[ '#note' !n ]>[ '[' !n ']' ] ]
300
301
302
303
304
305
306
307
308
309
   | <thumbnail ({href=url} & r)>[] ->
      thumbwh r url ""
   | <thumbnails ({href=url} & r)>l ->
      let l = split_thumbnails l in
      let f = thumbwh r in
      let c = ref Int 0 in
      (transform l with (x,y) -> 
          let t = f (url @ x) y in
          if (!c = 4) then (c := 1; [ <br>[] ] @ t)
          else (c := !c + 1; t))
310
   | z -> [ z ] 
311
 in
312

313
 let content (t : Content) : H:Flow =
314
  transform t with
315
   | <section title=title>c -> 
316
         [ <p>[ <b style="color: #008000">title ] !(content c) ]
317
   | <paper (r)>[ <title>tit aut::Author* <comment>com <abstract>ab  ]  ->
318
         [ (match r with
319
           | { file = f; old = "" } -> <a class="old" href=f>tit
320
321
           | { file = f } -> <a href=f>tit
           | _ -> <b>tit) '. '
322
           !(authors aut) '. '
323
	   !(text com)
324
325
326
           <div class="abstract">[ 'Abstract:' !(content ab) ]
         ]
   | <slides file=f>[ <title>tit aut::Author* <comment>com ]  ->
327
        [ <a href=f>tit '. ' !(authors aut) '. ' !(text com) ]
328
329
   | <sample highlight="false">s ->
        [ <div class="code">[ <pre>s ] ]
330
   | <sample>s ->
331
        [ <div class="code">[ <pre>(highlight s) ] ]
332
333
334
335
   | <xmlsample highlight="false">s ->
        [ <div class="xmlcode">[ <pre>s ] ]
   | <xmlsample>s ->
        [ <div class="xmlcode">[ <pre>(highlight s) ] ]
336
337
338
339
   | <sessionsample highlight="false">s ->
        [ <div class="session">[ <pre>s ] ]
   | <sessionsample>s ->
        [ <div class="session">[ <pre>(highlight s) ] ]
340
   | <link url=url title=title>com -> 
341
        [ <ul>[ <li>[ <a href=url>title '. ' !(text com) ] ] ]
342
   | <ul>lis -> 
343
        ul (map lis with <li>x -> <li>(content x))
344
345
   | <ol (attr) >lis -> 
        ol ((map lis with <li>x -> <li>(content x) ),(attr))
346
   | H:Xtable & x -> 
347
       [ <table width="100%">[<tr>[<td align="center">[x]]] ]
348
   | <p (attr)>x -> [ <p (attr)>(text x) ]
349
   | <pages-toc (a)>[] ->
350
351
352
353
354
355
      let toc = transform items with 
      | Page & p -> 
        let sects = match a with {|sections=_|} -> boxes_of p | _ -> [] in
        [ <li>[ (link_to p) ; sects ] ]
      | <external href=l title=t>[] -> [ <li>[ <a href=l>t ] ] in
      ul toc
356
   | <boxes-toc (a)>[] ->
357
358
      let sections = match a with { section=_ } -> `true | _ -> `false in
      let short = match a with { short=_ } -> `true | _ -> `false in
359
      let toc = transform items with 
360
361
362
363
      | <box ({title=t; link=l} & ({short=s} | {title=s}))>b ->
        let t = if short then s else t in
        let sects = 
         if sections then
364
          (transform b with <section title=t>_ -> [<br>[] '-' !t])
365
         else [] in
366
367
        [ <li>[ <a href=('#',l)>t !sects ]] in
      ul toc
368
369
370
   | <site-toc>[] ->
        [ <ul>[ (display_sitemap sitemap) ] ]
   | <local-links href=s>[] ->
371
        ul (map (split_comma s) with x -> <li>[ (local_link(sitemap,x,"")) ])
372
373
374
375
376
   | <two-columns>[ <left>x <right>y ] ->
	[ <table width="100%">[ 
            <tr>[ 
              <td valign="top">(content x) 
              <td valign="top">(content y) ] ] ]
377
   | <note title=t>c ->  [ <div class="note">[ <b>[!t ':  '] !(content c) ]]
378
379
380
381
382
   | <note>c ->  [ <div class="note">[ <b>"Note:  " !(content c) ]]
   | <footnotes>[] -> 
       (match !footnotes with 
        | [] -> [] 
        | n -> footnotes := []; [ <br>[] (meta n) ] )
383
384
   | t -> text [ t ]
 in
385

386
(* Preparing left panel *)
387

388
389
390
391
 let navig = transform items with <left>c -> [ c ] in
 let left = match navig with [] -> [ [<boxes-toc>[]] ] | n -> n in
 let left = 
   <td valign="top" align="left">[
392
     <table cellpadding="0" cellspacing="15" 
393
394
            width="200"
            style="font-size:80%; border: 1px dashed black;
395
                   background: #ffcd72">	(* altbg 9aa8ba *)
396
     (map left with x -> <tr>[ <td>[ (small_box (content x)) ] ]) ] in
397

398
 let dpath : H:Inlines = transform path with 
399
  | { url = f; title = t } -> [ <a href=f>t ': '] 
400
 in
401
 let npath = path @ [ { url = (url_of_page page); title = title } ] in
402
 let subpages = transform items with p & Page -> [ p ] in
403
 let (next,last) = gen_page_seq (site,page, subpages, next, npath, sitemap) in
404
 let next = match next with [] -> [] 
405
406
   | <page>[ <title>t; _ ] & p -> 
      [ <a href=(url_of_page p)>[ 
407
          <img width="16" height="16" class="icon" alt="Next page:"
408
               src="img/right.gif">[]
409
410
411
          ' ' !t
        ] ] in
 let prev = match prev with [] -> [] 
412
413
   | <page>[ <title>t; _ ] & p -> 
      [ <a href=(url_of_page p)>[ 
414
          <img width="16" height="16" class="icon"
415
               alt="Previous page:" src="img/left.gif">[]
416
417
          ' ' !t
        ] ] in
418
 let navig = 
419
   if prev = [] then [] else
420
   [ (small_box [
421
     <p>[ !dpath !title ]
422
423
424
425
     <p>[ !prev ' ' !next ] ]) ] in

(* Preparing main panel *)
 let main = transform items with
426
427
   | <box title=t link=l>c -> [ (box_title (content c, l, t)) ]
   | <box>c -> [ (box (content c)) ]
428
429
430
431
   | <footnotes>[] -> 
       (match !footnotes with 
        | [] -> [] 
        | n -> footnotes := []; [ (meta n) ] )
432
   | <meta>c -> [ (meta (content c)) ]
433
 in
434
435
436
437
 let notes = match !footnotes with
   | [] -> []
   | n -> [ (meta n) ] in
 let main = match (navig @ main @ notes @ navig) with
438
439
440
   | [] -> raise "Empty page !"
   | x -> x in

441
 let right : H:Xtd =
442
443
444
445
446
447
448
449
450
451
  <td valign="top" align="left" style="width:100%">[
   <table width="100%">[
    <tr>[ <td valign="top" align="left"
              style="border: 2px solid black; background: #ffffff;
text-align:center; color: #aa0000; font: bold 200% helvetica" >
          (text banner)
        ]
 
    <tr>[
      <td valign="top" align="left"
452
          style="border: 1px solid black; background: #fccead">[ (* altbg c8ccd1 *)
453
       <table width="100%" cellpadding="0" cellspacing="17">
454
455
456
457
         (map main with x -> <tr>[ <td>[x] ])
      ] ]
  ] ] in

458
 let html : H:Xhtml =
459
460
 <html>[
  <head>[ 
461
   <title>[ !site ': ' !title ]
462
   <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">[]
463
   <style type="text/css">style
464
  ]
465
  <body style="margin: 0; padding : 0; background: #fcb333">[  (* altbg  4e6e99 *)
466
467
468
   <table cellspacing="10" cellpadding="0" width="100%" border="0">[
    <tr>[ left right ]
   ]
469
  ]
470
471
 ]
 in
472
 let txt : Latin1 = 
473
   [ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
474
     '  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
475
476
     !(print_xml html) ] in
 let fn = "www/" @ name @ ".html" in
477
 dump_to_file fn txt;
478
 last
479
	
480

481
let gen_page_seq 
482
483
 (site : String,
  prev : PageO, pages : [Page*], next : PageO, 
484
  path : Path, sitemap : Tree) : (PageO, PageO) =
485
486
 match pages with
 | [ p1 p2 ; _ ] & [ _; rest ] -> 
487
488
     let last = gen_page (site,prev,p1,p2, path, sitemap) in
     let (_,last)  = gen_page_seq (site,last, rest, next, path, sitemap) in 
489
     (p1,last)
490
 | [ p ] ->
491
     let last = gen_page (site,prev,p,next, path, sitemap) in (p,last)
492
 | [] -> (next,prev)
493

494

495
;;
496

497
match load_include input with
498
499
 | [ <site>[ <title>(site & String) (p & Page) ] ] -> 
   let _ = gen_page (site,[],p,[], [], compute_sitemap p) in []
500
 | _ -> raise ("Invalid input document " @ input)