37
38:- module(pldoc_html,
39 [ doc_for_file/2, 40 doc_write_html/3, 41 doc_for_wiki_file/2, 42 43 doc_page_dom/3, 44 print_html_head/1, 45 predref//1, 46 predref//2, 47 nopredref//1, 48 module_info/3, 49 doc_hide_private/3, 50 edit_button//2, 51 source_button//2, 52 zoom_button//2, 53 pred_edit_button//2, 54 object_edit_button//2, 55 object_source_button//2, 56 doc_resources//1, 57 ensure_doc_objects/1, 58 59 doc_file_objects/5, 60 existing_linked_file/2, 61 unquote_filespec/2, 62 doc_tag_title/2, 63 mode_anchor_name/2, 64 pred_anchor_name/3, 65 private/2, 66 (multifile)/2, 67 is_pi/1, 68 is_op_type/2, 69 70 file//1, 71 file//2, 72 include//3, 73 tags//1, 74 term//3, 75 file_header//2, 76 flagref//1, 77 objects//2, 78 object_ref//2, 79 object_name//2, 80 object_href/2, 81 localise_object/2, 82 object_tree//3, 83 object_page//2, 84 object_page_header//2, 85 object_synopsis//2, 86 object_footer//2, 87 object_page_footer//2, 88 cite//1 89 ]). 91:- if(exists_source(library(http/http_dispatch))). 92:- use_module(library(http/http_dispatch)). 93:- use_module(library(http/http_wrapper)). 94:- use_module(library(http/jquery)). 95:- use_module(library(apply)). 96:- use_module(library(debug)). 97:- use_module(library(error)). 98:- use_module(library(filesex)). 99:- use_module(library(lists)). 100:- use_module(library(occurs)). 101:- use_module(library(option)). 102:- use_module(library(pairs)). 103:- use_module(library(prolog_source)). 104:- use_module(library(prolog_xref)). 105:- use_module(library(readutil)). 106:- use_module(library(solution_sequences)). 107:- use_module(library(uri)). 108:- use_module(library(http/html_head)). 109:- use_module(library(http/html_write)). 110:- use_module(library(http/http_path)). 111:- use_module(library(http/term_html)). 112:- use_module(pldoc(doc_index)). 113:- use_module(pldoc(doc_man)). 114:- use_module(pldoc(doc_modes)). 115:- use_module(pldoc(doc_process)). 116:- use_module(pldoc(doc_search)). 117:- use_module(pldoc(doc_util)). 118:- use_module(pldoc(doc_wiki)). 119:- use_module(library(dcg/high_order)). 120:- use_module(library(dcg/basics)). 121
122pldoc_server(true).
123:- else. 124
125:- multifile
126 http:location/3. 127
128http:location(pldoc_resource, '/pldoc/res', []).
129
130pldoc_server(false).
131:- endif. 132
133:- use_module(library(lists)). 134:- use_module(library(option)). 135:- use_module(library(uri)). 136:- use_module(library(readutil)). 137:- use_module(library(http/html_write)). 138:- use_module(library(http/http_path)). 139:- use_module(library(http/html_head)). 140:- use_module(library(http/term_html)). 141:- use_module(library(debug)). 142:- use_module(library(apply)). 143:- use_module(library(pairs)). 144:- use_module(library(filesex)). 145:- use_module(doc_process). 146:- use_module(doc_man). 147:- use_module(doc_modes). 148:- use_module(doc_wiki). 149:- use_module(doc_search). 150:- use_module(doc_index). 151:- use_module(doc_util). 152:- use_module(library(solution_sequences)). 153:- use_module(library(error)). 154:- use_module(library(occurs)). 155:- use_module(library(prolog_source)). 156:- use_module(library(prolog_xref)). 157
158:- include(hooks).
159
160
169
170:- public
171 args//1, 172 pred_dt//3, 173 section//2,
174 tag//2. 175
176
177:- predicate_options(doc_for_wiki_file/2, 2,
178 [ edit(boolean)
179 ]). 180:- predicate_options(doc_hide_private/3, 3,
181 [module(atom), public(list), public_only(boolean)]). 182:- predicate_options(edit_button//2, 2,
183 [ edit(boolean)
184 ]). 185:- predicate_options(file//2, 2,
186 [ label(any),
187 absolute_path(atom),
188 href(atom),
189 map_extension(list),
190 files(list),
191 edit_handler(atom)
192 ]). 193:- predicate_options(file_header//2, 2,
194 [ edit(boolean),
195 files(list),
196 public_only(boolean)
197 ]). 198:- predicate_options(include//3, 3,
199 [ absolute_path(atom),
200 class(atom),
201 files(list),
202 href(atom),
203 label(any),
204 map_extension(list)
205 ]). 206:- predicate_options(object_edit_button//2, 2,
207 [ edit(boolean),
208 pass_to(pred_edit_button//2, 2)
209 ]). 210:- predicate_options(object_page//2, 2,
211 [ for(any),
212 header(boolean),
213 links(boolean),
214 no_manual(boolean),
215 try_manual(boolean),
216 search_in(oneof([all,app,man])),
217 search_match(oneof([name,summary])),
218 search_options(boolean)
219 ]). 220:- predicate_options(object_ref//2, 2,
221 [ files(list),
222 qualify(boolean),
223 style(oneof([number,title,number_title])),
224 secref_style(oneof([number,title,number_title]))
225 ]). 226:- predicate_options(object_synopsis//2, 2,
227 [ href(atom)
228 ]). 229:- predicate_options(pred_dt//3, 3,
230 [ edit(boolean)
231 ]). 232:- predicate_options(pred_edit_button//2, 2,
233 [ edit(boolean)
234 ]). 235:- predicate_options(predref//2, 2,
236 [ files(list),
237 prefer(oneof([manual,app])),
238 pass_to(object_ref/4, 2)
239 ]). 240:- predicate_options(private/2, 2,
241 [ module(atom),
242 public(list)
243 ]). 244:- predicate_options(source_button//2, 2,
245 [ files(list)
246 ]). 247
248
249 252
253:- if(pldoc_server(true)). 254:- html_resource(pldoc_css,
255 [ virtual(true),
256 requires([ pldoc_resource('pldoc.css')
257 ])
258 ]). 259:- html_resource(pldoc_resource('pldoc.js'),
260 [ requires([ jquery
261 ])
262 ]). 263:- html_resource(pldoc_js,
264 [ virtual(true),
265 requires([ pldoc_resource('pldoc.js')
266 ])
267 ]). 268:- html_resource(pldoc,
269 [ virtual(true),
270 requires([ pldoc_css,
271 pldoc_js
272 ])
273 ]). 274:- else. 275:- html_resource(pldoc_css, [virtual(true)]). 276:- html_resource(pldoc_resource('pldoc.js'), [virtual(true)]). 277:- html_resource(pldoc_js, [virtual(true)]). 278:- html_resource(pldoc, [virtual(true)]). 279:- endif. 280
281
282 285
304
305doc_for_file(FileSpec, Options) :-
306 doc_file_objects(FileSpec, File, Objects, FileOptions, Options),
307 doc_file_title(File, Title, FileOptions, Options),
308 doc_write_page(
309 pldoc(file(File, Title)),
310 title(Title),
311 \prolog_file(File, Objects, FileOptions, Options),
312 Options).
313
314doc_file_title(_, Title, _, Options) :-
315 option(title(Title), Options),
316 !.
317doc_file_title(File, Title, FileOptions, _) :-
318 memberchk(file(Title0, _Comment), FileOptions),
319 !,
320 file_base_name(File, Base),
321 atomic_list_concat([Base, ' -- ', Title0], Title).
322doc_file_title(File, Title, _, _) :-
323 file_base_name(File, Title).
324
325:- html_meta doc_write_page(+, html, html, +). 326
327doc_write_page(Style, Head, Body, Options) :-
328 option(files(_), Options),
329 !,
330 phrase(page(Style, Head, Body), HTML),
331 print_html(HTML).
332doc_write_page(Style, Head, Body, _) :-
333 reply_html_page(Style, Head, Body).
334
335
336prolog_file(File, Objects, FileOptions, Options) -->
337 { b_setval(pldoc_file, File), 338 file_directory_name(File, Dir)
339 },
340 html([ \doc_resources(Options),
341 \doc_links(Dir, FileOptions),
342 \file_header(File, FileOptions)
343 | \objects(Objects, FileOptions)
344 ]),
345 undocumented(File, Objects, FileOptions).
346
351
352doc_resources(Options) -->
353 { option(resource_directory(ResDir), Options),
354 nb_current(pldoc_output, OutputFile),
355 !,
356 directory_file_path(ResDir, 'pldoc.css', Res),
357 relative_file_name(Res, OutputFile, Ref)
358 },
359 html_requires(Ref).
360doc_resources(Options) -->
361 { option(html_resources(Resoures), Options, pldoc)
362 },
363 html_requires(Resoures).
364
365
391
392doc_file_objects(FileSpec, File, Objects, FileOptions, Options) :-
393 xref_current_source(FileSpec),
394 xref_option(FileSpec, comments(collect)),
395 !,
396 File = FileSpec,
397 findall(Object, xref_doc_object(File, Object), Objects0),
398 reply_file_objects(File, Objects0, Objects, FileOptions, Options).
399doc_file_objects(FileSpec, File, Objects, FileOptions, Options) :-
400 absolute_file_name(FileSpec, File,
401 [ file_type(prolog),
402 access(read)
403 ]),
404 source_file(File),
405 !,
406 ensure_doc_objects(File),
407 Pos = File:Line,
408 findall(Line-doc(Obj,Pos,Comment),
409 doc_comment(Obj, Pos, _, Comment), Pairs),
410 sort(Pairs, Pairs1), 411 keysort(Pairs1, ByLine),
412 pairs_values(ByLine, Objs0),
413 reply_file_objects(File, Objs0, Objects, FileOptions, Options).
414doc_file_objects(FileSpec, File, Objects, FileOptions, Options) :-
415 absolute_file_name(FileSpec, File,
416 [ file_type(prolog),
417 access(read)
418 ]),
419 xref_source(File, [silent(true)]),
420 findall(Object, xref_doc_object(File, Object), Objects0),
421 reply_file_objects(File, Objects0, Objects, FileOptions, Options).
422
423
424reply_file_objects(File, Objs0, Objects, FileOptions, Options) :-
425 module_info(File, ModuleOptions, Options),
426 file_info(Objs0, Objs1, FileOptions, ModuleOptions),
427 doc_hide_private(Objs1, ObjectsSelf, ModuleOptions),
428 include_reexported(ObjectsSelf, Objects1, File, FileOptions),
429 remove_doc_duplicates(Objects1, Objects, []).
430
431remove_doc_duplicates([], [], _).
432remove_doc_duplicates([H|T0], [H|T], Seen) :-
433 H = doc(_, _, Comment),
434 \+ memberchk(Comment, Seen),
435 !,
436 remove_doc_duplicates(T0, T, [Comment|Seen]).
437remove_doc_duplicates([_|T0], T, Seen) :-
438 remove_doc_duplicates(T0, T, Seen).
439
440include_reexported(SelfObjects, Objects, File, Options) :-
441 option(include_reexported(true), Options),
442 option(module(Module), Options),
443 option(public(Exports), Options),
444 select_undocumented(Exports, Module, SelfObjects, Undoc),
445 re_exported_doc(Undoc, File, Module, REObjs, _),
446 REObjs \== [],
447 !,
448 append(SelfObjects, REObjs, Objects).
449include_reexported(Objects, Objects, _, _).
450
451
453
454xref_doc_object(File, doc(M:module(Title),File:0,Comment)) :-
455 xref_comment(File, Title, Comment),
456 xref_module(File, M).
457xref_doc_object(File, doc(M:Name/Arity,File:0,Comment)) :-
458 xref_comment(File, Head, _Summary, Comment),
459 xref_module(File, Module),
460 strip_module(Module:Head, M, Plain),
461 functor(Plain, Name, Arity).
462xref_doc_object(File, doc(M:Object,File:0,Comment)) :-
463 xref_object_comment(File, Object, _Summary, Comment),
464 ( xref_module(File, M)
465 -> true
466 ; M = user
467 ).
468
477
478:- dynamic
479 no_comments/2. 480
481ensure_doc_objects(File) :-
482 source_file(File),
483 !,
484 ( doc_file_has_comments(File)
485 -> true
486 ; no_comments(File, TimeChecked),
487 time_file(File, TimeChecked)
488 -> true
489 ; xref_source(File, [silent(true), comments(store)]),
490 retractall(no_comments(File, _)),
491 ( doc_file_has_comments(File)
492 -> true
493 ; time_file(File, TimeChecked),
494 assertz(no_comments(File, TimeChecked))
495 )
496 ).
497ensure_doc_objects(File) :-
498 xref_source(File, [silent(true)]).
499
504
505module_info(File, [module(Module), public(Exports)|Options], Options) :-
506 module_property(Module, file(File)),
507 !,
508 module_property(Module, exports(Exports)).
509module_info(File, [module(Module), public(Exports)|Options], Options) :-
510 xref_module(File, Module),
511 !,
512 findall(PI, xref_exported_pi(File, PI), Exports).
513module_info(_, Options, Options).
514
515xref_exported_pi(Src, Name/Arity) :-
516 xref_exported(Src, Head),
517 functor(Head, Name, Arity).
518
522
523doc_hide_private(Objs, Objs, Options) :-
524 option(public_only(false), Options, true),
525 !.
526doc_hide_private(Objs0, Objs, Options) :-
527 hide_private(Objs0, Objs, Options).
528
529hide_private([], [], _).
530hide_private([H|T0], T, Options) :-
531 obj(H, Obj),
532 private(Obj, Options),
533 !,
534 hide_private(T0, T, Options).
535hide_private([H|T0], [H|T], Options) :-
536 hide_private(T0, T, Options).
537
543
544obj(doc(Obj0, _Pos, _Summary), Obj) :-
545 !,
546 ( Obj0 = [Obj|_]
547 -> true
548 ; Obj = Obj0
549 ).
550obj(Obj0, Obj) :-
551 ( Obj0 = [Obj|_]
552 -> true
553 ; Obj = Obj0
554 ).
555
556
562
563:- multifile
564 prolog:doc_is_public_object/1. 565
566private(Object, _Options) :-
567 prolog:doc_is_public_object(Object), !, fail.
568private(Module:PI, Options) :-
569 multifile(Module:PI, Options), !, fail.
570private(Module:PI, Options) :-
571 public(Module:PI, Options), !, fail.
572private(Module:PI, Options) :-
573 option(module(Module), Options),
574 option(public(Public), Options),
575 !,
576 \+ ( member(PI2, Public),
577 eq_pi(PI, PI2)
578 ).
579private(Module:PI, _Options) :-
580 module_property(Module, file(_)), 581 !,
582 module_property(Module, exports(Exports)),
583 \+ ( member(PI2, Exports),
584 eq_pi(PI, PI2)
585 ).
586private(Module:PI, _Options) :-
587 \+ (pi_to_head(PI, Head),
588 xref_exported(Source, Head),
589 xref_module(Source, Module)).
590
595
599
600multifile(Obj, _Options) :-
601 strip_module(user:Obj, Module, PI),
602 pi_to_head(PI, Head),
603 ( predicate_property(Module:Head, multifile)
604 ; xref_module(Source, Module),
605 xref_defined(Source, Head, multifile(_Line))
606 ),
607 !.
608
612
613public(Obj, _Options) :-
614 strip_module(user:Obj, Module, PI),
615 pi_to_head(PI, Head),
616 ( predicate_property(Module:Head, public)
617 ; xref_module(Source, Module),
618 xref_defined(Source, Head, public(_Line))
619 ),
620 !.
621
622pi_to_head(Var, _) :-
623 var(Var), !, fail.
624pi_to_head(Name/Arity, Term) :-
625 functor(Term, Name, Arity).
626pi_to_head(Name//DCGArity, Term) :-
627 Arity is DCGArity+2,
628 functor(Term, Name, Arity).
629
633
634file_info(Comments, RestComments, [file(Title, Comment)|Opts], Opts) :-
635 select(doc(_:module(Title),_,Comment), Comments, RestComments),
636 !.
637file_info(Comments, Comments, Opts, Opts).
638
639
643
(File, Options) -->
645 { memberchk(file(Title, Comment), Options),
646 !,
647 file_base_name(File, Base)
648 },
649 file_title([Base, ' -- ', Title], File, Options),
650 { is_structured_comment(Comment, Prefixes),
651 string_codes(Comment, Codes),
652 indented_lines(Codes, Prefixes, Lines),
653 section_comment_header(Lines, _Header, Lines1),
654 wiki_lines_to_dom(Lines1, [], DOM)
655 },
656 html(DOM).
657file_header(File, Options) -->
658 { file_base_name(File, Base)
659 },
660 file_title([Base], File, Options).
661
662
666
667file_title(Title, File, Options) -->
668 prolog:doc_file_title(Title, File, Options),
669 !.
670file_title(Title, File, Options) -->
671 { file_base_name(File, Base)
672 },
673 html(h1(class(file),
674 [ span(style('float:right'),
675 [ \reload_button(File, Base, Options),
676 \zoom_button(Base, Options),
677 \source_button(Base, Options),
678 \edit_button(File, Options)
679 ])
680 | Title
681 ])).
682
683
690
691reload_button(File, _Base, Options) -->
692 { \+ source_file(File),
693 \+ option(files(_), Options)
694 },
695 !,
696 html(span(class(file_anot), '[not loaded]')).
697reload_button(_File, Base, Options) -->
698 { option(edit(true), Options),
699 !,
700 option(public_only(Public), Options, true)
701 },
702 html(a(href(Base+[reload(true), public_only(Public)]),
703 img([ class(action),
704 alt('Reload'),
705 title('Make & Reload'),
706 src(location_by_id(pldoc_resource)+'reload.png')
707 ]))).
708reload_button(_, _, _) --> [].
709
715
716edit_button(File, Options) -->
717 { option(edit(true), Options)
718 },
719 !,
720 html(a([ onClick('HTTPrequest(\'' +
721 location_by_id(pldoc_edit) + [file(File)] +
722 '\')')
723 ],
724 img([ class(action),
725 alt(edit),
726 title('Edit file'),
727 src(location_by_id(pldoc_resource)+'edit.png')
728 ]))).
729edit_button(_, _) -->
730 [].
731
732
736
737zoom_button(_, Options) -->
738 { option(files(_Map), Options) },
739 !. 740zoom_button(Base, Options) -->
741 { ( option(public_only(true), Options, true)
742 -> Zoom = 'public.png',
743 Alt = 'Public',
744 Title = 'Click to include private',
745 PublicOnly = false
746 ; Zoom = 'private.png',
747 Alt = 'All predicates',
748 Title = 'Click to show exports only',
749 PublicOnly = true
750 )
751 },
752 html(a(href(Base+[public_only(PublicOnly)]),
753 img([ class(action),
754 alt(Alt),
755 title(Title),
756 src(location_by_id(pldoc_resource)+Zoom)
757 ]))).
758
759
763
764source_button(_File, Options) -->
765 { option(files(_Map), Options) },
766 !. 767source_button(File, _Options) -->
768 { ( is_absolute_file_name(File)
769 -> doc_file_href(File, HREF0)
770 ; HREF0 = File
771 )
772 },
773 html(a(href(HREF0+[show(src)]),
774 img([ class(action),
775 alt('Show source'),
776 title('Show source'),
777 src(location_by_id(pldoc_resource)+'source.png')
778 ]))).
779
780
787
788objects(Objects, Options) -->
789 { option(navtree(true), Options),
790 !,
791 objects_nav_tree(Objects, Tree)
792 },
793 html([ div(class(navtree),
794 div(class(navwindow),
795 \nav_tree(Tree, Objects, Options))),
796 div(class(navcontent),
797 \objects_nt(Objects, Options))
798 ]).
799objects(Objects, Options) -->
800 objects_nt(Objects, Options).
801
802objects_nt(Objects, Options) -->
803 objects(Objects, [body], Options).
804
805objects([], Mode, _) -->
806 pop_mode(body, Mode, _).
807objects([Obj|T], Mode, Options) -->
808 object(Obj, Mode, Mode1, Options),
809 objects(T, Mode1, Options).
810
819
820object(doc(Obj,Pos,Comment), Mode0, Mode, Options) -->
821 !,
822 object(Obj, [Pos-Comment], Mode0, Mode, [scope(file)|Options]).
823object(Obj, Mode0, Mode, Options) -->
824 { findall(Pos-Comment,
825 doc_comment(Obj, Pos, _Summary, Comment),
826 Pairs)
827 },
828 !,
829 { b_setval(pldoc_object, Obj) },
830 object(Obj, Pairs, Mode0, Mode, Options).
831
832object(Obj, Pairs, Mode0, Mode, Options) -->
833 { is_pi(Obj),
834 !,
835 maplist(pred_dom(Obj, Options), Pairs, DOMS),
836 append(DOMS, DOM)
837 },
838 need_mode(dl, Mode0, Mode),
839 html(DOM).
840object([Obj|_Same], Pairs, Mode0, Mode, Options) -->
841 !,
842 object(Obj, Pairs, Mode0, Mode, Options).
843object(Obj, Pairs, Mode0, Mode, Options) -->
844 { phrase(prolog:doc_object(Obj, Pairs, Options), Tokens) },
845 !,
846 need_mode(body, Mode0, Mode),
847 tokens(Tokens).
848object(Obj, _Pairs, Mode, Mode, _Options) -->
849 { debug(pldoc, 'Skipped ~p', [Obj]) },
850 [].
851
858
860
861tokens(Tokens, List, Tail) :-
862 append(Tokens, Tail, List).
863
864pred_dom(Obj, Options, Pos-Comment, DOM) :-
865 is_structured_comment(Comment, Prefixes),
866 string_codes(Comment, Codes),
867 indented_lines(Codes, Prefixes, Lines),
868 strip_module(user:Obj, Module, _),
869 process_modes(Lines, Module, Pos, Modes, Args, Lines1),
870 ( private(Obj, Options)
871 -> Class = privdef 872 ; multifile(Obj, Options)
873 -> ( option(scope(file), Options)
874 -> ( more_doc(Obj, Pos)
875 -> Class = multidef(object(Obj))
876 ; Class = multidef
877 )
878 ; Class = multidef(file((Pos)))
879 )
880 ; public(Obj, Options)
881 -> Class = publicdef 882 ; Class = pubdef 883 ),
884 ( Obj = Module:_
885 -> POptions = [module(Module)|Options]
886 ; POptions = Options
887 ),
888 Pos = File:Line,
889 DTOptions = [file(File),line(Line)|POptions],
890 DOM = [\pred_dt(Modes, Class, DTOptions), dd(class=defbody, DOM1)],
891 wiki_lines_to_dom(Lines1, Args, DOM0),
892 strip_leading_par(DOM0, DOM1).
893
894more_doc(Obj, File:_) :-
895 doc_comment(Obj, File2:_, _, _),
896 File2 \== File,
897 !.
898
905
906need_mode(Mode, Stack, Stack) -->
907 { Stack = [Mode|_] },
908 !,
909 [].
910need_mode(Mode, Stack, Rest) -->
911 { memberchk(Mode, Stack)
912 },
913 !,
914 pop_mode(Mode, Stack, Rest).
915need_mode(Mode, Stack, [Mode|Stack]) -->
916 !,
917 html_begin(Mode).
918
919pop_mode(Mode, Stack, Stack) -->
920 { Stack = [Mode|_] },
921 !,
922 [].
923pop_mode(Mode, [H|Rest0], Rest) -->
924 html_end(H),
925 pop_mode(Mode, Rest0, Rest).
926
930
931undocumented(File, Objs, Options) -->
932 { option(module(Module), Options),
933 option(public(Exports), Options),
934 select_undocumented(Exports, Module, Objs, Undoc),
935 re_exported_doc(Undoc, File, Module, UREObjs, ReallyUnDoc),
936 sort(2, @=<, UREObjs, REObjs) 937 938 },
939 !,
940 re_exported_doc(REObjs, Options),
941 undocumented(ReallyUnDoc, Options).
942undocumented(_, _, _) -->
943 [].
944
945re_exported_doc([], _) --> !.
946re_exported_doc(Objs, Options) -->
947 reexport_header(Objs, Options),
948 objects(Objs, Options).
949
(_, Options) -->
951 { option(reexport_header(true), Options, true)
952 },
953 !,
954 html([ h2(class(wiki), 'Re-exported predicates'),
955 p([ "The following predicates are exported from this file \c
956 while their implementation is defined in imported modules \c
957 or non-module files loaded by this module."
958 ])
959 ]).
960reexport_header(_, _) -->
961 [].
962
963undocumented([], _) --> !.
964undocumented(UnDoc, Options) -->
965 html([ h2(class(undoc), 'Undocumented predicates'),
966 p(['The following predicates are exported, but not ',
967 'or incorrectly documented.'
968 ]),
969 dl(class(undoc),
970 \undocumented_predicates(UnDoc, Options))
971 ]).
972
973
974undocumented_predicates([], _) -->
975 [].
976undocumented_predicates([H|T], Options) -->
977 undocumented_pred(H, Options),
978 undocumented_predicates(T, Options).
979
980undocumented_pred(Name/Arity, Options) -->
981 { functor(Head, Name, Arity) },
982 html(dt(class=undoc, \pred_mode(Head, [], _, Options))).
983
984select_undocumented([], _, _, []).
985select_undocumented([PI|T0], M, Objs, [PI|T]) :-
986 is_pi(PI),
987 \+ in_doc(M:PI, Objs),
988 !,
989 select_undocumented(T0, M, Objs, T).
990select_undocumented([_|T0], M, Objs, T) :-
991 select_undocumented(T0, M, Objs, T).
992
993in_doc(PI, Objs) :-
994 member(doc(O,_,_), Objs),
995 ( is_list(O)
996 -> member(O2, O),
997 eq_pi(PI, O2)
998 ; eq_pi(PI, O)
999 ).
1000
1001
1005
1006eq_pi(PI, PI) :- !.
1007eq_pi(M:PI1, M:PI2) :-
1008 atom(M),
1009 !,
1010 eq_pi(PI1, PI2).
1011eq_pi(Name/A, Name//DCGA) :-
1012 A =:= DCGA+2,
1013 !.
1014eq_pi(Name//DCGA, Name/A) :-
1015 A =:= DCGA+2.
1016
1020
1021is_pi(Var) :-
1022 var(Var),
1023 !,
1024 fail.
1025is_pi(_:PI) :-
1026 !,
1027 is_pi(PI).
1028is_pi(_/_).
1029is_pi(_//_).
1030
1031
1034
1035re_exported_doc([], _, _, [], []).
1036re_exported_doc([PI|T0], File, Module, [doc(Orig:PI,Pos,Comment)|ObjT], UnDoc) :-
1037 pi_to_head(PI, Head),
1038 ( predicate_property(Module:Head, imported_from(Orig))
1039 -> true
1040 ; predicate_property(Module:Head, exported)
1041 -> Orig = Module
1042 ; xref_defined(File, Head, imported(File2)),
1043 ensure_doc_objects(File2),
1044 xref_module(File2, Orig)
1045 ),
1046 doc_comment(Orig:PI, Pos, _, Comment),
1047 !,
1048 re_exported_doc(T0, File, Module, ObjT, UnDoc).
1049re_exported_doc([PI|T0], File, Module, REObj, [PI|UnDoc]) :-
1050 re_exported_doc(T0, File, Module, REObj, UnDoc).
1051
1052
1053 1056
1064
1065object_page(Obj, Options) -->
1066 prolog:doc_object_page(Obj, Options),
1067 !,
1068 object_page_footer(Obj, Options).
1069object_page(Obj, Options) -->
1070 { doc_comment(Obj, File:_Line, _Summary, _Comment)
1071 },
1072 !,
1073 ( { \+ ( doc_comment(Obj, File2:_, _, _),
1074 File2 \== File )
1075 }
1076 -> html([ \html_requires(pldoc),
1077 \object_page_header(File, Options),
1078 \object_synopsis(Obj, []),
1079 \objects([Obj], Options)
1080 ])
1081 ; html([ \html_requires(pldoc),
1082 \object_page_header(-, Options),
1083 \objects([Obj], [synopsis(true)|Options])
1084 ])
1085 ),
1086 object_page_footer(Obj, Options).
1087object_page(M:Name/Arity, Options) --> 1088 { functor(Head, Name, Arity),
1089 ( predicate_property(M:Head, exported)
1090 -> module_property(M, class(library))
1091 ; \+ predicate_property(M:Head, defined)
1092 )
1093 },
1094 prolog:doc_object_page(Name/Arity, Options),
1095 !,
1096 object_page_footer(Name/Arity, Options).
1097
(File, Options) -->
1099 prolog:doc_page_header(file(File), Options),
1100 !.
1101object_page_header(File, Options) -->
1102 { option(header(true), Options, true) },
1103 !,
1104 html(div(class(navhdr),
1105 [ div(class(jump), \file_link(File)),
1106 div(class(search), \search_form(Options)),
1107 br(clear(right))
1108 ])).
1109object_page_header(_, _) --> [].
1110
1111file_link(-) -->
1112 !,
1113 places_menu(-).
1114file_link(File) -->
1115 { file_directory_name(File, Dir)
1116 },
1117 places_menu(Dir),
1118 html([ div(a(href(location_by_id(pldoc_doc)+File), File))
1119 ]).
1120
1128
(Obj, Options) -->
1130 object_changelog(Obj, Options),
1131 ( prolog:doc_object_footer(Obj, Options)
1132 -> []
1133 ; []
1134 ).
1135
1144
1145:- if(exists_source(library(pldoc/doc_changes))). 1146:- use_module(library(pldoc/doc_changes),
1147 [doc_introduced/3, doc_last_changed/4]). 1148
1149object_changelog(Objs, Options) -->
1150 { is_list(Objs), !,
1151 objs_pis(Objs, PIs)
1152 },
1153 object_changelog_pis(PIs, Options).
1154object_changelog(Obj, Options) -->
1155 { objs_pis([Obj], PIs)
1156 },
1157 object_changelog_pis(PIs, Options).
1158
1159object_changelog_pis(PIs, _Options) -->
1160 { changelog_union(PIs, Events),
1161 Events \== []
1162 },
1163 !,
1164 html(div(class('pldoc-changes'),
1165 [ div(class('pldoc-changes-header'), "History"),
1166 ul(\changelog_events(Events)),
1167 div(class('pldoc-changes-footer'),
1168 "Disclaimer: heuristically mined from GIT")
1169 ])).
1170object_changelog_pis(_, _) --> [].
1171
1180
1181objs_pis(Objs, PIs) :-
1182 convlist(obj_pi, Objs, PIs).
1183
1184obj_pi(_:O, PI) :- !, obj_pi(O, PI).
1185obj_pi(Name/Arity, Name/Arity) :- atom(Name), integer(Arity).
1186obj_pi(Name//Arity, Name/PArity) :-
1187 atom(Name), integer(Arity),
1188 PArity is Arity + 2.
1189
1190changelog_events(Events) -->
1191 sequence(changelog_event, Events).
1192
1193changelog_event(Event) -->
1194 html(li(\changelog_event_(Event))).
1195
1196changelog_event_(event(Type, Version, Hash, Subject, Repo)) -->
1197 { clean_subject(Subject, Subject1)
1198 },
1199 html([ \event_type(Type), " in ",
1200 \version_commit_link(Version, Hash, Repo),
1201 " ", em(Subject1)
1202 ]).
1203
1204clean_subject(Subject0, Subject) :-
1205 string_codes(Subject0, Codes),
1206 phrase((tag, string(Msg)), Codes),
1207 !,
1208 string_codes(Subject, Msg).
1209clean_subject(Subject, Subject).
1210
1211tag -->
1212 capitals, ":", whites.
1213
1214capitals -->
1215 [C], { between(0'A, 0'Z, C) }, !,
1216 capitals.
1217capitals -->
1218 [].
1219
1220event_type(introduced) ==> html(b(title("The predicate was added"),
1221 "Introduced")).
1222event_type(added) ==> html(b(title("New functinality was added"),
1223 "Extended")).
1224event_type(enhanced) ==> html(b(title("Implementation has been improved"),
1225 "Enhanced")).
1226event_type(fixed) ==> html(b(title("A bug was fixed"),
1227 "Fixed")).
1228event_type(modified) ==> html(b(title("The modification may break compatibility"),
1229 "Modified")).
1230event_type(Id) ==> html(b(title("Unknow tag"),
1231 Id)).
1232
1240
1241changelog_union(PIs, [Event]) :-
1242 all_introduced(PIs, Event).
1243changelog_union(PIs, Events) :-
1244 union_last_changed(PIs, Events).
1245
1253
1254all_introduced(PIs, Event) :-
1255 maplist(any_introduction, PIs, Events),
1256 E0 = event(introduced, V0, _, _, _),
1257 aggregate_all(max(V0, E0),
1258 member(E0, Events),
1259 max(_, Event)).
1260
1261any_introduction(PI, Event) :-
1262 doc_introduced(PI, _, Event), !.
1263
1268
1269union_last_changed(PIs, Events) :-
1270 Ev = event(T0, V0, _H0, _S0, _R0),
1271 findall(Ev,
1272 ( member(PI, PIs),
1273 doc_last_changed(PI, V0, T0, Ev)
1274 ),
1275 Events0),
1276 sort(2, >=, Events0, Events).
1277
1278version_commit_link(V, Hash, Repo) -->
1279 { version_string(V, VStr),
1280 short_hash(Hash, Short),
1281 commit_url(Repo, Hash, URL)
1282 },
1283 html([ b(VStr), ' (👉',
1284 a([href(URL), target('_blank')], Short),
1285 ')'
1286 ]).
1287
1288version_string(N, VStr) :-
1289 Major is N // 10000,
1290 Minor is (N // 100) mod 100,
1291 Patch is N mod 100,
1292 format(string(VStr), "~d.~d.~d", [Major, Minor, Patch]).
1293
1294short_hash(Hash, Short) :-
1295 string(Hash),
1296 !,
1297 sub_string(Hash, 0, 7, _, Short).
1298short_hash(Hash, Short) :-
1299 sub_atom(Hash, 0, 7, _, Short),
1300 !.
1301short_hash(Hash, Hash).
1302
1303commit_url(Repo, Hash, URL) :-
1304 atom(Repo), Repo \== unknown,
1305 !,
1306 format(atom(URL), "https://github.com/~w/commit/~w", [Repo, Hash]).
1307commit_url(_, Hash, URL) :-
1308 format(atom(URL), "#~w", [Hash]).
1309:- else. 1310object_changelog(_, _) --> [].
1311:- endif. 1312
1313
1318
(Obj, Options) -->
1320 prolog:doc_object_page_footer(Obj, Options),
1321 !.
1322object_page_footer(_, _) --> [].
1323
1324
1335
1336object_synopsis(Name/Arity, _) -->
1337 { functor(Head, Name, Arity),
1338 predicate_property(system:Head, built_in)
1339 },
1340 synopsis([span(class(builtin), 'built-in')]).
1341object_synopsis(Name/Arity, Options) -->
1342 !,
1343 object_synopsis(_:Name/Arity, Options).
1344object_synopsis(M:Name/Arity, Options) -->
1345 { functor(Head, Name, Arity),
1346 ( option(source(Spec), Options)
1347 -> absolute_file_name(Spec, File,
1348 [ access(read),
1349 file_type(prolog),
1350 file_errors(fail)
1351 ])
1352 ; predicate_property(M:Head, exported),
1353 \+ predicate_property(M:Head, imported_from(_)),
1354 module_property(M, file(File)),
1355 file_name_on_path(File, Spec)
1356 ),
1357 !,
1358 unquote_filespec(Spec, Unquoted0),
1359 ( prolog:pldoc_synopsis_spec(Unquoted0, Unquoted)
1360 -> true
1361 ; Unquoted = Unquoted0
1362 )
1363 },
1364 use_module_synopsis(Head, File, Unquoted, Options).
1365object_synopsis(Name//Arity, Options) -->
1366 !,
1367 { DCGArity is Arity+2 },
1368 object_synopsis(Name/DCGArity, Options).
1369object_synopsis(Module:Name//Arity, Options) -->
1370 !,
1371 { DCGArity is Arity+2 },
1372 object_synopsis(Module:Name/DCGArity, Options).
1373object_synopsis(f(_/_), _) -->
1374 synopsis(span(class(function),
1375 [ 'Arithmetic function (see ',
1376 \object_ref(is/2, []),
1377 ')'
1378 ])).
1379object_synopsis(c(Func), _) -->
1380 { sub_atom(Func, 0, _, _, 'PL_')
1381 ; sub_atom(Func, 0, _, _, 'S')
1382 },
1383 !,
1384 synopsis([span(class(cfunc), 'C-language interface function')]).
1385object_synopsis(_, _) --> [].
1386
1387:- html_meta(synopsis(html,?,?)). 1388
1389use_module_synopsis(Head, File, Unquoted, Options) -->
1390 { Args = [class(copy), title('Click to copy')] },
1391 ( { option(href(HREF), Options) }
1392 -> synopsis([ code(Args, [':- use_module(',a(href(HREF), '~q'-[Unquoted]),').'])
1393 | \can_autoload(Head, File)
1394 ])
1395 ; synopsis([ code(Args, ':- use_module(~q).'-[Unquoted])
1396 | \can_autoload(Head, File)
1397 ])
1398 ).
1399
1400synopsis(HTML) -->
1401 html(div(class(synopsis),
1402 [ span(class('synopsis-hdr'), 'Availability:')
1403 | HTML
1404 ])).
1405
1406can_autoload(Head, File) -->
1407 { predicate_property(Head, autoload(FileBase)),
1408 file_name_extension(FileBase, _Ext, File)
1409 },
1410 !,
1411 html(span(class(autoload), \can_be_autoloaded)).
1412can_autoload(_, _) -->
1413 [].
1414
1415can_be_autoloaded -->
1416 { catch(http_link_to_id(pldoc_man, [section(autoload)], HREF),
1417 error(_,_), fail)
1418 },
1419 html(['(can be ', a(href(HREF), autoloaded), ')']).
1420can_be_autoloaded -->
1421 html('(can be autoloaded)').
1422
1423
1428
1429unquote_filespec(Spec, Unquoted) :-
1430 compound(Spec),
1431 Spec =.. [Alias,Path],
1432 atom(Path),
1433 atomic_list_concat(Parts, /, Path),
1434 maplist(need_no_quotes, Parts),
1435 !,
1436 parts_to_path(Parts, UnquotedPath),
1437 Unquoted =.. [Alias, UnquotedPath].
1438unquote_filespec(Spec, Spec).
1439
1440need_no_quotes(Atom) :-
1441 format(atom(A), '~q', [Atom]),
1442 \+ sub_atom(A, 0, _, _, '\'').
1443
1444parts_to_path([One], One) :- !.
1445parts_to_path(List, More/T) :-
1446 ( append(H, [T], List)
1447 -> parts_to_path(H, More)
1448 ).
1449
1450
1451 1454
1458
1459doc_write_html(Out, Title, Doc) :-
1460 doc_page_dom(Title, Doc, DOM),
1461 phrase(html(DOM), Tokens),
1462 print_html_head(Out),
1463 print_html(Out, Tokens).
1464
1469
1470doc_page_dom(Title, Body, DOM) :-
1471 DOM = html([ head([ title(Title),
1472 link([ rel(stylesheet),
1473 type('text/css'),
1474 href(location_by_id(pldoc_resource)+'pldoc.css')
1475 ]),
1476 script([ src(location_by_id(pldoc_resource)+'pldoc.js'),
1477 type('text/javascript')
1478 ], [])
1479 ]),
1480 body(Body)
1481 ]).
1482
1486
1487print_html_head(Out) :-
1488 format(Out,
1489 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" \c
1490 "http://www.w3.org/TR/html4/strict.dtd">~n', []).
1491
1495
1501
1502tags(Tags) -->
1503 html(dl(class=tags, Tags)).
1504
1508
1509tag(Tag, Values) -->
1510 { doc_tag_title(Tag, Title),
1511 atom_concat('keyword-', Tag, Class)
1512 },
1513 html([ dt(class=Class, Title),
1514 \tag_values(Values, Class)
1515 ]).
1516
1517tag_values([], _) -->
1518 [].
1519tag_values([H|T], Class) -->
1520 html(dd(class=Class, ['- '|H])),
1521 tag_values(T, Class).
1522
1523
1527
1528doc_tag_title(Tag, Title) :-
1529 tag_title(Tag, Title),
1530 !.
1531doc_tag_title(Tag, Tag).
1532
1533tag_title(compat, 'Compatibility').
1534tag_title(tbd, 'To be done').
1535tag_title(see, 'See also').
1536tag_title(error, 'Errors').
1537tag_title(since, 'Since').
1538
1543
1544args(Params) -->
1545 html([ dt(class=tag, 'Arguments:'),
1546 dd(table(class=arglist,
1547 \arg_list(Params)))
1548 ]).
1549
1550arg_list([]) -->
1551 [].
1552arg_list([H|T]) -->
1553 argument(H),
1554 arg_list(T).
1555
1556argument(arg(Name,Descr)) -->
1557 html(tr([td(var(Name)), td(class=argdescr, ['- '|Descr])])).
1558
1559
1560 1563
1568
1569objects_nav_tree(Objects, Tree) :-
1570 maplist(object_nav_tree, Objects, Trees),
1571 union_trees(Trees, Tree0),
1572 remove_unique_root(Tree0, Tree).
1573
1574object_nav_tree(Obj, Tree) :-
1575 Node = node(directory(Dir), FileNodes),
1576 FileNode = node(file(File), Siblings),
1577 doc_comment(Obj, File:_Line, _Summary, _Comment),
1578 !,
1579 file_directory_name(File, Dir),
1580 sibling_file_nodes(Dir, FileNodes0),
1581 selectchk(node(file(File),[]), FileNodes0, FileNode, FileNodes),
1582 findall(Sibling, doc_comment(Sibling, File:_, _, _), Siblings0),
1583 delete(Siblings0, _:module(_), Siblings1),
1584 doc_hide_private(Siblings1, Siblings2, []),
1585 flatten(Siblings2, Siblings), 1586 embed_directories(Node, Tree).
1587
1588sibling_file_nodes(Dir, Nodes) :-
1589 findall(node(file(File), []),
1590 ( source_file(File),
1591 file_directory_name(File, Dir)
1592 ),
1593 Nodes).
1594
1595embed_directories(Node, Tree) :-
1596 Node = node(file(File), _),
1597 !,
1598 file_directory_name(File, Dir),
1599 Super = node(directory(Dir), [Node]),
1600 embed_directories(Super, Tree).
1601embed_directories(Node, Tree) :-
1602 Node = node(directory(Dir), _),
1603 file_directory_name(Dir, SuperDir),
1604 SuperDir \== Dir,
1605 !,
1606 Super = node(directory(SuperDir), [Node]),
1607 embed_directories(Super, Tree).
1608embed_directories(Tree, Tree).
1609
1610
1611union_trees([Tree], Tree) :- !.
1612union_trees([T1,T2|Trees], Tree) :-
1613 merge_trees(T1, T2, M1),
1614 union_trees([M1|Trees], Tree).
1615
1616merge_trees(node(R, Ch1), node(R, Ch2), node(R, Ch)) :-
1617 merge_nodes(Ch1, Ch2, Ch).
1618
1619merge_nodes([], Ch, Ch) :- !.
1620merge_nodes(Ch, [], Ch) :- !.
1621merge_nodes([node(Root, Ch1)|T1], N1, [T1|Nodes]) :-
1622 selectchk(node(Root, Ch2), N1, N2),
1623 !,
1624 merge_trees(node(Root, Ch1), node(Root, Ch2), T1),
1625 merge_nodes(T1, N2, Nodes).
1626merge_nodes([Node|T1], N1, [Node|Nodes]) :-
1627 merge_nodes(T1, N1, Nodes).
1628
1632
1633remove_unique_root(node(_, [node(R1, [R2])]), Tree) :-
1634 !,
1635 remove_unique_root(node(R1, [R2]), Tree).
1636remove_unique_root(Tree, Tree).
1637
1641
1642nav_tree(Tree, Current, Options) -->
1643 html(ul(class(nav),
1644 \object_tree(Tree, Current, Options))).
1645
1649
1650object_tree(node(Id, []), Target, Options) -->
1651 !,
1652 { node_class(Id, Target, Class) },
1653 html(li(class(Class),
1654 \node(Id, Options))).
1655object_tree(node(Id, Children), Target, Options) -->
1656 !,
1657 { node_class(Id, Target, Class) },
1658 html(li(class(Class),
1659 [ \node(Id, Options),
1660 ul(class(nav),
1661 \object_trees(Children, Target, Options))
1662 ])).
1663object_tree(Id, Target, Options) -->
1664 !,
1665 { node_class(Id, Target, Class) },
1666 html(li(class([obj|Class]), \node(Id, Options))).
1667
1668object_trees([], _, _) --> [].
1669object_trees([H|T], Target, Options) -->
1670 object_tree(H, Target, Options),
1671 object_trees(T, Target, Options).
1672
1673node_class(Ids, Current, Class) :-
1674 is_list(Ids),
1675 !,
1676 ( member(Id, Ids), memberchk(Id, Current)
1677 -> Class = [nav,current]
1678 ; Class = [nav]
1679 ).
1680node_class(Id, Current, Class) :-
1681 ( memberchk(Id, Current)
1682 -> Class = [nav,current]
1683 ; Class = [nav]
1684 ).
1685
1686node(file(File), Options) -->
1687 !,
1688 object_ref(file(File), [style(title)|Options]).
1689node(Id, Options) -->
1690 object_ref(Id, Options).
1691
1692
1693 1696
1697section(Type, Title) -->
1698 { string_codes(Title, Codes),
1699 wiki_codes_to_dom(Codes, [], Content0),
1700 strip_leading_par(Content0, Content),
1701 make_section(Type, Content, HTML)
1702 },
1703 html(HTML).
1704
1705make_section(module, Title, h1(class=module, Title)).
1706make_section(section, Title, h1(class=section, Title)).
1707
1708
1709 1712
1718
1719pred_dt(Modes, Class, Options) -->
1720 pred_dt(Modes, Class, [], _Done, Options).
1721
1722pred_dt([], _, Done, Done, _) -->
1723 [].
1724pred_dt([H|T], Class, Done0, Done, Options) -->
1725 { functor(Class, CSSClass, _) },
1726 html(dt(class=CSSClass,
1727 [ \pred_mode(H, Done0, Done1, Options),
1728 \mode_anot(Class)
1729 ])),
1730 pred_dt(T, Class, Done1, Done, Options).
1731
1732mode_anot(privdef) -->
1733 !,
1734 html(span([class(anot), style('float:right')],
1735 '[private]')).
1736mode_anot(multidef(object(Obj))) -->
1737 !,
1738 { object_href(Obj, HREF) },
1739 html(span([class(anot), style('float:right')],
1740 ['[', a(href(HREF), multifile), ']'
1741 ])).
1742mode_anot(multidef(file(File:_))) -->
1743 !,
1744 { file_name_on_path(File, Spec),
1745 unquote_filespec(Spec, Unquoted),
1746 doc_file_href(File, HREF)
1747 },
1748 html(span([class(anot), style('float:right')],
1749 ['[multifile, ', a(href(HREF), '~q'-[Unquoted]), ']'
1750 ])).
1751mode_anot(multidef) -->
1752 !,
1753 html(span([class(anot), style('float:right')],
1754 '[multifile]')).
1755mode_anot(_) -->
1756 [].
1757
1758pred_mode(mode(Head,Vars), Done0, Done, Options) -->
1759 !,
1760 { bind_vars(Head, Vars) },
1761 pred_mode(Head, Done0, Done, Options).
1762pred_mode(Head is Det, Done0, Done, Options) -->
1763 !,
1764 anchored_pred_head(Head, Done0, Done, Options),
1765 pred_det(Det).
1766pred_mode(Head, Done0, Done, Options) -->
1767 anchored_pred_head(Head, Done0, Done, Options).
1768
1769bind_vars(Term, Bindings) :-
1770 bind_vars(Bindings),
1771 anon_vars(Term).
1772
1773bind_vars([]).
1774bind_vars([Name=Var|T]) :-
1775 Var = '$VAR'(Name),
1776 bind_vars(T).
1777
1782
1783anon_vars(Var) :-
1784 var(Var),
1785 !,
1786 Var = '$VAR'('_').
1787anon_vars(Term) :-
1788 compound(Term),
1789 !,
1790 Term =.. [_|Args],
1791 maplist(anon_vars, Args).
1792anon_vars(_).
1793
1794
1795anchored_pred_head(Head, Done0, Done, Options) -->
1796 { pred_anchor_name(Head, PI, Name) },
1797 ( { memberchk(PI, Done0) }
1798 -> { Done = Done0 },
1799 pred_head(Head)
1800 ; html([ span(style('float:right'),
1801 [ \pred_edit_or_source_button(Head, Options),
1802 &(nbsp)
1803 ]),
1804 a(name=Name, \pred_head(Head))
1805 ]),
1806 { Done = [PI|Done0] }
1807 ).
1808
1809
1810pred_edit_or_source_button(Head, Options) -->
1811 { option(edit(true), Options) },
1812 !,
1813 pred_edit_button(Head, Options).
1814pred_edit_or_source_button(Head, Options) -->
1815 { option(source_link(true), Options) },
1816 !,
1817 pred_source_button(Head, Options).
1818pred_edit_or_source_button(_, _) --> [].
1819
1831
1832pred_edit_button(_, Options) -->
1833 { \+ option(edit(true), Options) },
1834 !.
1835pred_edit_button(PI0, Options0) -->
1836 { canonicalise_predref(PI0, PI, Options0, Options) },
1837 pred_edit_button2(PI, Options).
1838
1839pred_edit_button2(Name/Arity, Options) -->
1840 { \+ ( memberchk(file(_), Options), 1841 memberchk(line(_), Options) 1842 ),
1843 functor(Head, Name, Arity),
1844 option(module(M), Options, _),
1845 \+ ( current_module(M),
1846 source_file(M:Head, _File)
1847 )
1848 },
1849 !.
1850pred_edit_button2(Name/Arity, Options) -->
1851 { include(edit_param, Options, Extra),
1852 http_link_to_id(pldoc_edit,
1853 [name(Name),arity(Arity)|Extra],
1854 EditHREF)
1855 },
1856 html(a(onClick('HTTPrequest(\'' + EditHREF + '\')'),
1857 img([ class(action),
1858 alt('Edit predicate'),
1859 title('Edit predicate'),
1860 src(location_by_id(pldoc_resource)+'editpred.png')
1861 ]))).
1862pred_edit_button2(_, _) -->
1863 !,
1864 [].
1865
1866edit_param(module(_)).
1867edit_param(file(_)).
1868edit_param(line(_)).
1869
1870
1874
1875object_edit_button(_, Options) -->
1876 { \+ option(edit(true), Options) },
1877 !.
1878object_edit_button(PI, Options) -->
1879 { is_pi(PI) },
1880 !,
1881 pred_edit_button(PI, Options).
1882object_edit_button(_, _) -->
1883 [].
1884
1885
1889
1890pred_source_button(PI0, Options0) -->
1891 { canonicalise_predref(PI0, PI, Options0, Options),
1892 option(module(M), Options, _),
1893 pred_source_href(PI, M, HREF), !
1894 },
1895 html(a([ href(HREF),
1896 class(source)
1897 ],
1898 img([ class(action),
1899 alt('Source'),
1900 title('Show source'),
1901 src(location_by_id(pldoc_resource)+'source.png')
1902 ]))).
1903pred_source_button(_, _) -->
1904 [].
1905
1906
1910
1911object_source_button(PI, Options) -->
1912 { is_pi(PI),
1913 option(source_link(true), Options, true)
1914 },
1915 !,
1916 pred_source_button(PI, Options).
1917object_source_button(_, _) -->
1918 [].
1919
1920
1925
1926canonicalise_predref(M:PI0, PI, Options0, [module(M)|Options]) :-
1927 !,
1928 canonicalise_predref(PI0, PI, Options0, Options).
1929canonicalise_predref(//(Head), PI, Options0, Options) :-
1930 !,
1931 functor(Head, Name, Arity),
1932 PredArity is Arity + 2,
1933 canonicalise_predref(Name/PredArity, PI, Options0, Options).
1934canonicalise_predref(Name//Arity, PI, Options0, Options) :-
1935 integer(Arity), Arity >= 0,
1936 !,
1937 PredArity is Arity + 2,
1938 canonicalise_predref(Name/PredArity, PI, Options0, Options).
1939canonicalise_predref(PI, PI, Options, Options) :-
1940 PI = Name/Arity,
1941 atom(Name), integer(Arity), Arity >= 0,
1942 !.
1943canonicalise_predref(Head, PI, Options0, Options) :-
1944 functor(Head, Name, Arity),
1945 canonicalise_predref(Name/Arity, PI, Options0, Options).
1946
1947
1952
1953pred_head(Var) -->
1954 { var(Var),
1955 !,
1956 instantiation_error(Var)
1957 }.
1958pred_head(//(Head)) -->
1959 !,
1960 pred_head(Head),
1961 html(//).
1962pred_head(M:Head) -->
1963 html([span(class=module, M), :]),
1964 pred_head(Head).
1965pred_head(Head) -->
1966 { atom(Head) },
1967 !,
1968 html(b(class=pred, Head)).
1969pred_head(Head) --> 1970 { Head =.. [Functor,Left,Right],
1971 is_op_type(Functor, infix)
1972 },
1973 !,
1974 html([ var(class=arglist, \pred_arg(Left, 1)),
1975 ' ', b(class=pred, Functor), ' ',
1976 var(class=arglist, \pred_arg(Right, 2))
1977 ]).
1978pred_head(Head) --> 1979 { Head =.. [Functor,Arg],
1980 is_op_type(Functor, prefix)
1981 },
1982 !,
1983 html([ b(class=pred, Functor), ' ',
1984 var(class=arglist, \pred_arg(Arg, 1))
1985 ]).
1986pred_head(Head) --> 1987 { Head =.. [Functor,Arg],
1988 is_op_type(Functor, postfix)
1989 },
1990 !,
1991 html([ var(class=arglist, \pred_arg(Arg, 1)),
1992 ' ', b(class=pred, Functor)
1993 ]).
1994pred_head({Head}) -->
1995 !,
1996 html([ b(class=pred, '{'),
1997 var(class=arglist,
1998 \pred_args([Head], 1)),
1999 b(class=pred, '}')
2000 ]).
2001pred_head(Head) --> 2002 { Head =.. [Functor|Args] },
2003 html([ b(class=pred, Functor),
2004 var(class=arglist,
2005 [ '(', \pred_args(Args, 1), ')' ])
2006 ]).
2007
2012
2013is_op_type(Functor, Type) :-
2014 current_op(_Pri, F, Functor),
2015 op_type(F, Type).
2016
2017op_type(fx, prefix).
2018op_type(fy, prefix).
2019op_type(xf, postfix).
2020op_type(yf, postfix).
2021op_type(xfx, infix).
2022op_type(xfy, infix).
2023op_type(yfx, infix).
2024op_type(yfy, infix).
2025
2026
2027pred_args([], _) -->
2028 [].
2029pred_args([H|T], I) -->
2030 pred_arg(H, I),
2031 ( {T==[]}
2032 -> []
2033 ; html(', '),
2034 { I2 is I + 1 },
2035 pred_args(T, I2)
2036 ).
2037
2038pred_arg(Var, I) -->
2039 { var(Var) },
2040 !,
2041 html(['Arg', I]).
2042pred_arg(...(Term), I) -->
2043 !,
2044 pred_arg(Term, I),
2045 html('...').
2046pred_arg(Term, I) -->
2047 { Term =.. [Ind,Arg],
2048 mode_indicator(Ind)
2049 },
2050 !,
2051 html([Ind, \pred_arg(Arg, I)]).
2052pred_arg(Arg:Type, _) -->
2053 !,
2054 html([\argname(Arg), :, \argtype(Type)]).
2055pred_arg(Arg, _) -->
2056 argname(Arg).
2057
2058argname('$VAR'(Name)) -->
2059 !,
2060 html(Name).
2061argname(Name) -->
2062 !,
2063 html(Name).
2064
2065argtype(Term) -->
2066 { format(string(S), '~W',
2067 [ Term,
2068 [ quoted(true),
2069 numbervars(true)
2070 ]
2071 ]) },
2072 html(S).
2073
2074pred_det(unknown) -->
2075 [].
2076pred_det(Det) -->
2077 html([' is ', b(class=det, Det)]).
2078
2079
2085
2086term(_, Atom, []) -->
2087 { atomic(Atom),
2088 !,
2089 format(string(S), '~W', [Atom,[quoted(true)]])
2090 },
2091 html(span(class=functor, S)).
2092term(_, Key:Type, [TypeName=Type]) -->
2093 { atomic(Key)
2094 },
2095 !,
2096 html([span(class='pl-key', Key), :, span(class('pl-var'), TypeName)]).
2097term(_, Term, Bindings) -->
2098 { is_mode(Term is det), 2099 bind_vars(Bindings)
2100 },
2101 !,
2102 pred_head(Term).
2103term(_, Term, Bindings) -->
2104 term(Term,
2105 [ variable_names(Bindings),
2106 quoued(true)
2107 ]).
2108
2109
2110 2113
2124
2125predref(Term) -->
2126 { catch(nb_getval(pldoc_options, Options), _, Options = []) },
2127 predref(Term, Options).
2128
2129predref(Obj, Options) -->
2130 { Obj = _:_,
2131 doc_comment(Obj, File:_Line, _, _),
2132 ( ( option(files(Map), Options)
2133 -> memberchk(file(File,_), Map)
2134 ; true
2135 )
2136 -> object_href(Obj, HREF, Options)
2137 ; manref(Obj, HREF, Options)
2138 )
2139 },
2140 !,
2141 html(a(href(HREF), \object_name(Obj, [qualify(true)|Options]))).
2142predref(M:Term, Options) -->
2143 !,
2144 predref(Term, M, Options).
2145predref(Term, Options) -->
2146 predref(Term, _, Options).
2147
2148predref(Name/Arity, _, Options) --> 2149 { prolog:doc_object_summary(Name/Arity, manual, _, _),
2150 !,
2151 manref(Name/Arity, HREF, Options)
2152 },
2153 html(a([class=builtin, href=HREF], [Name, /, Arity])).
2154predref(Name/Arity, _, Options) --> 2155 { option(prefer(manual), Options),
2156 prolog:doc_object_summary(Name/Arity, Category, _, _),
2157 !,
2158 manref(Name/Arity, HREF, Options)
2159 },
2160 html(a([class=Category, href=HREF], [Name, /, Arity])).
2161predref(Obj, Module, Options) --> 2162 { doc_comment(Module:Obj, File:_Line, _, _),
2163 ( option(files(Map), Options)
2164 -> memberchk(file(File,_), Map)
2165 ; true
2166 )
2167 },
2168 !,
2169 object_ref(Module:Obj, Options).
2170predref(Name/Arity, Module, Options) -->
2171 { \+ option(files(_), Options),
2172 pred_href(Name/Arity, Module, HREF)
2173 },
2174 !,
2175 html(a(href=HREF, [Name, /, Arity])).
2176predref(Name//Arity, Module, Options) -->
2177 { \+ option(files(_), Options),
2178 PredArity is Arity + 2,
2179 pred_href(Name/PredArity, Module, HREF)
2180 },
2181 !,
2182 html(a(href=HREF, [Name, //, Arity])).
2183predref(PI, _, Options) --> 2184 { canonical_pi(PI, CPI, HTML),
2185 ( option(files(_), Options)
2186 -> Category = extmanual
2187 ; prolog:doc_object_summary(CPI, Category, _, _)
2188 ),
2189 manref(CPI, HREF, Options)
2190 },
2191 html(a([class=Category, href=HREF], HTML)).
2192predref(PI, _, _Options) -->
2193 { canonical_pi(PI, _CPI, HTML)
2194 },
2195 !,
2196 html(span(class=undef, HTML)).
2197predref(Callable, Module, Options) -->
2198 { callable(Callable),
2199 functor(Callable, Name, Arity)
2200 },
2201 predref(Name/Arity, Module, Options).
2202
2203canonical_pi(Name/Arity, Name/Arity, [Name, /, Arity]) :-
2204 atom(Name), integer(Arity),
2205 !.
2206canonical_pi(Name//Arity, Name/Arity2, [Name, //, Arity]) :-
2207 atom(Name), integer(Arity),
2208 !,
2209 Arity2 is Arity+2.
2210
2214
2215nopredref(PI) -->
2216 { canonical_pi(PI, _CPI, HTML)
2217 },
2218 !,
2219 html(span(class=nopredref, HTML)).
2220
2226
2227flagref(Flag) -->
2228 html(code(Flag)).
2229
2234
2235cite(Citations) -->
2236 html('['), citations(Citations), html(']').
2237
2238citations([]) --> [].
2239citations([H|T]) -->
2240 citation(H),
2241 ( {T==[]}
2242 -> []
2243 ; [';'],
2244 citations(T)
2245 ).
2246
2247citation(H) -->
2248 html([@,H]).
2249
2250
2255
2256manref(PI, HREF, Options) :-
2257 predname(PI, PredName),
2258 ( option(files(_Map), Options)
2259 -> option(man_server(Server), Options,
2260 'http://www.swi-prolog.org/pldoc'),
2261 uri_components(Server, Comp0),
2262 uri_data(path, Comp0, Path0),
2263 directory_file_path(Path0, man, Path),
2264 uri_data(path, Comp0, Path, Components),
2265 uri_query_components(Query, [predicate=PredName]),
2266 uri_data(search, Components, Query),
2267 uri_components(HREF, Components)
2268 ; http_link_to_id(pldoc_man, [predicate=PredName], HREF)
2269 ).
2270
2271predname(Name/Arity, PredName) :-
2272 !,
2273 format(atom(PredName), '~w/~d', [Name, Arity]).
2274predname(Module:Name/Arity, PredName) :-
2275 !,
2276 format(atom(PredName), '~w:~w/~d', [Module, Name, Arity]).
2277
2278
2289
2290pred_href(Name/Arity, Module, HREF) :-
2291 format(string(FragmentId), '~w/~d', [Name, Arity]),
2292 uri_data(fragment, Components, FragmentId),
2293 functor(Head, Name, Arity),
2294 ( catch(relative_file(Module:Head, File), _, fail)
2295 -> uri_data(path, Components, File),
2296 uri_components(HREF, Components)
2297 ; in_file(Module:Head, File)
2298 -> ( current_prolog_flag(home, SWI),
2299 sub_atom(File, 0, _, _, SWI),
2300 prolog:doc_object_summary(Name/Arity, packages, _, _)
2301 -> http_link_to_id(pldoc_man, [predicate=FragmentId], HREF)
2302 ; http_location_by_id(pldoc_doc, DocHandler),
2303 atom_concat(DocHandler, File, Path),
2304 uri_data(path, Components, Path),
2305 uri_components(HREF, Components)
2306 )
2307 ).
2308
2309relative_file(Head, '') :-
2310 b_getval(pldoc_file, CurrentFile), CurrentFile \== [],
2311 in_file(Head, CurrentFile),
2312 !.
2313relative_file(Head, RelFile) :-
2314 b_getval(pldoc_file, CurrentFile), CurrentFile \== [],
2315 in_file(Head, DefFile),
2316 relative_file_name(DefFile, CurrentFile, RelFile).
2317
2321
2322pred_source_href(Name/Arity, Module, HREF) :-
2323 format(string(FragmentId), '~w/~d', [Name, Arity]),
2324 uri_data(fragment, Components, FragmentId),
2325 uri_query_components(Query, [show=src]),
2326 uri_data(search, Components, Query),
2327 functor(Head, Name, Arity),
2328 ( catch(relative_file(Module:Head, File), _, fail)
2329 -> uri_data(path, Components, File),
2330 uri_components(HREF, Components)
2331 ; in_file(Module:Head, File0)
2332 -> insert_alias(File0, File),
2333 http_location_by_id(pldoc_doc, DocHandler),
2334 atom_concat(DocHandler, File, Path),
2335 uri_data(path, Components, Path),
2336 uri_components(HREF, Components)
2337 ).
2338
2339
2345
2346object_ref([], _) -->
2347 !,
2348 [].
2349object_ref([H|T], Options) -->
2350 !,
2351 object_ref(H, Options),
2352 ( {T == []}
2353 -> html(', '),
2354 object_ref(T, Options)
2355 ; []
2356 ).
2357object_ref(Obj, Options) -->
2358 { object_href(Obj, HREF, Options)
2359 },
2360 html(a(href(HREF), \object_name(Obj, Options))).
2361
2366
2367object_href(Obj, HREF) :-
2368 object_href(Obj, HREF, []).
2369
2370object_href(M:PI0, HREF, Options) :-
2371 option(files(Map), Options),
2372 ( module_property(M, file(File))
2373 -> true
2374 ; xref_module(File, M)
2375 ),
2376 memberchk(file(File, DocFile), Map),
2377 !,
2378 file_base_name(DocFile, LocalFile), 2379 expand_pi(PI0, PI),
2380 term_to_string(PI, PIS),
2381 uri_data(path, Components, LocalFile),
2382 uri_data(fragment, Components, PIS),
2383 uri_components(HREF, Components).
2384object_href(file(File), HREF, _Options) :-
2385 doc_file_href(File, HREF),
2386 !.
2387object_href(directory(Dir), HREF, _Options) :-
2388 directory_file_path(Dir, 'index.html', Index),
2389 doc_file_href(Index, HREF),
2390 !.
2391object_href(Obj, HREF, _Options) :-
2392 prolog:doc_object_href(Obj, HREF),
2393 !.
2394object_href(Obj0, HREF, _Options) :-
2395 localise_object(Obj0, Obj),
2396 term_to_string(Obj, String),
2397 http_link_to_id(pldoc_object, [object=String], HREF).
2398
2399expand_pi(Name//Arity0, Name/Arity) :-
2400 !,
2401 Arity is Arity0+2.
2402expand_pi(PI, PI).
2403
2404
2409
2410localise_object(Obj0, Obj) :-
2411 prolog:doc_canonical_object(Obj0, Obj),
2412 !.
2413localise_object(Obj, Obj).
2414
2415
2420
2421term_to_string(Term, String) :-
2422 State = state(-),
2423 ( numbervars(Term, 0, _, [singletons(true)]),
2424 with_output_to(string(String),
2425 write_term(Term,
2426 [ numbervars(true),
2427 quoted(true)
2428 ])),
2429 nb_setarg(1, State, String),
2430 fail
2431 ; arg(1, State, String)
2432 ).
2433
2445
2446object_name(Obj, Options) -->
2447 { option(style(Style), Options, inline)
2448 },
2449 object_name(Style, Obj, Options).
2450
2451object_name(title, Obj, Options) -->
2452 { merge_options(Options, [secref_style(title)], Options1) },
2453 prolog:doc_object_link(Obj, Options1),
2454 !.
2455object_name(inline, Obj, Options) -->
2456 prolog:doc_object_link(Obj, Options),
2457 !.
2458object_name(title, f(Name/Arity), _Options) -->
2459 !,
2460 html(['Function ', Name, /, Arity]).
2461object_name(inline, f(Name/Arity), _Options) -->
2462 !,
2463 html([Name, /, Arity]).
2464object_name(Style, PI, Options) -->
2465 { is_pi(PI) },
2466 !,
2467 pi(Style, PI, Options).
2468object_name(inline, Module:module(_Title), _) -->
2469 !,
2470 { module_property(Module, file(File)),
2471 file_base_name(File, Base)
2472 },
2473 !,
2474 html(Base).
2475object_name(title, Module:module(Title), _) -->
2476 { module_property(Module, file(File)),
2477 file_base_name(File, Base)
2478 },
2479 !,
2480 html([Base, ' -- ', Title]).
2481object_name(title, file(File), _) -->
2482 { module_property(Module, file(File)),
2483 doc_comment(Module:module(Title), _, _, _),
2484 !,
2485 file_base_name(File, Base)
2486 },
2487 html([Base, ' -- ', Title]).
2488object_name(_, file(File), _) -->
2489 { file_base_name(File, Base) },
2490 html(Base).
2491object_name(_, directory(Dir), _) -->
2492 { file_base_name(Dir, Base) },
2493 html(Base).
2494object_name(_, module(Title), _Options) -->
2495 { print_message(warning,
2496 pldoc(module_comment_outside_module(Title)))
2497 }.
2498
2499pi(title, PI, Options) -->
2500 pi_type(PI),
2501 pi(PI, Options).
2502pi(inline, PI, Options) -->
2503 pi(PI, Options).
2504
2505pi(M:PI, Options) -->
2506 !,
2507 ( { option(qualify(true), Options) }
2508 -> html([span(class(module), M), :])
2509 ; []
2510 ),
2511 pi(PI, Options).
2512pi(Name/Arity, _) -->
2513 !,
2514 html([Name, /, \arity(Arity)]).
2515pi(Name//Arity, _) -->
2516 html([Name, //, \arity(Arity)]).
2517
2518arity(Arity) -->
2519 { var(Arity) },
2520 !,
2521 html('_').
2522arity(Arity) -->
2523 html(Arity).
2524
2525pi_type(_:PI) -->
2526 !,
2527 pi_type(PI).
2528pi_type(_/_) -->
2529 html(['Predicate ']).
2530pi_type(_//_) -->
2531 html(['Grammar rule ']).
2532
2533
2534
2542
2543in_file(Module:Head, File) :-
2544 !,
2545 distinct(File, in_file(Module, Head, File)).
2546in_file(Head, File) :-
2547 distinct(File, in_file(_, Head, File)).
2548
2549in_file(Module, Head, File) :-
2550 var(Module),
2551 ( predicate_property(system:Head, foreign)
2552 -> !,
2553 fail
2554 ; predicate_property(system:Head, file(File)),
2555 \+ system_arithmetic_function(Head)
2556 -> !
2557 ; predicate_property(Head, autoload(File0))
2558 -> !,
2559 file_name_extension(File0, pl, File)
2560 ; exported_from(Module, Head, File),
2561 module_property(Module, class(library))
2562 ).
2563in_file(Module, Head, File) :-
2564 nonvar(Module),
2565 predicate_property(Module:Head, file(File)),
2566 \+ predicate_property(Module:Head, imported_from(_)).
2567in_file(Module, Head, File) :-
2568 xref_defined(File, Head, How),
2569 xref_current_source(File),
2570 atom(File), 2571 xref_module(File, Module),
2572 How \= imported(_From).
2573in_file(Module, Head, File) :-
2574 exported_from(Module, Head, File).
2575in_file(Module, Head, File) :-
2576 predicate_property(Module:Head, file(File)),
2577 \+ predicate_property(Module:Head, imported_from(_)).
2578in_file(Module, Head, File) :-
2579 current_module(Module),
2580 source_file(Module:Head, File).
2581
2582exported_from(Module, Head, File) :-
2583 distinct(Primary,
2584 ( predicate_property(Module:Head, exported),
2585 ( predicate_property(Module:Head, imported_from(Primary))
2586 -> true
2587 ; Primary = Module
2588 ))),
2589 module_property(Primary, file(File)).
2590
2591:- multifile
2592 arithmetic:evaluable/2. 2593
2594system_arithmetic_function(Head) :-
2595 functor(Head, Name, Arity),
2596 FArith is Arity-1,
2597 FArith >= 0,
2598 functor(FHead, Name, FArith),
2599 arithmetic:evaluable(FHead, system).
2600
2629
2630file(File) -->
2631 file(File, []).
2632
2633file(File, Options) -->
2634 { catch(nb_getval(pldoc_options, GenOptions), _, GenOptions = []),
2635 merge_options(Options, GenOptions, FinalOptions)
2636 },
2637 link_file(File, FinalOptions),
2638 !.
2639file(File, Options) -->
2640 { option(edit_handler(Handler), Options),
2641 http_current_request(Request),
2642 memberchk(path(Path), Request),
2643 absolute_file_name(File, Location,
2644 [ relative_to(Path)
2645 ]),
2646 http_link_to_id(Handler, [location(Location)], HREF),
2647 format(atom(Title), 'Click to create ~w', [File])
2648 },
2649 html(a([href(HREF), class(nofile), title(Title)], File)).
2650file(File, _) -->
2651 html(code(class(nofile), File)).
2652
2653link_file(File, Options) -->
2654 { file_href(File, HREF, Options),
2655 option(label(Label), Options, File),
2656 option(class(Class), Options, file)
2657 },
2658 html(a([class(Class), href(HREF)], Label)).
2659
2663
2664file_href(_, HREF, Options) :-
2665 option(href(HREF), Options),
2666 !.
2667file_href(File, HREF, Options) :-
2668 file_href_real(File, HREF0, Options),
2669 map_extension(HREF0, HREF, Options).
2670
2676
2677map_extension(HREF0, HREF, Options) :-
2678 option(map_extension(Map), Options),
2679 file_name_extension(Base, Old, HREF0),
2680 memberchk(Old-New, Map),
2681 !,
2682 file_name_extension(Base, New, HREF).
2683map_extension(HREF, HREF, _).
2684
2685
2686file_href_real(File, HREF, Options) :-
2687 ( option(absolute_path(Path), Options)
2688 ; existing_linked_file(File, Path)
2689 ),
2690 !,
2691 ( option(files(Map), Options),
2692 memberchk(file(Path, LinkFile), Map)
2693 -> true
2694 ; LinkFile = Path
2695 ),
2696 file_href(LinkFile, HREF).
2697file_href_real(File, HREF, _) :-
2698 directory_alias(Alias),
2699 Term =.. [Alias,File],
2700 absolute_file_name(Term, _,
2701 [ access(read),
2702 file_errors(fail)
2703 ]),
2704 !,
2705 http_absolute_location(Term, HREF, []).
2706
2707directory_alias(icons).
2708directory_alias(css).
2709
2710
2717
2718file_href(Path, HREF) :- 2719 source_file(Path),
2720 !,
2721 doc_file_href(Path, HREF).
2722file_href(Path, HREF) :-
2723 ( nb_current(pldoc_output, CFile)
2724 ; nb_current(pldoc_file, CFile)
2725 ),
2726 CFile \== [],
2727 !,
2728 relative_file_name(Path, CFile, HREF).
2729file_href(Path, Path).
2730
2731
2736
2737existing_linked_file(File, Path) :-
2738 catch(b_getval(pldoc_file, CurrentFile), _, fail),
2739 CurrentFile \== [],
2740 absolute_file_name(File, Path,
2741 [ relative_to(CurrentFile),
2742 access(read),
2743 file_errors(fail)
2744 ]).
2745
2746
2753
2754include(PI, predicate, _) -->
2755 !,
2756 ( html_tokens_for_predicates(PI, [])
2757 -> []
2758 ; html(['[[', \predref(PI), ']]'])
2759 ).
2760include(File, image, Options) -->
2761 { file_name_extension(_, svg, File),
2762 file_href(File, HREF, Options),
2763 !,
2764 include(image_attribute, Options, Attrs0),
2765 merge_options(Attrs0,
2766 [ alt(File),
2767 data(HREF),
2768 type('image/svg+xml')
2769 ], Attrs)
2770 },
2771 ( { option(caption(Caption), Options) }
2772 -> html(div(class(figure),
2773 [ div(class(image), object(Attrs, [])),
2774 div(class(caption), Caption)
2775 ]))
2776 ; html(object(Attrs, []))
2777 ).
2778include(File, image, Options) -->
2779 { file_href(File, HREF, Options),
2780 !,
2781 include(image_attribute, Options, Attrs0),
2782 merge_options(Attrs0,
2783 [ alt(File),
2784 border(0),
2785 src(HREF)
2786 ], Attrs)
2787 },
2788 ( { option(caption(Caption), Options) }
2789 -> html(div(class(figure),
2790 [ div(class(image), img(Attrs)),
2791 div(class(caption), Caption)
2792 ]))
2793 ; html(img(Attrs))
2794 ).
2795include(File, wiki, _Options) --> 2796 { access_file(File, read),
2797 !,
2798 read_file_to_codes(File, String, []),
2799 wiki_codes_to_dom(String, [], DOM)
2800 },
2801 html(DOM).
2802include(File, _Type, Options) -->
2803 link_file(File, Options),
2804 !.
2805include(File, _, _) -->
2806 html(code(class(nofile), ['[[',File,']]'])).
2807
2808image_attribute(src(_)).
2809image_attribute(alt(_)).
2810image_attribute(title(_)).
2811image_attribute(align(_)).
2812image_attribute(width(_)).
2813image_attribute(height(_)).
2814image_attribute(border(_)).
2815image_attribute(class(_)).
2816image_attribute(style(_)).
2817
2818
2828
2829html_tokens_for_predicates([], _Options) -->
2830 [].
2831html_tokens_for_predicates([H|T], Options) -->
2832 !,
2833 html_tokens_for_predicates(H, Options),
2834 html_tokens_for_predicates(T, Options).
2835html_tokens_for_predicates(PI, Options) -->
2836 { PI = _:_/_,
2837 !,
2838 ( doc_comment(PI, Pos, _Summary, Comment)
2839 -> true
2840 ; Comment = ''
2841 )
2842 },
2843 object(PI, [Pos-Comment], [dl], _, Options).
2844html_tokens_for_predicates(Spec, Options) -->
2845 { findall(PI, documented_pi(Spec, PI), List),
2846 List \== [], !
2847 },
2848 html_tokens_for_predicates(List, Options).
2849html_tokens_for_predicates(Spec, Options) -->
2850 man_page(Spec,
2851 [ links(false), 2852 navtree(false), 2853 footer(false), 2854 synopsis(false) 2855 | Options
2856 ]).
2857
2858
2859documented_pi(Spec, PI) :-
2860 generalise_spec(Spec, PI),
2861 doc_comment(PI, _Pos, _Summary, _Comment).
2862
2863generalise_spec(Name/Arity, _M:Name/Arity).
2864generalise_spec(Name//Arity, _M:Name//Arity).
2865
2866
2867 2870
2871
2875
2876doc_for_wiki_file(FileSpec, Options) :-
2877 absolute_file_name(FileSpec, File,
2878 [ access(read)
2879 ]),
2880 read_file_to_codes(File, String, []),
2881 b_setval(pldoc_file, File),
2882 call_cleanup(reply_wiki_page(File, String, Options),
2883 nb_delete(pldoc_file)).
2884
2885reply_wiki_page(File, String, Options) :-
2886 wiki_codes_to_dom(String, [], DOM0),
2887 title(DOM0, File, Title),
2888 insert_edit_button(DOM0, File, DOM, Options),
2889 reply_html_page(pldoc(wiki),
2890 title(Title),
2891 [ \html_requires(pldoc)
2892 | DOM
2893 ]).
2894
2895title(DOM, _, Title) :-
2896 sub_term(h1(_,Title), DOM),
2897 !.
2898title(_, File, Title) :-
2899 file_base_name(File, Title).
2900
2901insert_edit_button(DOM, _, DOM, Options) :-
2902 option(edit(false), Options, false),
2903 !.
2904insert_edit_button([h1(Attrs,Title)|DOM], File,
2905 [h1(Attrs,[ span(style('float:right'),
2906 \edit_button(File, [edit(true)]))
2907 | Title
2908 ])|DOM], _) :- !.
2909insert_edit_button(DOM, File,
2910 [ h1(class(wiki),
2911 [ span(style('float:right'),
2912 \edit_button(File, [edit(true)]))
2913 ])
2914 | DOM
2915 ], _).
2916
2917
2918 2921
2925
2926mode_anchor_name(Var, _) :-
2927 var(Var),
2928 !,
2929 instantiation_error(Var).
2930mode_anchor_name(mode(Head, _), Anchor) :-
2931 !,
2932 mode_anchor_name(Head, Anchor).
2933mode_anchor_name(Head is _Det, Anchor) :-
2934 !,
2935 mode_anchor_name(Head, Anchor).
2936mode_anchor_name(Head, Anchor) :-
2937 pred_anchor_name(Head, _, Anchor).
2938
2939
2943
2944pred_anchor_name(//(Head), Name/Arity, Anchor) :-
2945 !,
2946 functor(Head, Name, DCGArity),
2947 Arity is DCGArity+2,
2948 format(atom(Anchor), '~w/~d', [Name, Arity]).
2949pred_anchor_name(Head, Name/Arity, Anchor) :-
2950 functor(Head, Name, Arity),
2951 format(atom(Anchor), '~w/~d', [Name, Arity]).
2952
2953:- multifile prolog:message//1. 2954
2955prolog:message(pldoc(module_comment_outside_module(Title))) -->
2956 [ 'PlDoc comment <module> ~w does not appear in a module'-[Title] ]