35
36:- module(pldoc_latex,
37 [ doc_latex/3, 38 latex_for_file/3, 39 latex_for_wiki_file/3, 40 latex_for_predicates/3 41 ]).
42:- use_module(library(pldoc)).
43:- use_module(library(readutil)).
44:- use_module(library(error)).
45:- use_module(library(apply)).
46:- use_module(library(option)).
47:- use_module(library(lists)).
48:- use_module(library(debug)).
49:- use_module(pldoc(doc_wiki)).
50:- use_module(pldoc(doc_process)).
51:- use_module(pldoc(doc_modes)).
52:- use_module(pldoc(doc_html), 53 [ doc_file_objects/5, 54 unquote_filespec/2,
55 doc_tag_title/2,
56 existing_linked_file/2,
57 pred_anchor_name/3,
58 private/2,
59 (multifile)/2,
60 is_pi/1,
61 is_op_type/2
62 ]).
63
84
85:- predicate_options(doc_latex/3, 3,
86 [ stand_alone(boolean),
87 public_only(boolean),
88 section_level(oneof([section,subsection,subsubsection])),
89 summary(atom)
90 ]).
91:- predicate_options(latex_for_file/3, 3,
92 [ stand_alone(boolean),
93 public_only(boolean),
94 section_level(oneof([section,subsection,subsubsection]))
95 ]).
96:- predicate_options(latex_for_predicates/3, 3,
97 [ 98 ]).
99:- predicate_options(latex_for_wiki_file/3, 3,
100 [ stand_alone(boolean),
101 public_only(boolean),
102 section_level(oneof([section,subsection,subsubsection]))
103 ]).
104
105
106:- thread_local
107 options/1,
108 documented/1.
109
110current_options(Options) :-
111 options(Current),
112 !,
113 Options = Current.
114current_options([]).
115
151
152doc_latex(Spec, OutFile, Options) :-
153 load_urldefs,
154 merge_options(Options,
155 [ include_reexported(true)
156 ],
157 Options1),
158 retractall(documented(_)),
159 setup_call_cleanup(
160 asserta(options(Options), Ref),
161 phrase(process_items(Spec, [body], Options1), Tokens),
162 erase(Ref)),
163 setup_call_cleanup(
164 open(OutFile, write, Out),
165 print_latex(Out, Tokens, Options1),
166 close(Out)),
167 latex_summary(Options).
168
169process_items([], Mode, _) -->
170 !,
171 pop_mode(body, Mode, _).
172process_items([H|T], Mode, Options) -->
173 process_items(H, Mode, Mode1, Options),
174 process_items(T, Mode1, Options).
175process_items(Spec, Mode, Options) -->
176 {Mode = [Mode0|_]},
177 process_items(Spec, Mode, Mode1, Options),
178 pop_mode(Mode0, Mode1, _).
179
180process_items(PI, Mode0, Mode, Options) -->
181 { is_pi(PI) },
182 !,
183 need_mode(description, Mode0, Mode),
184 latex_tokens_for_predicates(PI, Options).
185process_items(FileSpec, Mode0, Mode, Options) -->
186 { ( absolute_file_name(FileSpec,
187 [ file_type(prolog),
188 access(read),
189 file_errors(fail)
190 ],
191 File)
192 -> true
193 ; absolute_file_name(FileSpec,
194 [ access(read)
195 ],
196 File)
197 ),
198 file_name_extension(_Base, Ext, File)
199 },
200 need_mode(body, Mode0, Mode),
201 ( { user:prolog_file_type(Ext, prolog) }
202 -> latex_tokens_for_file(File, Options)
203 ; latex_tokens_for_wiki_file(File, Options)
204 ).
205
206
213
214latex_for_file(FileSpec, Out, Options) :-
215 load_urldefs,
216 phrase(latex_tokens_for_file(FileSpec, Options), Tokens),
217 print_latex(Out, Tokens, Options).
218
219
221
222latex_tokens_for_file(FileSpec, Options, Tokens, Tail) :-
223 absolute_file_name(FileSpec,
224 [ file_type(prolog),
225 access(read)
226 ],
227 File),
228 doc_file_objects(FileSpec, File, Objects, FileOptions, Options),
229 asserta(options(Options), Ref),
230 call_cleanup(phrase(latex([ \file_header(File, FileOptions)
231 | \objects(Objects, FileOptions)
232 ]),
233 Tokens, Tail),
234 erase(Ref)).
235
236
243
244latex_for_wiki_file(FileSpec, Out, Options) :-
245 load_urldefs,
246 phrase(latex_tokens_for_wiki_file(FileSpec, Options), Tokens),
247 print_latex(Out, Tokens, Options).
248
249latex_tokens_for_wiki_file(FileSpec, Options, Tokens, Tail) :-
250 absolute_file_name(FileSpec, File,
251 [ access(read)
252 ]),
253 read_file_to_codes(File, String, []),
254 b_setval(pldoc_file, File),
255 asserta(options(Options), Ref),
256 call_cleanup((wiki_codes_to_dom(String, [], DOM),
257 phrase(latex(DOM), Tokens, Tail)
258 ),
259 (nb_delete(pldoc_file),
260 erase(Ref))).
261
262
269
270latex_for_predicates(Spec, Out, Options) :-
271 load_urldefs,
272 phrase(latex_tokens_for_predicates(Spec, Options), Tokens),
273 print_latex(Out, [nl_exact(0)|Tokens], Options).
274
275latex_tokens_for_predicates([], _Options) --> !.
276latex_tokens_for_predicates([H|T], Options) -->
277 !,
278 latex_tokens_for_predicates(H, Options),
279 latex_tokens_for_predicates(T, Options).
280latex_tokens_for_predicates(PI, Options) -->
281 { generic_pi(PI),
282 !,
283 ( doc_comment(PI, Pos, _Summary, Comment)
284 -> true
285 ; Comment = ''
286 )
287 },
288 object(PI, Pos, Comment, [description], _, Options).
289latex_tokens_for_predicates(Spec, Options) -->
290 { findall(PI, documented_pi(Spec, PI, Options), List),
291 ( List == []
292 -> print_message(warning, pldoc(no_predicates_from(Spec)))
293 ; true
294 )
295 },
296 latex_tokens_for_predicates(List, Options).
297
298documented_pi(Spec, PI, Options) :-
299 option(modules(List), Options),
300 member(M, List),
301 generalise_spec(Spec, PI, M),
302 doc_comment(PI, _Pos, _Summary, _Comment),
303 !.
304documented_pi(Spec, PI, Options) :-
305 option(module(M), Options),
306 generalise_spec(Spec, PI, M),
307 doc_comment(PI, _Pos, _Summary, _Comment),
308 !.
309documented_pi(Spec, PI, _Options) :-
310 generalise_spec(Spec, PI, _),
311 doc_comment(PI, _Pos, _Summary, _Comment).
312
313generic_pi(Module:Name/Arity) :-
314 atom(Module), atom(Name), integer(Arity),
315 !.
316generic_pi(Module:Name//Arity) :-
317 atom(Module), atom(Name), integer(Arity).
318
319generalise_spec(Name/Arity, M:Name/Arity, M).
320generalise_spec(Name//Arity, M:Name//Arity, M).
321
322
323 326
327:- thread_local
328 fragile/0. 329
330latex([]) -->
331 !,
332 [].
333latex(Atomic) -->
334 { string(Atomic),
335 atom_string(Atom, Atomic),
336 sub_atom(Atom, 0, _, 0, 'LaTeX')
337 },
338 !,
339 [ latex('\\LaTeX{}') ].
340latex(Atomic) --> 341 { atomic(Atomic),
342 !,
343 atom_string(Atom, Atomic),
344 findall(x, sub_atom(Atom, _, _, _, '\n'), Xs),
345 length(Xs, Lines)
346 },
347 ( {Lines == 0}
348 -> [ Atomic ]
349 ; [ nl(Lines) ]
350 ).
351latex(List) -->
352 latex_special(List, Rest),
353 !,
354 latex(Rest).
355latex(w(Word)) -->
356 [ Word ].
357latex([H|T]) -->
358 !,
359 ( latex(H)
360 -> latex(T)
361 ; { print_message(error, latex(failed(H))) },
362 latex(T)
363 ).
364
366latex(h1(Attrs, Content)) -->
367 latex_section(0, Attrs, Content).
368latex(h2(Attrs, Content)) -->
369 latex_section(1, Attrs, Content).
370latex(h3(Attrs, Content)) -->
371 latex_section(2, Attrs, Content).
372latex(h4(Attrs, Content)) -->
373 latex_section(3, Attrs, Content).
374latex(p(Content)) -->
375 [ nl_exact(2) ],
376 latex(Content).
377latex(blockquote(Content)) -->
378 latex(cmd(begin(quote))),
379 latex(Content),
380 latex(cmd(end(quote))).
381latex(center(Content)) -->
382 latex(cmd(begin(center))),
383 latex(Content),
384 latex(cmd(end(center))).
385latex(a(Attrs, Content)) -->
386 { attribute(href(HREF), Attrs) },
387 ( {HREF == Content}
388 -> latex(cmd(url(no_escape(HREF))))
389 ; { atom_concat(#,Sec,HREF) }
390 -> latex([Content, ' (', cmd(secref(Sec)), ')'])
391 ; latex(cmd(href(no_escape(HREF), Content)))
392 ).
393latex(hr(_)) -->
394 latex(cmd(hrule)).
395latex(code(CodeList)) -->
396 { is_list(CodeList),
397 !,
398 atomic_list_concat(CodeList, Atom)
399 },
400 ( {fragile}
401 -> latex(cmd(const(Atom)))
402 ; [ verb(Atom) ]
403 ).
404latex(code(Code)) -->
405 { identifier(Code) },
406 !,
407 latex(cmd(const(Code))).
408latex(code(Code)) -->
409 ( {fragile}
410 -> latex(cmd(const(Code)))
411 ; [ verb(Code) ]
412 ).
413latex(b(Code)) -->
414 latex(cmd(textbf(Code))).
415latex(strong(Code)) -->
416 latex(cmd(textbf(Code))).
417latex(i(Code)) -->
418 latex(cmd(textit(Code))).
419latex(var(Var)) -->
420 latex(cmd(arg(Var))).
421latex(pre(_Class, Code)) -->
422 [ nl_exact(2), code(Code), nl_exact(2) ].
423latex(ul(Content)) -->
424 { if_short_list(Content, shortlist, itemize, Env) },
425 latex(cmd(begin(Env))),
426 latex(Content),
427 latex(cmd(end(Env))).
428latex(ol(Content)) -->
429 latex(cmd(begin(enumerate))),
430 latex(Content),
431 latex(cmd(end(enumerate))).
432latex(li(Content)) -->
433 latex(cmd(item)),
434 latex(Content).
435latex(dl(_, Content)) -->
436 latex(cmd(begin(description))),
437 latex(Content),
438 latex(cmd(end(description))).
439latex(dd(_, Content)) -->
440 latex(Content).
441latex(dd(Content)) -->
442 latex(Content).
443latex(dt(class=term, \term(Text, Term, Bindings))) -->
444 termitem(Text, Term, Bindings).
445latex(dt(Content)) -->
446 latex(cmd(item(opt(Content)))).
447latex(table(Attrs, Content)) -->
448 latex_table(Attrs, Content).
449latex(\Cmd, List, Tail) :-
450 call(Cmd, List, Tail).
451
453latex(latex(Text)) -->
454 [ latex(Text) ].
455latex(cmd(Term)) -->
456 { Term =.. [Cmd|Args] },
457 indent(Cmd),
458 [ cmd(Cmd) ],
459 latex_arguments(Args),
460 outdent(Cmd).
461
462indent(begin) --> !, [ nl(2) ].
463indent(end) --> !, [ nl_exact(1) ].
464indent(section) --> !, [ nl(2) ].
465indent(subsection) --> !, [ nl(2) ].
466indent(subsubsection) --> !, [ nl(2) ].
467indent(item) --> !, [ nl(1), indent(4) ].
468indent(definition) --> !, [ nl(1), indent(4) ].
469indent(tag) --> !, [ nl(1), indent(4) ].
470indent(termitem) --> !, [ nl(1), indent(4) ].
471indent(prefixtermitem) --> !, [ nl(1), indent(4) ].
472indent(infixtermitem) --> !, [ nl(1), indent(4) ].
473indent(postfixtermitem) --> !, [ nl(1), indent(4) ].
474indent(predicate) --> !, [ nl(1), indent(4) ].
475indent(dcg) --> !, [ nl(1), indent(4) ].
476indent(infixop) --> !, [ nl(1), indent(4) ].
477indent(prefixop) --> !, [ nl(1), indent(4) ].
478indent(postfixop) --> !, [ nl(1), indent(4) ].
479indent(predicatesummary) --> !,[ nl(1) ].
480indent(dcgsummary) --> !, [ nl(1) ].
481indent(oppredsummary) --> !, [ nl(1) ].
482indent(hline) --> !, [ nl(1) ].
483indent(_) --> [].
484
485outdent(begin) --> !, [ nl_exact(1) ].
486outdent(end) --> !, [ nl(2) ].
487outdent(item) --> !, [ ' ' ].
488outdent(tag) --> !, [ nl(1) ].
489outdent(termitem) --> !, [ nl(1) ].
490outdent(prefixtermitem) --> !, [ nl(1) ].
491outdent(infixtermitem) --> !, [ nl(1) ].
492outdent(postfixtermitem) --> !, [ nl(1) ].
493outdent(definition) --> !, [ nl(1) ].
494outdent(section) --> !, [ nl(2) ].
495outdent(subsection) --> !, [ nl(2) ].
496outdent(subsubsection) --> !, [ nl(2) ].
497outdent(predicate) --> !, [ nl(1) ].
498outdent(dcg) --> !, [ nl(1) ].
499outdent(infixop) --> !, [ nl(1) ].
500outdent(prefixop) --> !, [ nl(1) ].
501outdent(postfixop) --> !, [ nl(1) ].
502outdent(predicatesummary) --> !,[ nl(1) ].
503outdent(dcgsummary) --> !, [ nl(1) ].
504outdent(oppredsummary) --> !, [ nl(1) ].
505outdent(hline) --> !, [ nl(1) ].
506outdent(_) --> [].
507
511
512latex_special(In, Rest) -->
513 { url_chars(In, Chars, Rest),
514 special(Chars),
515 atom_chars(Atom, Chars),
516 urldef_name(Atom, Name)
517 },
518 !,
519 latex([cmd(Name), latex('{}')]).
520
521special(Chars) :-
522 memberchk(\, Chars),
523 !.
524special(Chars) :-
525 length(Chars, Len),
526 Len > 1.
527
528url_chars([H|T0], [H|T], Rest) :-
529 urlchar(H),
530 !,
531 url_chars(T0, T, Rest).
532url_chars(L, [], L).
533
534
545
546latex_arguments(List, Out, Tail) :-
547 asserta(fragile, Ref),
548 call_cleanup(fragile_list(List, Out, Tail),
549 erase(Ref)).
550
551fragile_list([]) --> [].
552fragile_list([opt([])|T]) -->
553 !,
554 fragile_list(T).
555fragile_list([opt(H)|T]) -->
556 !,
557 [ '[' ],
558 latex_arg(H),
559 [ ']' ],
560 fragile_list(T).
561fragile_list([H|T]) -->
562 [ curl(open) ],
563 latex_arg(H),
564 [ curl(close) ],
565 fragile_list(T).
566
571
572latex_arg(H) -->
573 { atomic(H),
574 atom_string(Atom, H),
575 urldef_name(Atom, Name)
576 },
577 !,
578 latex(cmd(Name)).
579latex_arg(H) -->
580 { maplist(atom, H),
581 atomic_list_concat(H, Atom),
582 urldef_name(Atom, Name)
583 },
584 !,
585 latex(cmd(Name)).
586latex_arg(no_escape(Text)) -->
587 !,
588 [no_escape(Text)].
589latex_arg(H) -->
590 latex(H).
591
592attribute(Att, Attrs) :-
593 is_list(Attrs),
594 !,
595 option(Att, Attrs).
596attribute(Att, One) :-
597 option(Att, [One]).
598
599if_short_list(Content, If, Else, Env) :-
600 ( short_list(Content)
601 -> Env = If
602 ; Env = Else
603 ).
604
609
610short_list([]).
611short_list([_,dd(Content)|T]) :-
612 !,
613 short_content(Content),
614 short_list(T).
615short_list([_,dd(_, Content)|T]) :-
616 !,
617 short_content(Content),
618 short_list(T).
619short_list([li(Content)|T]) :-
620 short_content(Content),
621 short_list(T).
622
623short_content(Content) :-
624 phrase(latex(Content), Tokens),
625 summed_string_len(Tokens, 0, Len),
626 Len < 50.
627
628summed_string_len([], Len, Len).
629summed_string_len([H|T], L0, L) :-
630 atomic(H),
631 !,
632 atom_length(H, AL),
633 L1 is L0 + AL,
634 summed_string_len(T, L1, L).
635summed_string_len([_|T], L0, L) :-
636 summed_string_len(T, L0, L).
637
638
646
647latex_section(Level, Attrs, Content) -->
648 { current_options(Options),
649 option(section_level(LaTexSection), Options, section),
650 latex_section_level(LaTexSection, BaseLevel),
651 FinalLevel is BaseLevel+Level,
652 ( latex_section_level(SectionCommand, FinalLevel)
653 -> Term =.. [SectionCommand, Content]
654 ; domain_error(latex_section_level, FinalLevel)
655 )
656 },
657 latex(cmd(Term)),
658 section_label(Attrs).
659
660section_label(Attrs) -->
661 { is_list(Attrs),
662 memberchk(id(Name), Attrs),
663 !,
664 delete_unsafe_label_chars(Name, SafeName),
665 atom_concat('sec:', SafeName, Label)
666 },
667 latex(cmd(label(Label))).
668section_label(_) -->
669 [].
670
671latex_section_level(chapter, 0).
672latex_section_level(section, 1).
673latex_section_level(subsection, 2).
674latex_section_level(subsubsection, 3).
675latex_section_level(paragraph, 4).
676
677deepen_section_level(Level0, Level1) :-
678 latex_section_level(Level0, N),
679 N1 is N + 1,
680 latex_section_level(Level1, N1).
681
687
688delete_unsafe_label_chars(LabelIn, LabelOut) :-
689 atom_chars(LabelIn, Chars),
690 delete(Chars, '_', CharsOut),
691 atom_chars(LabelOut, CharsOut).
692
693
694 697
701
702include(PI, predicate, _) -->
703 !,
704 ( { options(Options)
705 -> true
706 ; Options = []
707 },
708 latex_tokens_for_predicates(PI, Options)
709 -> []
710 ; latex(cmd(item(['[[', \predref(PI), ']]'])))
711 ).
712include(File, Type, Options) -->
713 { existing_linked_file(File, Path) },
714 !,
715 include_file(Path, Type, Options).
716include(File, _, _) -->
717 latex(code(['[[', File, ']]'])).
718
719include_file(Path, image, Options) -->
720 { option(caption(Caption), Options) },
721 !,
722 latex(cmd(begin(figure, [no_escape(htbp)]))),
723 latex(cmd(begin(center))),
724 latex(cmd(includegraphics(Path))),
725 latex(cmd(end(center))),
726 latex(cmd(caption(Caption))),
727 latex(cmd(end(figure))).
728include_file(Path, image, _) -->
729 !,
730 latex(cmd(includegraphics(Path))).
731include_file(Path, Type, _) -->
732 { assertion(memberchk(Type, [prolog,wiki])),
733 current_options(Options0),
734 select_option(stand_alone(_), Options0, Options1, _),
735 select_option(section_level(Level0), Options1, Options2, section),
736 deepen_section_level(Level0, Level),
737 Options = [stand_alone(false), section_level(Level)|Options2]
738 },
739 ( {Type == prolog}
740 -> latex_tokens_for_file(Path, Options)
741 ; latex_tokens_for_wiki_file(Path, Options)
742 ).
743
748
749file(File, _Options) -->
750 { fragile },
751 !,
752 latex(cmd(texttt(File))).
753file(File, _Options) -->
754 latex(cmd(file(File))).
755
760
761predref(Module:Name/Arity) -->
762 !,
763 latex(cmd(qpredref(Module, Name, Arity))).
764predref(Module:Name//Arity) -->
765 latex(cmd(qdcgref(Module, Name, Arity))).
766predref(Name/Arity) -->
767 latex(cmd(predref(Name, Arity))).
768predref(Name//Arity) -->
769 latex(cmd(dcgref(Name, Arity))).
770
775
776tags([\args(Params)|Rest]) -->
777 !,
778 args(Params),
779 tags_list(Rest).
780tags(List) -->
781 tags_list(List).
782
783tags_list([]) -->
784 [].
785tags_list(List) -->
786 [ nl(2) ],
787 latex(cmd(begin(tags))),
788 latex(List),
789 latex(cmd(end(tags))),
790 [ nl(2) ].
791
795
796tag(Tag, [One]) -->
797 !,
798 { doc_tag_title(Tag, Title) },
799 latex([ cmd(tag(Title))
800 | One
801 ]).
802tag(Tag, More) -->
803 { doc_tag_title(Tag, Title) },
804 latex([ cmd(mtag(Title)),
805 \tag_value_list(More)
806 ]).
807
808tag_value_list([H|T]) -->
809 latex(['- '|H]),
810 ( { T \== [] }
811 -> [latex(' \\\\')],
812 tag_value_list(T)
813 ; []
814 ).
815
820
821args(Params) -->
822 latex([ cmd(begin(arguments)),
823 \arg_list(Params),
824 cmd(end(arguments))
825 ]).
826
827arg_list([]) -->
828 [].
829arg_list([H|T]) -->
830 argument(H),
831 arg_list(T).
832
833argument(arg(Name,Descr)) -->
834 [ nl(1) ],
835 latex(cmd(arg(Name))), [ latex(' & ') ],
836 latex(Descr), [latex(' \\\\')].
837
841
(File, Options) -->
843 { memberchk(file(Title, Comment), Options),
844 !,
845 file_synopsis(File, Synopsis)
846 },
847 file_title([Synopsis, ': ', Title], File, Options),
848 { is_structured_comment(Comment, Prefixes),
849 string_codes(Comment, Codes),
850 indented_lines(Codes, Prefixes, Lines),
851 section_comment_header(Lines, _Header, Lines1),
852 wiki_lines_to_dom(Lines1, [], DOM0),
853 tags_to_front(DOM0, DOM)
854 },
855 latex(DOM),
856 latex(cmd(vspace('0.7cm'))).
857file_header(File, Options) -->
858 { file_synopsis(File, Synopsis)
859 },
860 file_title([Synopsis], File, Options).
861
862tags_to_front(DOM0, DOM) :-
863 append(Content, [\tags(Tags)], DOM0),
864 !,
865 DOM = [\tags(Tags)|Content].
866tags_to_front(DOM, DOM).
867
868file_synopsis(File, Synopsis) :-
869 file_name_on_path(File, Term),
870 unquote_filespec(Term, Unquoted),
871 format(atom(Synopsis), '~w', [Unquoted]).
872
873
877
878file_title(Title, File, Options) -->
879 { option(section_level(Level), Options, section),
880 Section =.. [Level,Title],
881 file_base_name(File, BaseExt),
882 file_name_extension(Base, _, BaseExt),
883 delete_unsafe_label_chars(Base, SafeBase),
884 atom_concat('sec:', SafeBase, Label)
885 },
886 latex(cmd(Section)),
887 latex(cmd(label(Label))).
888
889
893
894objects(Objects, Options) -->
895 objects(Objects, [body], Options).
896
897objects([], Mode, _) -->
898 pop_mode(body, Mode, _).
899objects([Obj|T], Mode, Options) -->
900 object(Obj, Mode, Mode1, Options),
901 objects(T, Mode1, Options).
902
903object(doc(Obj,Pos,Comment), Mode0, Mode, Options) -->
904 !,
905 object(Obj, Pos, Comment, Mode0, Mode, Options).
906object(Obj, Mode0, Mode, Options) -->
907 { doc_comment(Obj, Pos, _Summary, Comment)
908 },
909 !,
910 object(Obj, Pos, Comment, Mode0, Mode, Options).
911
912object(Obj, Pos, Comment, Mode0, Mode, Options) -->
913 { is_pi(Obj),
914 !,
915 is_structured_comment(Comment, Prefixes),
916 string_codes(Comment, Codes),
917 indented_lines(Codes, Prefixes, Lines),
918 strip_module(user:Obj, Module, _),
919 process_modes(Lines, Module, Pos, Modes, Args, Lines1),
920 ( private(Obj, Options)
921 -> Class = privdef % private definition
922 ; multifile(Obj, Options)
923 -> Class = multidef
924 ; Class = pubdef % public definition
925 ),
926 ( Obj = Module:_
927 -> POptions = [module(Module)|Options]
928 ; POptions = Options
929 ),
930 DOM = [\pred_dt(Modes, Class, POptions), dd(class=defbody, DOM1)],
931 wiki_lines_to_dom(Lines1, Args, DOM0),
932 strip_leading_par(DOM0, DOM1),
933 assert_documented(Obj)
934 },
935 need_mode(description, Mode0, Mode),
936 latex(DOM).
937object([Obj|Same], Pos, Comment, Mode0, Mode, Options) -->
938 !,
939 object(Obj, Pos, Comment, Mode0, Mode, Options),
940 { maplist(assert_documented, Same) }.
941object(Obj, _Pos, _Comment, Mode, Mode, _Options) -->
942 { debug(pldoc, 'Skipped ~p', [Obj]) },
943 [].
944
945assert_documented(Obj) :-
946 assert(documented(Obj)).
947
948
955
956need_mode(Mode, Stack, Stack) -->
957 { Stack = [Mode|_] },
958 !,
959 [].
960need_mode(Mode, Stack, Rest) -->
961 { memberchk(Mode, Stack)
962 },
963 !,
964 pop_mode(Mode, Stack, Rest).
965need_mode(Mode, Stack, [Mode|Stack]) -->
966 !,
967 latex(cmd(begin(Mode))).
968
969pop_mode(Mode, Stack, Stack) -->
970 { Stack = [Mode|_] },
971 !,
972 [].
973pop_mode(Mode, [H|Rest0], Rest) -->
974 latex(cmd(end(H))),
975 pop_mode(Mode, Rest0, Rest).
976
977
986
987pred_dt(Modes, Class, Options) -->
988 [nl(2)],
989 pred_dt(Modes, [], _Done, [class(Class)|Options]).
990
991pred_dt([], Done, Done, _) -->
992 [].
993pred_dt([H|T], Done0, Done, Options) -->
994 pred_mode(H, Done0, Done1, Options),
995 ( {T == []}
996 -> []
997 ; latex(cmd(nodescription)),
998 pred_dt(T, Done1, Done, Options)
999 ).
1000
1001pred_mode(mode(Head,Vars), Done0, Done, Options) -->
1002 !,
1003 { bind_vars(Head, Vars) },
1004 pred_mode(Head, Done0, Done, Options).
1005pred_mode(Head is Det, Done0, Done, Options) -->
1006 !,
1007 anchored_pred_head(Head, Done0, Done, [det(Det)|Options]).
1008pred_mode(Head, Done0, Done, Options) -->
1009 anchored_pred_head(Head, Done0, Done, Options).
1010
1011bind_vars(Term, Bindings) :-
1012 bind_vars(Bindings),
1013 anon_vars(Term).
1014
1015bind_vars([]).
1016bind_vars([Name=Var|T]) :-
1017 Var = '$VAR'(Name),
1018 bind_vars(T).
1019
1024
1025anon_vars(Var) :-
1026 var(Var),
1027 !,
1028 Var = '$VAR'('_').
1029anon_vars(Term) :-
1030 compound(Term),
1031 !,
1032 Term =.. [_|Args],
1033 maplist(anon_vars, Args).
1034anon_vars(_).
1035
1036
1037anchored_pred_head(Head, Done0, Done, Options) -->
1038 { pred_anchor_name(Head, PI, _Name) },
1039 ( { memberchk(PI, Done0) }
1040 -> { Done = Done0 }
1041 ; { Done = [PI|Done0] }
1042 ),
1043 pred_head(Head, Options).
1044
1045
1052
1053pred_head(//(Head), Options) -->
1054 !,
1055 { pred_attributes(Options, Atts),
1056 Head =.. [Functor|Args],
1057 length(Args, Arity)
1058 },
1059 latex(cmd(dcg(opt(Atts), Functor, Arity, \pred_args(Args, 1)))).
1060pred_head(Head, _Options) --> 1061 { Head =.. [Functor,Left,Right],
1062 Functor \== (:),
1063 is_op_type(Functor, infix), !
1064 },
1065 latex(cmd(infixop(Functor, \pred_arg(Left, 1), \pred_arg(Right, 2)))).
1066pred_head(Head, _Options) --> 1067 { Head =.. [Functor,Arg],
1068 is_op_type(Functor, prefix), !
1069 },
1070 latex(cmd(prefixop(Functor, \pred_arg(Arg, 1)))).
1071pred_head(Head, _Options) --> 1072 { Head =.. [Functor,Arg],
1073 is_op_type(Functor, postfix), !
1074 },
1075 latex(cmd(postfixop(Functor, \pred_arg(Arg, 1)))).
1076pred_head(M:Head, Options) --> 1077 !,
1078 { pred_attributes(Options, Atts),
1079 Head =.. [Functor|Args],
1080 length(Args, Arity)
1081 },
1082 latex(cmd(qpredicate(opt(Atts),
1083 M,
1084 Functor, Arity, \pred_args(Args, 1)))).
1085pred_head(Head, Options) --> 1086 { pred_attributes(Options, Atts),
1087 Head =.. [Functor|Args],
1088 length(Args, Arity)
1089 },
1090 latex(cmd(predicate(opt(Atts),
1091 Functor, Arity, \pred_args(Args, 1)))).
1092
1097
1098pred_attributes(Options, Attrs) :-
1099 findall(A, pred_att(Options, A), As),
1100 insert_comma(As, Attrs).
1101
1102pred_att(Options, Det) :-
1103 option(det(Det), Options).
1104pred_att(Options, private) :-
1105 option(class(privdef), Options).
1106pred_att(Options, multifile) :-
1107 option(class(multidef), Options).
1108
1109insert_comma([H1,H2|T0], [H1, ','|T]) :-
1110 !,
1111 insert_comma([H2|T0], T).
1112insert_comma(L, L).
1113
1114
1115:- if(current_predicate(is_dict/1)).
1116dict_kv_pairs([]) --> [].
1117dict_kv_pairs([H|T]) -->
1118 dict_kv(H),
1119 ( { T == [] }
1120 -> []
1121 ; latex(', '),
1122 dict_kv_pairs(T)
1123 ).
1124
1125dict_kv(Key-Value) -->
1126 latex(cmd(key(Key))),
1127 latex(':'),
1128 term(Value).
1129:- endif.
1130
1131pred_args([], _) -->
1132 [].
1133pred_args([H|T], I) -->
1134 pred_arg(H, I),
1135 ( {T==[]}
1136 -> []
1137 ; latex(', '),
1138 { I2 is I + 1 },
1139 pred_args(T, I2)
1140 ).
1141
1142pred_arg(Var, I) -->
1143 { var(Var) },
1144 !,
1145 latex(['Arg', I]).
1146pred_arg(...(Term), I) -->
1147 !,
1148 pred_arg(Term, I),
1149 latex(cmd(ldots)).
1150pred_arg(Term, I) -->
1151 { Term =.. [Ind,Arg],
1152 mode_indicator(Ind)
1153 },
1154 !,
1155 latex([Ind, \pred_arg(Arg, I)]).
1156pred_arg(Arg:Type, _) -->
1157 !,
1158 latex([\argname(Arg), :, \argtype(Type)]).
1159pred_arg(Arg, _) -->
1160 { atom(Arg) },
1161 !,
1162 argname(Arg).
1163pred_arg(Arg, _) -->
1164 argtype(Arg). 1165
1166argname('$VAR'(Name)) -->
1167 !,
1168 latex(Name).
1169argname(Name) -->
1170 !,
1171 latex(Name).
1172
1173argtype(Term) -->
1174 { format(string(S), '~W',
1175 [ Term,
1176 [ quoted(true),
1177 numbervars(true)
1178 ]
1179 ]) },
1180 latex(S).
1181
1187
1188term(_, Term, Bindings) -->
1189 { bind_vars(Bindings) },
1190 term(Term).
1191
1192term('$VAR'(Name)) -->
1193 !,
1194 latex(cmd(arg(Name))).
1195term(Compound) -->
1196 { callable(Compound),
1197 !,
1198 Compound =.. [Functor|Args]
1199 },
1200 !,
1201 term_with_args(Functor, Args).
1202term(Rest) -->
1203 latex(Rest).
1204
1205term_with_args(Functor, [Left, Right]) -->
1206 { is_op_type(Functor, infix) },
1207 !,
1208 latex(cmd(infixterm(Functor, \term(Left), \term(Right)))).
1209term_with_args(Functor, [Arg]) -->
1210 { is_op_type(Functor, prefix) },
1211 !,
1212 latex(cmd(prefixterm(Functor, \term(Arg)))).
1213term_with_args(Functor, [Arg]) -->
1214 { is_op_type(Functor, postfix) },
1215 !,
1216 latex(cmd(postfixterm(Functor, \term(Arg)))).
1217term_with_args(Functor, Args) -->
1218 latex(cmd(term(Functor, \pred_args(Args, 1)))).
1219
1220
1224
1225termitem(_Text, Term, Bindings) -->
1226 { bind_vars(Bindings) },
1227 termitem(Term).
1228
1229termitem('$VAR'(Name)) -->
1230 !,
1231 latex(cmd(termitem(var(Name), ''))).
1232:- if(current_predicate(is_dict/1)).
1233termitem(Dict) -->
1234 { is_dict(Dict),
1235 !,
1236 dict_pairs(Dict, Tag, Pairs)
1237 },
1238 latex(cmd(dictitem(Tag, \dict_kv_pairs(Pairs)))).
1239:- endif.
1240termitem(Compound) -->
1241 { callable(Compound),
1242 !,
1243 Compound =.. [Functor|Args]
1244 },
1245 !,
1246 termitem_with_args(Functor, Args).
1247termitem(Rest) -->
1248 latex(cmd(termitem(Rest, ''))).
1249
1250termitem_with_args(Functor, [Left, Right]) -->
1251 { is_op_type(Functor, infix) },
1252 !,
1253 latex(cmd(infixtermitem(Functor, \term(Left), \term(Right)))).
1254termitem_with_args(Functor, [Arg]) -->
1255 { is_op_type(Functor, prefix) },
1256 !,
1257 latex(cmd(prefixtermitem(Functor, \term(Arg)))).
1258termitem_with_args(Functor, [Arg]) -->
1259 { is_op_type(Functor, postfix) },
1260 !,
1261 latex(cmd(postfixtermitem(Functor, \term(Arg)))).
1262termitem_with_args(Functor, Args) -->
1263 latex(cmd(termitem(Functor, \pred_args(Args, 1)))).
1264
1265
1269
1270latex_table(_Attrs, Content) -->
1271 { max_columns(Content, 0, N),
1272 make_frame(N, l, List),
1273 atom_chars(Format, ['|'|List])
1274 },
1276 latex(cmd(begin(quote))),
1277 latex(cmd(begin(tabular, no_escape(Format)))),
1278 latex(cmd(hline)),
1279 rows(Content),
1280 latex(cmd(hline)),
1281 latex(cmd(end(tabular))),
1282 latex(cmd(end(quote))).
1284
1285max_columns([], C, C).
1286max_columns([tr(List)|T], C0, C) :-
1287 length(List, C1),
1288 C2 is max(C0, C1),
1289 max_columns(T, C2, C).
1290
1291make_frame(0, _, []) :- !.
1292make_frame(N, C, [C,'|'|T]) :-
1293 N2 is N - 1,
1294 make_frame(N2, C, T).
1295
1296rows([]) -->
1297 [].
1298rows([tr(Content)|T]) -->
1299 row(Content),
1300 rows(T).
1301
1302row([]) -->
1303 [ latex(' \\\\'), nl(1) ].
1304row([td(Content)|T]) -->
1305 latex(Content),
1306 ( {T == []}
1307 -> []
1308 ; [ latex(' & ') ]
1309 ),
1310 row(T).
1311
1312
1313 1316
1321
1322latex_summary(Options) :-
1323 option(summary(File), Options),
1324 !,
1325 findall(Obj, summary_obj(Obj), Objs),
1326 maplist(pi_sort_key, Objs, Keyed),
1327 keysort(Keyed, KSorted),
1328 pairs_values(KSorted, SortedObj),
1329 phrase(summarylist(SortedObj, Options), Tokens),
1330 open(File, write, Out),
1331 call_cleanup(print_latex(Out, Tokens, Options),
1332 close(Out)).
1333latex_summary(_) :-
1334 retractall(documented(_)).
1335
1336summary_obj(Obj) :-
1337 documented(Obj),
1338 pi_head(Obj, Head),
1339 \+ xref_hook(Head).
1340
1341pi_head(M:PI, M:Head) :-
1342 !,
1343 pi_head(PI, Head).
1344pi_head(Name/Arity, Head) :-
1345 functor(Head, Name, Arity).
1346pi_head(Name//DCGArity, Head) :-
1347 Arity is DCGArity+2,
1348 functor(Head, Name, Arity).
1349
1350
1351pi_sort_key(M:PI, PI-(M:PI)) :- !.
1352pi_sort_key(PI, PI-PI).
1353
1354object_name_arity(_:Term, Type, Name, Arity) :-
1355 nonvar(Term),
1356 !,
1357 object_name_arity(Term, Type, Name, Arity).
1358object_name_arity(Name/Arity, pred, Name, Arity).
1359object_name_arity(Name//Arity, dcg, Name, Arity).
1360
1361summarylist(Objs, Options) -->
1362 latex(cmd(begin(summarylist, ll))),
1363 summary(Objs, Options),
1364 latex(cmd(end(summarylist))).
1365
1366summary([], _) -->
1367 [].
1368summary([H|T], Options) -->
1369 summary_line(H, Options),
1370 summary(T, Options).
1371
1372summary_line(Obj, _Options) -->
1373 { doc_comment(Obj, _Pos, Summary, _Comment) ->
1374 atom_codes(Summary, Codes),
1375 phrase(pldoc_wiki:line_tokens(Tokens), Codes), % TBD: proper export
1376 object_name_arity(Obj, Type, Name, Arity)
1377 },
1378 ( {Type == dcg}
1379 -> latex(cmd(dcgsummary(Name, Arity, Tokens)))
1380 ; { strip_module(Obj, M, _),
1381 current_op(Pri, Ass, M:Name)
1382 }
1383 -> latex(cmd(oppredsummary(Name, Arity, Ass, Pri, Tokens)))
1384 ; latex(cmd(predicatesummary(Name, Arity, Tokens)))
1385 ).
1386
1387
1388 1391
1392print_latex(Out, Tokens, Options) :-
1393 latex_header(Out, Options),
1394 print_latex_tokens(Tokens, Out),
1395 latex_footer(Out, Options).
1396
1397
1401
1402print_latex_tokens([], _).
1403print_latex_tokens([nl(N)|T0], Out) :-
1404 !,
1405 max_nl(T0, T, N, NL),
1406 nl(Out, NL),
1407 print_latex_tokens(T, Out).
1408print_latex_tokens([nl_exact(N)|T0], Out) :-
1409 !,
1410 nl_exact(T0, T,N, NL),
1411 nl(Out, NL),
1412 print_latex_tokens(T, Out).
1413print_latex_tokens([H|T], Out) :-
1414 print_latex_token(H, Out),
1415 print_latex_tokens(T, Out).
1416
1417print_latex_token(cmd(Cmd), Out) :-
1418 !,
1419 format(Out, '\\~w', [Cmd]).
1420print_latex_token(curl(open), Out) :-
1421 !,
1422 format(Out, '{', []).
1423print_latex_token(curl(close), Out) :-
1424 !,
1425 format(Out, '}', []).
1426print_latex_token(indent(N), Out) :-
1427 !,
1428 format(Out, '~t~*|', [N]).
1429print_latex_token(nl(N), Out) :-
1430 !,
1431 format(Out, '~N', []),
1432 forall(between(2,N,_), nl(Out)).
1433print_latex_token(verb(Verb), Out) :-
1434 is_list(Verb), Verb \== [],
1435 !,
1436 atomic_list_concat(Verb, Atom),
1437 print_latex_token(verb(Atom), Out).
1438print_latex_token(verb(Verb), Out) :-
1439 !,
1440 ( member(C, [$,'|',@,=,'"',^,!]),
1441 \+ sub_atom(Verb, _, _, _, C)
1442 -> atom_replace_char(Verb, '\n', ' ', Verb2),
1443 format(Out, '\\verb~w~w~w', [C,Verb2,C])
1444 ; assertion(fail)
1445 ).
1446print_latex_token(code(Code), Out) :-
1447 !,
1448 format(Out, '~N\\begin{code}~n', []),
1449 format(Out, '~w', [Code]),
1450 format(Out, '~N\\end{code}', []).
1451print_latex_token(latex(Code), Out) :-
1452 !,
1453 write(Out, Code).
1454print_latex_token(w(Word), Out) :-
1455 !,
1456 print_latex(Out, Word).
1457print_latex_token(no_escape(Text), Out) :-
1458 !,
1459 write(Out, Text).
1460print_latex_token(Rest, Out) :-
1461 ( atomic(Rest)
1462 -> print_latex(Out, Rest)
1463 ; 1464 write(Out, Rest)
1465 ).
1466
1467atom_replace_char(In, From, To, Out) :-
1468 sub_atom(In, _, _, _, From),
1469 !,
1470 atom_chars(In, CharsIn),
1471 replace(CharsIn, From, To, CharsOut),
1472 atom_chars(Out, CharsOut).
1473atom_replace_char(In, _, _, In).
1474
1475replace([], _, _, []).
1476replace([H|T0], H, N, [N|T]) :-
1477 !,
1478 replace(T0, H, N, T).
1479replace([H|T0], F, N, [H|T]) :-
1480 replace(T0, F, N, T).
1481
1482
1486
1487print_latex(Out, String) :-
1488 atom_string(Atom, String),
1489 atom_chars(Atom, Chars),
1490 print_chars(Chars, Out).
1491
1492print_chars([], _).
1493print_chars([H|T], Out) :-
1494 print_char(H, Out),
1495 print_chars(T, Out).
1496
1497
1501
1502max_nl([nl(M1)|T0], T, M0, M) :-
1503 !,
1504 M2 is max(M1, M0),
1505 max_nl(T0, T, M2, M).
1506max_nl([nl_exact(M1)|T0], T, _, M) :-
1507 !,
1508 nl_exact(T0, T, M1, M).
1509max_nl(T, T, M, M).
1510
1511nl_exact([nl(_)|T0], T, M0, M) :-
1512 !,
1513 max_nl(T0, T, M0, M).
1514nl_exact([nl_exact(M1)|T0], T, M0, M) :-
1515 !,
1516 M2 is max(M1, M0),
1517 max_nl(T0, T, M2, M).
1518nl_exact(T, T, M, M).
1519
1520
1521nl(Out, N) :-
1522 forall(between(1, N, _), nl(Out)).
1523
1524
1525print_char('<', Out) :- !, write(Out, '$<$').
1526print_char('>', Out) :- !, write(Out, '$>$').
1527print_char('{', Out) :- !, write(Out, '\\{').
1528print_char('}', Out) :- !, write(Out, '\\}').
1529print_char('$', Out) :- !, write(Out, '\\$').
1530print_char('&', Out) :- !, write(Out, '\\&').
1531print_char('#', Out) :- !, write(Out, '\\#').
1532print_char('%', Out) :- !, write(Out, '\\%').
1533print_char('~', Out) :- !, write(Out, '\\Stilde{}').
1534print_char('\\',Out) :- !, write(Out, '\\bsl{}').
1535print_char('^', Out) :- !, write(Out, '\\Shat{}').
1536print_char('|', Out) :- !, write(Out, '\\Sbar{}').
1537print_char(C, Out) :- put_char(Out, C).
1538
1539
1543
1544identifier(Atom) :-
1545 atom_chars(Atom, [C0|Chars]),
1546 char_type(C0, lower),
1547 all_chartype(Chars, alnum).
1548
1549all_chartype([], _).
1550all_chartype([H|T], Type) :-
1551 char_type(H, Type),
1552 all_chartype(T, Type).
1553
1554
1555 1558
1566
1567:- dynamic
1568 urldef_name/2,
1569 urlchar/1, 1570 urldefs_loaded/1.
1571
1577
1578load_urldefs :-
1579 urldefs_loaded(_),
1580 !.
1581load_urldefs :-
1582 absolute_file_name(library('pldoc/pldoc.sty'), File,
1583 [ access(read) ]),
1584 load_urldefs(File).
1585
1586load_urldefs(File) :-
1587 urldefs_loaded(File),
1588 !.
1589load_urldefs(File) :-
1590 open(File, read, In),
1591 call_cleanup(( read_line_to_codes(In, L0),
1592 process_urldefs(L0, In)),
1593 close(In)),
1594 assert(urldefs_loaded(File)).
1595
1596process_urldefs(end_of_file, _) :- !.
1597process_urldefs(Line, In) :-
1598 ( phrase(urldef(Name, String), Line)
1599 -> assert(urldef_name(String, Name)),
1600 assert_chars(String)
1601 ; true
1602 ),
1603 read_line_to_codes(In, L2),
1604 process_urldefs(L2, In).
1605
1606assert_chars(String) :-
1607 atom_chars(String, Chars),
1608 ( member(C, Chars),
1609 \+ urlchar(C),
1610 assert(urlchar(C)),
1611 fail
1612 ; true
1613 ).
1614
1615urldef(Name, String) -->
1616 "\\urldef{\\", string(NameS), "}\\satom{", string(StringS), "}",
1617 ws,
1618 ( "%"
1619 -> string(_)
1620 ; []
1621 ),
1622 eol,
1623 !,
1624 { atom_codes(Name, NameS),
1625 atom_codes(String, StringS)
1626 }.
1627
1628ws --> [C], { C =< 32 }, !, ws.
1629ws --> [].
1630
1631string([]) --> [].
1632string([H|T]) --> [H], string(T).
1633
1634eol([],[]).
1635
1636
1637 1640
(Out, Options) :-
1642 ( option(stand_alone(true), Options, true)
1643 -> forall(header(Line), format(Out, '~w~n', [Line]))
1644 ; true
1645 ),
1646 forall(generated(Line), format(Out, '~w~n', [Line])).
1647
(Out, Options) :-
1649 ( option(stand_alone(true), Options, true)
1650 -> forall(footer(Line), format(Out, '~w~n', [Line]))
1651 ; true
1652 ).
1653
('\\documentclass[11pt]{article}').
1655header('\\usepackage{times}').
1656header('\\usepackage{pldoc}').
1657header('\\sloppy').
1658header('\\makeindex').
1659header('').
1660header('\\begin{document}').
1661
('').
1663footer('\\printindex').
1664footer('\\end{document}').
1665
1666generated('% This LaTeX document was generated using the LaTeX backend of PlDoc,').
1667generated('% The SWI-Prolog documentation system').
1668generated('').