doc.pl 19.7 KB
Newer Older
Thierry Martinez's avatar
Thierry Martinez committed
1
2
3
4
:- module(
  doc,
  [
    doc/1,
Thierry Martinez's avatar
Thierry Martinez committed
5
    devdoc/1,
Thierry Martinez's avatar
Thierry Martinez committed
6
    grammar/1,
Thierry Martinez's avatar
Thierry Martinez committed
7
8
    biocham/1,
    biocham_silent/1,
Thierry Martinez's avatar
Thierry Martinez committed
9
10
11
12
    generate_doc/0
  ]
).

Thierry Martinez's avatar
Thierry Martinez committed
13
14
15
doc(_) :-
  !,
  true.
Thierry Martinez's avatar
Thierry Martinez committed
16

Thierry Martinez's avatar
Thierry Martinez committed
17
18
19
20
21
doc(_) :-
  doc('
    Writes in the documentation (both the Reference Manual
    and the Developer Manual).
  ').
Thierry Martinez's avatar
Thierry Martinez committed
22
23


Thierry Martinez's avatar
Thierry Martinez committed
24
25
devdoc(_) :-
  doc('Writes in the Developer Manual.').
Thierry Martinez's avatar
Thierry Martinez committed
26
27


Thierry Martinez's avatar
Thierry Martinez committed
28
29
grammar(_) :-
  doc('Declares a grammar predicate to be written in the documentation.').
Thierry Martinez's avatar
Thierry Martinez committed
30
31


Thierry Martinez's avatar
Thierry Martinez committed
32
33
34
35
36
37
biocham(_).


biocham_silent(_).


Thierry Martinez's avatar
Thierry Martinez committed
38
generate_doc :-
Thierry Martinez's avatar
Thierry Martinez committed
39
  set_plot_driver(gnu_plot_png),
Thierry Martinez's avatar
SBML    
Thierry Martinez committed
40
41
  set_image_viewer_driver(img_tag),
  set_draw_graph_driver(graph_svg),
Thierry Martinez's avatar
Thierry Martinez committed
42
43
44
45
46
  generate_doc(doc),
  generate_doc(devdoc).


generate_doc(Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
47
  catch(
Thierry Martinez's avatar
Thierry Martinez committed
48
    make_directory(Type),
Thierry Martinez's avatar
Thierry Martinez committed
49
50
51
    error(existence_error(directory, _), _),
    true
  ),
Thierry Martinez's avatar
SBML    
Thierry Martinez committed
52
53
  set_counter(plot_png, 0),
  set_counter(graph_svg, 0),
Thierry Martinez's avatar
Thierry Martinez committed
54
55
  working_directory(OldDir, Type),
  format(atom(IndexFilename), 'index.html', [Type]),
Thierry Martinez's avatar
Thierry Martinez committed
56
  setup_call_cleanup(
Thierry Martinez's avatar
Thierry Martinez committed
57
58
    open(IndexFilename, write, Stream),
    generate_doc(Stream, Type),
Thierry Martinez's avatar
Thierry Martinez committed
59
    close(Stream)
Thierry Martinez's avatar
Thierry Martinez committed
60
61
  ),
  working_directory(_OldDir, OldDir).
Thierry Martinez's avatar
Thierry Martinez committed
62
63


Thierry Martinez's avatar
Thierry Martinez committed
64
generate_doc(Doc, Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
65
  version(Version),
Thierry Martinez's avatar
Thierry Martinez committed
66
67
  doc_title(Type, DocTitle),
  format(atom(Title), 'Biocham ~a ~a', [Version, DocTitle]),
Thierry Martinez's avatar
Thierry Martinez committed
68
69
70
71
72
73
74
75
76
  format(Doc, '\c
<!DOCTYPE html>
<html>
<head>
  <title>~a</title>
</head>
<body>
  <h1>~a</h1>
', [Title, Title]),
Thierry Martinez's avatar
Thierry Martinez committed
77
78
  generate_toc(Doc, Type),
  generate_body(Doc, Type),
Thierry Martinez's avatar
Thierry Martinez committed
79
80
81
82
83
  write(Doc, '
</body>
</html>').


Thierry Martinez's avatar
Thierry Martinez committed
84
85
86
87
88
doc_title(doc, 'Reference Manual').

doc_title(devdoc, 'Developer Manual').


Thierry Martinez's avatar
Thierry Martinez committed
89
90
91
:- dynamic(toc/1).


Thierry Martinez's avatar
Thierry Martinez committed
92
generate_toc(Doc, Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
93
  retractall(toc(_)),
Thierry Martinez's avatar
Thierry Martinez committed
94
95
  nb_setval(last_level, 0),
  read_toc(Type),
Thierry Martinez's avatar
Thierry Martinez committed
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
  write(Doc, '  <h2 id="Contents">Contents</h2>\n'),
  nb_setval(current_counters, []),
  \+ (
    toc(section(Level, Title)),
    \+ (
      generate_toc_section(Doc, Level, Title)
    )
  ),
  goto_toc_level(Doc, 0).


generate_toc_section(Doc, Level, Title) :-
  goto_toc_level(Doc, Level),
  indent(Doc, Level),
  increment_counter,
  write(Doc, '<li>'),
  write_counters(Doc),
  make_id(Title, Id),
  format(Doc, ' <a href="#~a">~a</a></li>\n', [Id, Title]).


goto_toc_level(Doc, Level) :-
  nb_getval(current_counters, OldCounters),
  length(OldCounters, OldLevel),
  (
    OldLevel > Level
  ->
    LevelDiff is OldLevel - Level,
    \+ (
      between(1, LevelDiff, I),
      \+ (
        CurrentLevel is OldLevel - I,
        indent(Doc, CurrentLevel),
        write(Doc, '</ul>\n')
      )
    )
  ;
    OldLevel = Level
  ->
    true
  ;
    OldLevel is Level - 1
  ->
    indent(Doc, OldLevel),
    write(Doc, '<ul>\n')
  ;
    throw(error(bad_toc_structure))
  ),
  goto_level(Level).


goto_level(Level) :-
  nb_getval(current_counters, OldCounters),
  length(OldCounters, OldLevel),
  (
    OldLevel > Level
  ->
    LevelDiff is OldLevel - Level,
    length(FormerCounters, LevelDiff),
    append(NewCounters, FormerCounters, OldCounters),
    nb_setval(current_counters, NewCounters)
  ;
    OldLevel = Level
  ->
    true
  ;
    OldLevel is Level - 1
  ->
    append(OldCounters, [0], NewCounters),
    nb_setval(current_counters, NewCounters)
  ;
    throw(error(bad_toc_structure))
  ).


increment_counter :-
  nb_getval(current_counters, OldCounters),
  append(HigherCounters, [LastCounter], OldCounters),
  NewCounter is LastCounter + 1,
  append(HigherCounters, [NewCounter], NewCounters),
  nb_setval(current_counters, NewCounters).


write_counters(Doc) :-
  nb_getval(current_counters, Counters),
Thierry Martinez's avatar
Thierry Martinez committed
181
182
183
  write_counters(Doc, Counters).

write_counters(Doc, Counters) :-
Thierry Martinez's avatar
Thierry Martinez committed
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
  \+ (
    member(Counter, Counters),
    \+ (
      format(Doc, '~d.', [Counter])
    )
  ).


make_id(Title, Id) :-
  atom_chars(Title, Chars),
  filter_id(Chars, CharsId),
  atom_chars(Id, CharsId).


filter_id([], []).

filter_id([Char | Tail], [Char | TailId]) :-
  (
    '0' @=< Char, Char @=< '9'
  ;
    'A' @=< Char, Char @=< 'Z'
  ;
    'a' @=< Char, Char @=< 'z'
  ;
    Char = '_'
  ;
    Char = '-'
  ;
    Char = '.'
  ),
  !,
  filter_id(Tail, TailId).

filter_id([' ' | Tail], ['_' | TailId]) :-
  !,
  filter_id(Tail, TailId).

filter_id(['/' | Tail], ['-' | TailId]) :-
  !,
  filter_id(Tail, TailId).

filter_id([_ | Tail], Id) :-
  filter_id(Tail, Id).


Thierry Martinez's avatar
Thierry Martinez committed
229
read_toc(Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
230
  setup_call_cleanup(
Thierry Martinez's avatar
Thierry Martinez committed
231
    open('../toc.org', read, Stream),
Thierry Martinez's avatar
Thierry Martinez committed
232
    read_toc(Stream, Type),
Thierry Martinez's avatar
Thierry Martinez committed
233
234
235
236
    close(Stream)
  ).


Thierry Martinez's avatar
Thierry Martinez committed
237
read_toc(Stream, Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
238
239
240
241
242
243
244
245
246
247
248
249
  \+ (
    repeat,
    read_line_to_codes(Stream, Line),
    (
      Line = end_of_file
    ->
      !
    ;
      atom_codes(Atom, Line),
      (
        atom_concat('* ', Section, Atom)
      ->
Thierry Martinez's avatar
Thierry Martinez committed
250
        add_section(1, Section)
Thierry Martinez's avatar
Thierry Martinez committed
251
252
253
      ;
        atom_concat('** ', Section, Atom)
      ->
Thierry Martinez's avatar
Thierry Martinez committed
254
        add_section(2, Section)
Thierry Martinez's avatar
Thierry Martinez committed
255
256
257
      ;
        atom_concat('*** ', Section, Atom)
      ->
Thierry Martinez's avatar
Thierry Martinez committed
258
259
260
261
262
263
264
265
266
        add_section(3, Section)
      ;
        Atom = '+ index'
      ->
        assertz(toc(index))
      ;
        Atom = '- biocham.bib'
      ->
        assertz(toc(bibliography))
Thierry Martinez's avatar
Thierry Martinez committed
267
268
269
      ;
        atom_concat('- ', File, Atom)
      ->
Thierry Martinez's avatar
Thierry Martinez committed
270
271
272
273
274
275
276
277
278
279
        (
          Type = devdoc,
          atom_concat(_, '.pl', File)
        ->
          nb_getval(last_level, Level),
          LevelSucc is Level + 1,
          add_section_nolevel(LevelSucc, File)
        ;
          true
        ),
Thierry Martinez's avatar
Thierry Martinez committed
280
281
282
283
284
285
286
        assertz(toc(file(File)))
      )
    ),
    fail
  ).


Thierry Martinez's avatar
Thierry Martinez committed
287
288
289
290
291
292
293
294
295
296
add_section(Level, Section) :-
  add_section_nolevel(Level, Section),
  nb_setval(last_level, Level).

add_section_nolevel(Level, Section) :-
  assertz(toc(section(Level, Section))).


generate_body(Doc, Type) :-
  retractall(index_contents(_, _)),
Thierry Martinez's avatar
Thierry Martinez committed
297
298
299
300
  nb_setval(current_counters, []),
  \+ (
    toc(Item),
    \+ (
Thierry Martinez's avatar
Thierry Martinez committed
301
      generate_body_item(Item, Doc, Type)
Thierry Martinez's avatar
Thierry Martinez committed
302
303
304
305
    )
  ).


Thierry Martinez's avatar
Thierry Martinez committed
306
generate_body_item(section(Level, Title), Doc, _Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  goto_level(Level),
  increment_counter,
  make_id(Title, Id),
  (
    Level = 1
  ->
    nb_getval(current_counters, [Counter]),
    format(Doc, '<h2 id="~a">Chapter ~d<br />~a</h2>', [Id, Counter, Title])
  ;
    HLevel is Level + 1,
    format(Doc, '<h~d id="~a">', [HLevel, Id]),
    write_counters(Doc),
    format(Doc, ' ~a</h~d>\n', [Title, HLevel])
  ).


Thierry Martinez's avatar
Thierry Martinez committed
323
generate_body_item(file(File), Doc, Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
324
  atom_concat('../', File, ParentFile),
Thierry Martinez's avatar
Thierry Martinez committed
325
  setup_call_cleanup(
Thierry Martinez's avatar
Thierry Martinez committed
326
    open(ParentFile, read, Stream),
Thierry Martinez's avatar
Thierry Martinez committed
327
    generate_body_item_stream(Stream, Doc, Type),
Thierry Martinez's avatar
Thierry Martinez committed
328
329
330
    close(Stream)
  ).

Thierry Martinez's avatar
Thierry Martinez committed
331
332
generate_body_item(index, Doc, _Type) :-
  \+ (
Thierry Martinez's avatar
Thierry Martinez committed
333
    bagof(Entry, index_entry(Letter, Entry), Entries),
Thierry Martinez's avatar
Thierry Martinez committed
334
335
336
    \+ (
      format(Doc, '<h4>~a</h4>\n', [Letter]),
      write(Doc, '<ul>\n'),
Thierry Martinez's avatar
Thierry Martinez committed
337
      sort(1, @=<, Entries, SortedEntries),
Thierry Martinez's avatar
Thierry Martinez committed
338
      \+ (
Thierry Martinez's avatar
Thierry Martinez committed
339
        member((Key: Sections), SortedEntries),
Thierry Martinez's avatar
Thierry Martinez committed
340
341
342
        \+ (
          format(Doc, '<li>~a ', [Key]),
          \+ (
Thierry Martinez's avatar
Thierry Martinez committed
343
            member(Section - Id, Sections),
Thierry Martinez's avatar
Thierry Martinez committed
344
345
            \+ (
              format(Doc, '<a href="#~a">', [Id]),
Thierry Martinez's avatar
Thierry Martinez committed
346
              write_counters(Doc, Section),
Thierry Martinez's avatar
Thierry Martinez committed
347
348
349
350
351
352
353
354
355
356
              write(Doc, '</a>')
            )
          ),
          write(Doc, '</li>\n')
        )
      ),
      write(Doc, '</ul>\n')
    )
  ).

Thierry Martinez's avatar
Thierry Martinez committed
357

Thierry Martinez's avatar
Thierry Martinez committed
358
359
360
361
362
363
364
365
366
generate_body_item(bibliography, _Doc, _Type) :-
  true.
%  setup_call_cleanup(
%    open('biocham.bib', read, Stream),
%    generate_body_item_stream(Stream, Doc, Type),
%    close(Stream)
%  ).


Thierry Martinez's avatar
Doc    
Thierry Martinez committed
367
generate_body_item_stream(SourceStream, Stream, Type) :-
Thierry Martinez's avatar
Thierry Martinez committed
368
  nb_setval(current_grammar, none),
Thierry Martinez's avatar
Thierry Martinez committed
369
370
371
  \+ (
    repeat,
    read_term(
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
372
373
374
      SourceStream,
      Clause,
      [variables(Variables), variable_names(VariableNames)]
Thierry Martinez's avatar
Thierry Martinez committed
375
376
377
378
    ),
    (
      Clause = end_of_file
    ->
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
379
      close_grammar(Stream),
Thierry Martinez's avatar
Thierry Martinez committed
380
      !
Thierry Martinez's avatar
Thierry Martinez committed
381
382
383
384
385
386
387
388
    ;
      (
        Clause = (:- doc(Contents))
      ;
        Clause = (:- devdoc(Contents)),
        Type = devdoc
      )
    ->
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
389
390
      write_doc(Stream, Contents),
      nl(Stream)
Thierry Martinez's avatar
Thierry Martinez committed
391
    ;
Thierry Martinez's avatar
Thierry Martinez committed
392
393
      Clause = (:- grammar(Grammar))
    ->
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
394
      close_grammar(Stream),
Thierry Martinez's avatar
Thierry Martinez committed
395
396
397
      nb_setval(current_grammar, Grammar),
      make_id(Grammar, Id),
      format(
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
398
        Stream,
Thierry Martinez's avatar
Thierry Martinez committed
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
        '<table id="~a"><tr><td>~a ::= </td><td>\n',
        [Id, Grammar]
      )
    ;
      nb_getval(current_grammar, Grammar),
      Grammar \= none,
      (
        Clause = (Head :- Body)
      ;
        Clause = Head,
        Body = true
      ),
      Head =.. [Grammar, Item]
    ->
      instantiate_grammar_body(Body),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
414
      format(Stream, '<div>| <code>~w</code></div>', [Item])
Thierry Martinez's avatar
Thierry Martinez committed
415
    ;
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
416
      close_grammar(Stream),
Thierry Martinez's avatar
Thierry Martinez committed
417
      name_variables_and_anonymous(Variables, VariableNames),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
418
      generate_body_item_clause(Clause, Stream, Type)
Thierry Martinez's avatar
Thierry Martinez committed
419
420
421
422
423
    ),
    fail
  ).


Thierry Martinez's avatar
Thierry Martinez committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
close_grammar(Stream) :-
  nb_getval(current_grammar, Grammar),
  (
    Grammar = none
  ->
    true
  ;
    nb_setval(current_grammar, none),
    write(Stream, '</td></tr></table>\n')
  ).


instantiate_grammar_body((G0, G1)) :-
  !,
  instantiate_grammar_body(G0),
  instantiate_grammar_body(G1).

instantiate_grammar_body(true) :-
  !.

Thierry Martinez's avatar
Thierry Martinez committed
444
445
446
447
448
449
450
451
452
453
instantiate_grammar_body(list(Grammar, NonTerminal)) :-
  !,
  make_id(Grammar, Id),
  format(
    atom(NonTerminal), '
      [</code> <a href="#~a">~a</a>
       <code>,</code> ... <code>,</code>
       <a href="#~a">~a</a> <code>] ', [Id, Grammar, Id, Grammar]
  ).

Thierry Martinez's avatar
Thierry Martinez committed
454
455
456
457
458
459
460
461
462
463
instantiate_grammar_body(function_application(Grammar, NonTerminal)) :-
  !,
  make_id(Grammar, Id),
  format(
    atom(NonTerminal), '
      </code> <a href="#name">name</a><code>(</code><a href="#~a">~a</a>
       <code>,</code> ... <code>,</code>
       <a href="#~a">~a</a><code>) ', [Id, Grammar, Id, Grammar]
  ).

Thierry Martinez's avatar
Thierry Martinez committed
464
465
466
467
468
469
470
471
instantiate_grammar_body(Item) :-
  Item =.. [Grammar, NonTerminal],
  make_id(Grammar, Id),
  format(
    atom(NonTerminal), ' </code> <a href="#~a">~a</a> <code> ', [Id, Grammar]
  ).


Thierry Martinez's avatar
Thierry Martinez committed
472
473
474
:- dynamic(argument_type/2).


Thierry Martinez's avatar
Thierry Martinez committed
475
476
generate_body_item_clause(Clause, Stream, Type) :-
  predicate_info(Clause, ArgumentTypes, BiochamCommand, Doc),
Thierry Martinez's avatar
Thierry Martinez committed
477
  (
Thierry Martinez's avatar
Thierry Martinez committed
478
    (
Thierry Martinez's avatar
Thierry Martinez committed
479
      BiochamCommand = yes
Thierry Martinez's avatar
Thierry Martinez committed
480
481
    ;
      BiochamCommand = variantargs
Thierry Martinez's avatar
Thierry Martinez committed
482
483
    ;
      Type = devdoc,
Thierry Martinez's avatar
Thierry Martinez committed
484
      Doc \= []
Thierry Martinez's avatar
Thierry Martinez committed
485
    )
Thierry Martinez's avatar
Thierry Martinez committed
486
  ->
Thierry Martinez's avatar
Thierry Martinez committed
487
    Clause = (Head :- _),
Thierry Martinez's avatar
Thierry Martinez committed
488
489
    Head =.. [Command | Arguments],
    retractall(argument_type(_, _)),
Thierry Martinez's avatar
Thierry Martinez committed
490
491
492
493
494
495
496
497
    \+ (
      nth0(Index, Arguments, Argument),
      nth0(Index, ArgumentTypes, ArgumentType),
      nonvar(ArgumentType),
      \+ (
        assertz(argument_type(Argument, ArgumentType))
      )
    ),
Thierry Martinez's avatar
Thierry Martinez committed
498
499
500
501
502
503
504
505
506
    (
      BiochamCommand = variantargs
    ->
      format(atom(Key), '~a/*', [Command])
    ;
      length(Arguments, Arity),
      format(atom(Key), '~a/~w', [Command, Arity])
    ),
    make_id(Key, Id),
Thierry Martinez's avatar
Thierry Martinez committed
507
    index_use_id(Key, Id),
Thierry Martinez's avatar
Thierry Martinez committed
508
509
510
    format(Stream, '<h5 id="~a""><code>~a', [Id, Command]),
    write_arguments(Arguments, Stream),
    write(Stream, '.</code></h5>\n'),
Thierry Martinez's avatar
Thierry Martinez committed
511
    write(Stream, '<div>'),
Thierry Martinez's avatar
Thierry Martinez committed
512
513
    \+ (
      member(DocItem, Doc),
Thierry Martinez's avatar
Thierry Martinez committed
514
515
516
517
518
      \+ (
        write_doc_item(DocItem, Stream, Type)
      )
    ),
    write(Stream, '</div>')
Thierry Martinez's avatar
Thierry Martinez committed
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  ;
    true
  ).


write_arguments([], _Doc) :-
  !,
  true.

write_arguments([First | Arguments], Doc) :-
  write(Doc, '('),
  write_argument(First, Doc),
  \+ (
    member(Argument, Arguments),
    \+ (
      write(Doc, ', '),
      write_argument(Argument, Doc)
    )
  ),
  write(Doc, ')').


write_argument(Argument, Doc) :-
  (
    argument_type(Argument, Type)
  ->
    (
Thierry Martinez's avatar
Thierry Martinez committed
546
547
548
549
550
551
552
553
554
      Type = '*'(Name = Value)
    ->
      make_id(Name, NameId),
      make_id(Value, ValueId),
      format(
        Doc,
        '<a href="#~a">~a</a><sub>1</sub> = <a href="#~a">~a</a><sub>1</sub>,
         ...,
         <a href="#~a">~a</a><sub><var>n</var></sub> =
Thierry Martinez's avatar
Thierry Martinez committed
555
         <a href="#~a">~a</a><sub><var>n</var></sub>',
Thierry Martinez's avatar
Thierry Martinez committed
556
557
        [NameId, Name, ValueId, Value, NameId, Name, ValueId, Value]
      )
Thierry Martinez's avatar
Thierry Martinez committed
558
559
560
561
562
563
564
565
566
567
568
    ;
      Type = '*'([Name])
    ->
      make_id(Name, NameId),
      format(
        Doc,
        '[<a href="#~a">~a</a><sub>1</sub>],
         ...,
         [<a href="#~a">~a</a><sub><var>n</var></sub>]',
        [NameId, Name, NameId, Name]
      )
Thierry Martinez's avatar
Thierry Martinez committed
569
570
571
572
573
574
575
576
577
578
579
    ;
      Type = '*'(Name)
    ->
      make_id(Name, NameId),
      format(
        Doc,
        '<a href="#~a">~a</a><sub>1</sub>,
         ...,
         <a href="#~a">~a</a><sub><var>n</var></sub>',
        [NameId, Name, NameId, Name]
      )
Thierry Martinez's avatar
Thierry Martinez committed
580
    ;
Thierry Martinez's avatar
Thierry Martinez committed
581
      Type = '='(ItemType)
Thierry Martinez's avatar
Thierry Martinez committed
582
    ->
Thierry Martinez's avatar
Thierry Martinez committed
583
      make_id(ItemType, Id),
Thierry Martinez's avatar
Thierry Martinez committed
584
585
      format(
        Doc,
Thierry Martinez's avatar
Thierry Martinez committed
586
587
588
        '<a href="#~a">~a</a><sub>1</sub> = ... =
         <a href="#~a">~a</a><sub><var>n</var></sub>',
        [Id, ItemType, Id, ItemType]
Thierry Martinez's avatar
Thierry Martinez committed
589
      )
Thierry Martinez's avatar
Thierry Martinez committed
590
    ;
Thierry Martinez's avatar
Thierry Martinez committed
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
      Type = {ItemType}
    ->
      make_id(ItemType, Id),
      format(
        Doc,
        '{<a href="#~a">~a</a><sub>1</sub>, ...,
          <a href="#~a">~a</a><sub><var>n</var></sub>}',
        [Id, ItemType, Id, ItemType]
      )
    ;
      Type = [ItemType]
    ->
      make_id(ItemType, Id),
      format(
        Doc,
        '[<a href="#~a">~a</a><sub>1</sub>, ...,
          <a href="#~a">~a</a><sub><var>n</var></sub>]',
        [Id, ItemType, Id, ItemType]
      )
    ;
      camel_case(Type, CamelCaseType),
Thierry Martinez's avatar
Thierry Martinez committed
612
613
      make_id(Type, Id),
      format(atom(TypeLink), '<a href="#~a">~a</a>', [Id, Type]),
Thierry Martinez's avatar
Thierry Martinez committed
614
615
616
617
      (
        Argument = CamelCaseType
      ->
        make_id(Type, Id),
Thierry Martinez's avatar
Thierry Martinez committed
618
        write(Doc, TypeLink)
Thierry Martinez's avatar
Thierry Martinez committed
619
620
621
622
623
      ;
        atom_concat(CamelCaseType, Suffix, Argument)
      ->
        format(
          Doc,
Thierry Martinez's avatar
Thierry Martinez committed
624
625
          '~a<sub><var>~a</var></sub>',
          [TypeLink, Suffix]
Thierry Martinez's avatar
Thierry Martinez committed
626
627
        )
      ;
Thierry Martinez's avatar
Thierry Martinez committed
628
        format(Doc, '<var>~a</var>: ~a', [Argument, TypeLink])
Thierry Martinez's avatar
Thierry Martinez committed
629
      )
Thierry Martinez's avatar
Thierry Martinez committed
630
631
632
633
634
635
636
637
638
639
640
641
642
643
    )
  ;
    write_var(Doc, Argument)
  ).

write_var(Doc, Var) :-
  format(Doc, '<var>~a</var>', [Var]).


refer_argument(Argument, Doc) :-
  (
    argument_type(Argument, Type)
  ->
    (
Thierry Martinez's avatar
Thierry Martinez committed
644
645
      (
        Type = '='(ItemType)
Thierry Martinez's avatar
Thierry Martinez committed
646
647
      ;
        Type = '*'(ItemType)
Thierry Martinez's avatar
Thierry Martinez committed
648
649
650
651
652
      ;
        Type = [ItemType]
      ;
        Type = {ItemType}
      )
Thierry Martinez's avatar
Thierry Martinez committed
653
    ->
Thierry Martinez's avatar
Thierry Martinez committed
654
      make_id(ItemType, Id),
Thierry Martinez's avatar
Thierry Martinez committed
655
656
      format(
        Doc,
Thierry Martinez's avatar
Thierry Martinez committed
657
658
659
        '<a href="#~a">~a</a><sub>1</sub>, ...,
         <a href="#~a">~a</a><sub><var>n</var></sub>',
        [Id, ItemType, Id, ItemType]
Thierry Martinez's avatar
Thierry Martinez committed
660
      )
Thierry Martinez's avatar
Thierry Martinez committed
661
    ;
Thierry Martinez's avatar
Thierry Martinez committed
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
      camel_case(Type, CamelCaseType),
      (
        Argument = CamelCaseType
      ->
        make_id(Type, Id),
        format(Doc, '<a href="#~a">~a</a>', [Id, Type])
      ;
        atom_concat(CamelCaseType, Suffix, Argument)
      ->
        make_id(Type, Id),
        format(
          Doc,
          '<a href="#~a">~a</a><sub><var>~a</var></sub>',
          [Id, Type, Suffix]
        )
      ;
        format(Doc, '<var>~a</var>', [Argument])
      )
Thierry Martinez's avatar
Thierry Martinez committed
680
681
    )
  ;
Thierry Martinez's avatar
Thierry Martinez committed
682
    write_var(Doc, Argument)
Thierry Martinez's avatar
Thierry Martinez committed
683
684
685
  ).


Thierry Martinez's avatar
Thierry Martinez committed
686
write_doc_item(doc(DocBody), Stream, _Type) :-
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
687
688
  write_doc(Stream, DocBody),
  nl(Stream).
Thierry Martinez's avatar
Thierry Martinez committed
689
690


Thierry Martinez's avatar
Thierry Martinez committed
691
692
693
694
write_doc_item(devdoc(DocBody), Stream, Type) :-
  (
    Type = devdoc
  ->
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
695
696
    write_doc(Stream, DocBody),
    nl(Stream)
Thierry Martinez's avatar
Thierry Martinez committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  ;
    true
  ).

write_doc_item(biocham_silent(Command), _Stream, _Type) :-
  command(Command).

write_doc_item(biocham(Command), Stream, _Type) :-
  with_output_to(
    atom(Output),
    command(Command)
  ),
  prompt(Prompt),
  format(
    Stream,
    '</div>
<div><code>~a</code><kbd>~w.</kbd></div>
<pre>~a</pre>
<div>',
    [Prompt, Command, Output]
  ).
Thierry Martinez's avatar
Thierry Martinez committed
718
719


Thierry Martinez's avatar
Doc    
Thierry Martinez committed
720
721
722
write_doc(Stream, Atom) :-
  atom_chars(Atom, Chars),
  write_doc_chars(Chars, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
723
724
725
726


write_doc_chars([], _).

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
727
write_doc_chars(['\\', '\\' | Tail],  Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
728
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
729
730
  write(Stream, '\\'),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
731

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
732
write_doc_chars(['\\' | Tail],  Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
733
  !,
Thierry Martinez's avatar
Thierry Martinez committed
734
  parse_latex_command(Tail, Command, Argument, TailDoc),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
735
736
  write_command(Command, Argument, Stream),
  write_doc_chars(TailDoc, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
737

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
738
write_doc_chars(['-', '-', '-' | Tail], Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
739
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
740
741
  write(Stream, '&mdash;'),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
742

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
743
write_doc_chars(['-', '-' | Tail], Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
744
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
745
746
  write(Stream, '&ndash;'),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
747

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
748
write_doc_chars(['<' | Tail], Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
749
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
750
751
  write(Stream, '&lt;'),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
752

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
753
write_doc_chars(['~' | Tail], Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
754
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
755
756
  write(Stream, '&nbsp;'),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
757

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
758
759
760
write_doc_chars([Char | Tail], Stream) :-
  write(Stream, Char),
  write_doc_chars(Tail, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
761
762


Thierry Martinez's avatar
Thierry Martinez committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
parse_latex_command(Chars, Command, Argument, Tail) :-
  parse_latex_command_name(Chars, CommandChars, Tail0),
  parse_latex_command_arguments(Tail0, ArgumentChars, Tail),
  atom_chars(Command, CommandChars),
  atom_chars(Argument, ArgumentChars).


parse_latex_command_name([Head | Tail], CommandChars, Others) :-
  (
    'A' @=< Head, Head @=< 'Z'
  ;
    'a' @=< Head, Head @=< 'z'
  ),
  !,
  CommandChars = [Head | TailCommandChars],
  parse_latex_command_name(Tail, TailCommandChars, Others).

parse_latex_command_name(Tail, [], Tail).


parse_latex_command_arguments([Head | Tail], ArgumentChars, Others) :-
  (
    Head = ' '
  ;
    Head = '\n'
  ;
    Head = '\t'
  ),
  !,
  parse_latex_command_arguments(Tail, ArgumentChars, Others).

parse_latex_command_arguments(['{' | Tail], ArgumentsChars, Others) :-
  !,
  read_latex_command_arguments(Tail, ArgumentsChars, [], Others).

parse_latex_command_arguments(Tail, [], Tail).


read_latex_command_arguments(
  ['{' | Tail], ['{' | ArgumentsChars], End, Others
) :-
  !,
  read_latex_command_arguments(Tail, ArgumentsChars, ['}' | End0], Others0),
  read_latex_command_arguments(Others0, End0, End, Others).

read_latex_command_arguments(
  ['}' | Tail], ArgumentsChars, ArgumentsChars, Tail
) :-
  !.

read_latex_command_arguments(
  [Char | Tail], [Char | ArgumentsChars], End, Others
) :-
  read_latex_command_arguments(Tail, ArgumentsChars, End, Others).

read_latex_command_arguments([], _ArgumentChars, _End, _Others) :-
  throw(error(missing_closing_curly_braces)).


Thierry Martinez's avatar
Doc    
Thierry Martinez committed
822
write_command(texttt, Text, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
823
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
824
  format(Stream, '<code>~a</code>', [Text]).
Thierry Martinez's avatar
Thierry Martinez committed
825

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
826
write_command(command, Command, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
827
828
  !,
  make_id(Command, Id),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
829
  format(Stream, '<a href="#~a"><code>~a</code></a>', [Id, Command]).
Thierry Martinez's avatar
Thierry Martinez committed
830

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
831
write_command(argument, Argument, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
832
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
833
834
835
  write(Stream, '<code>'),
  refer_argument(Argument, Stream),
  write(Stream, '</code>').
Thierry Martinez's avatar
Thierry Martinez committed
836

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
837
write_command(emph, Argument, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
838
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
839
  write(Stream, '<em>'),
Thierry Martinez's avatar
Thierry Martinez committed
840
  atom_chars(Argument, ArgumentChars),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
841
842
  write_doc_chars(ArgumentChars, Stream),
  write(Stream, '</em>').
Thierry Martinez's avatar
Thierry Martinez committed
843

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
844
write_command(index, Key, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
845
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
846
  index(Stream, Key),
Thierry Martinez's avatar
Thierry Martinez committed
847
  atom_chars(Key, KeyChars),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
848
  write_doc_chars(KeyChars, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
849

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
850
write_command(begin, itemize, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
851
  !,
Thierry Martinez's avatar
Thierry Martinez committed
852
  nb_setval(opened_li, false),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
853
  write(Stream, '</div>\n<ul>\n').
Thierry Martinez's avatar
Thierry Martinez committed
854

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
855
write_command(begin, enumerate, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
856
  !,
Thierry Martinez's avatar
Thierry Martinez committed
857
  nb_setval(opened_li, false),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
858
  write(Stream, '</div>\n<ol>\n').
Thierry Martinez's avatar
Thierry Martinez committed
859

Thierry Martinez's avatar
Thierry Martinez committed
860
write_command(begin, example, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
861
  !,
Thierry Martinez's avatar
Thierry Martinez committed
862
  write(Stream, '</div><div class="example"><div><strong>Example.</strong> ').
Thierry Martinez's avatar
Thierry Martinez committed
863

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
864
write_command(item, Argument, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
865
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
866
867
  close_opened_li(Stream),
  write(Stream, '<li><div>'),
Thierry Martinez's avatar
Thierry Martinez committed
868
  atom_chars(Argument, ArgumentChars),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
869
  write_doc_chars(ArgumentChars, Stream).
Thierry Martinez's avatar
Thierry Martinez committed
870

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
871
write_command(end, itemize, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
872
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
873
874
  close_opened_li(Stream),
  write(Stream, '</ul>\n<div>').
Thierry Martinez's avatar
Thierry Martinez committed
875

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
876
write_command(end, enumerate, Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
877
  !,
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
878
879
  close_opened_li(Stream),
  write(Stream, '</ol>\n<div>').
Thierry Martinez's avatar
Thierry Martinez committed
880

Thierry Martinez's avatar
Thierry Martinez committed
881
write_command(end, example, Doc) :-
Thierry Martinez's avatar
Thierry Martinez committed
882
  !,
Thierry Martinez's avatar
Thierry Martinez committed
883
  write(Doc, '</div></div><div>').
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
884
885
886
887

write_command(section, Argument, Stream) :-
  !,
  nb_getval(current_counters, Counters),
Thierry Martinez's avatar
Thierry Martinez committed
888
  length(Counters, CounterCount),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
889
890
  SectionLevel is CounterCount + 2,
  format(Stream, '</div>\n<h~d>', [SectionLevel]),
Thierry Martinez's avatar
Thierry Martinez committed
891
  write_doc(Stream, Argument),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
892
  format(Stream, '</h~d>\n<div>', [SectionLevel]).
Thierry Martinez's avatar
Thierry Martinez committed
893

Thierry Martinez's avatar
Doc    
Thierry Martinez committed
894
write_command(Command, _Argument, _Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
895
  throw(error(unknown_command(Command))).
Thierry Martinez's avatar
Thierry Martinez committed
896
897


Thierry Martinez's avatar
Doc    
Thierry Martinez committed
898
close_opened_li(Stream) :-
Thierry Martinez's avatar
Thierry Martinez committed
899
900
901
  (
    nb_getval(opened_li, true)
  ->
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
902
    write(Stream, '</div></li>\n'),
Thierry Martinez's avatar
Thierry Martinez committed
903
904
905
906
907
    nb_setval(opened_li, false)
  ;
    true
  ).

Thierry Martinez's avatar
Thierry Martinez committed
908
909
910
:- dynamic(index_contents/2).


Thierry Martinez's avatar
Thierry Martinez committed
911
index_entry(UppercaseLetter, Key: Sections) :-
Thierry Martinez's avatar
Thierry Martinez committed
912
  index_contents(Key, Sections),
Thierry Martinez's avatar
Thierry Martinez committed
913
914
915
  atom_chars(Key, [Letter | _]),
  to_upper(Letter, UpperCode),
  atom_codes(UppercaseLetter, [UpperCode]).
Thierry Martinez's avatar
Thierry Martinez committed
916
917


Thierry Martinez's avatar
Doc    
Thierry Martinez committed
918
index(Stream, Key) :-
Thierry Martinez's avatar
Thierry Martinez committed
919
  index_new_id(Key, Id),
Thierry Martinez's avatar
Doc    
Thierry Martinez committed
920
  write(Stream, '<a id="~a" />', [Id]).
Thierry Martinez's avatar
Thierry Martinez committed
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936


index_new_id(Key, Id) :-
  nb_getval(current_counters, Counters),
  (
    retract(index_contents(Key, List))
  ->
    length(List, Count),
    SuccCount is Count + 1,
    format(atom(Name), '~a_~d', [Key, SuccCount])
  ;
    List = [],
    Name = Key
  ),
  make_id(Name, Id),
  append(List, [Counters - Id], NewList),
Thierry Martinez's avatar
Thierry Martinez committed
937
  assertz(index_contents(Key, NewList)).
Thierry Martinez's avatar
Thierry Martinez committed
938
939
940
941
942
943
944
945
946
947
948
949


index_use_id(Key, Id) :-
  nb_getval(current_counters, Counters),
  (
    retract(index_contents(Key, List))
  ->
    true
  ;
    List = []
  ),
  append(List, [Counters - Id], NewList),
Thierry Martinez's avatar
Thierry Martinez committed
950
  assertz(index_contents(Key, NewList)).