1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2006-2020, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module(pldoc_man, 38 [ man_page//2, % +Obj, +Options 39 man_overview//1, % +Options 40 41 man_content_tree/2, % +Dir, -Tree 42 man_packages_tree/1 % -Tree 43 ]). 44:- use_module(library(xpath),[xpath/3, op(_,_,_)]). 45:- use_module(library(http/html_write)). 46 47:- autoload(doc_html, 48 [ object_tree/5, private/2, object_page_header/4, objects/4, 49 object_href/2, object_synopsis/4, object_footer/4, 50 object_page_footer/4, 51 object_ref/4, object_page/4, 52 object_source_button//2 53 ]). 54:- autoload(doc_process,[doc_comment/4]). 55:- autoload(doc_search,[search_form/3]). 56:- autoload(doc_util,[atom_to_object/2,atom_pi/2]). 57:- autoload(man_index,[manual_object/5]). 58:- autoload(library(apply),[maplist/2,maplist/3,convlist/3]). 59:- autoload(library(debug),[assertion/1,debug/3]). 60:- autoload(library(error),[permission_error/3,existence_error/2]). 61:- autoload(library(filesex), 62 [directory_file_path/3,relative_file_name/3]). 63:- autoload(library(lists), 64 [select/4,append/3,member/2,last/2,selectchk/3]). 65:- autoload(library(option),[merge_options/3,option/2,option/3]). 66:- autoload(library(pairs),[pairs_values/2,pairs_keys/2]). 67:- autoload(library(prolog_xref),[xref_public_list/3]). 68:- autoload(library(sgml), 69 [ load_html/3, dtd/2, new_sgml_parser/2, set_sgml_parser/2, 70 sgml_parse/2, free_sgml_parser/1 71 ]). 72:- autoload(library(uri),[uri_encoded/3]). 73:- autoload(library(www_browser),[expand_url_path/2]). 74:- autoload(library(http/html_head),[html_requires/3]). 75:- if(exists_source(library(http/http_dispatch))). 76:- autoload(library(http/http_dispatch), 77 [ http_link_to_id/3, http_location_by_id/2, 78 http_handler/3, http_reply_file/3, http_redirect/3 79 ]). 80:- endif. 81:- autoload(library(http/http_path),[http_absolute_location/3]). 82:- autoload(library(http/mimetype),[file_mime_type/2]). 83 84:- include(hooks).
90:- predicate_options(man_page//2, 2, 91 [ for(atom), 92 links(boolean), 93 navtree(boolean), 94 synopsis(boolean), 95 footer(boolean), 96 link_source(boolean), 97 no_manual(oneof([fail,error])), 98 search_in(oneof([all, app, man])), 99 search_match(oneof([name, summary])), 100 search_options(boolean) 101 ]). 102 103 104 /******************************* 105 * HIERARCHY * 106 *******************************/
ul list that
reflects the location of Obj in the manual.
(Obj, Options) -->
114 { ensure_man_tree,
115 man_nav_tree(Obj, Tree, Options),
116 TreeOptions = [ secref_style(title)
117 | Options
118 ]
119 },
120 html(ul(class(nav),
121 \object_tree(Tree, [Obj], TreeOptions))).130man_nav_tree(Obj, Tree, _Options) :- 131 man_child_of(Obj, Parent), 132 !, 133 findall(Neighbour, man_child_of(Neighbour, Parent), Neighbours0), 134 ( findall(Child, man_child_of(Child, Obj), Children), 135 Children \== [] 136 -> select(Obj, Neighbours0, node(Obj, Children), Neighbours) 137 ; Neighbours = Neighbours0 138 ), 139 path_up(node(Parent, Neighbours), Tree). 140man_nav_tree(Obj, node(Obj, Children), _Options) :- 141 findall(Child, man_child_of(Child, Obj), Children). 142 143 144path_up(Node, Tree) :- 145 node_id(Node, Id), 146 man_child_of(Id, Parent), 147 !, 148 ( Parent == root 149 -> findall(Neighbour, man_child_of(Neighbour, Parent), Neighbours0), 150 select(Id, Neighbours0, Node, Neighbours), 151 Tree = node(root, Neighbours) 152 ; path_up(node(Parent, [Node]), Tree) 153 ). 154path_up(Tree, Tree).
161man_child_of(Child, Parent) :- 162 term_hash(Child, ChildHash), 163 term_hash(Parent, ParentHash), 164 man_child_of(ChildHash, Child, ParentHash, Parent). 165 166:- dynamic 167 man_child_of/4, 168 man_tree_done/0.
174ensure_man_tree :- 175 man_tree_done, 176 !. 177ensure_man_tree :- 178 with_mutex(man_tree, 179 make_man_tree). 180 181make_man_tree :- 182 man_tree_done, 183 !. 184make_man_tree :- 185 man_content_tree(swi_man_manual('.'), ManTree), 186 man_packages_tree(PkgTree), 187 assert_tree(node(root, [ManTree, PkgTree])), 188 assertz(man_tree_done). 189 190assert_tree(node(Id, Children)) :- 191 !, 192 maplist(assert_parent(Id), Children), 193 maplist(assert_tree, Children). 194assert_tree(_). 195 196assert_parent(Id, Child) :- 197 node_id(Child, ChildId), 198 term_hash(Id, ParentHash), 199 term_hash(ChildId, ChildHash), 200 assertz(man_child_of(ChildHash, ChildId, ParentHash, Id)). 201 202node_id(node(Id, _), Id) :- !. 203node_id(Id, Id).
Contents.html for making the toplevel tree
that links to the individual files. Then we use
html_content_tree/2 to materialize the trees for the files.213man_content_tree(Spec, node(manual, Chapters)) :- 214 absolute_file_name(Spec, Dir, 215 [ file_type(directory), 216 access(read) 217 ]), 218 directory_file_path(Dir, 'Contents.html', ContentsFile), 219 load_html(ContentsFile, DOM, [cdata(string)]), 220 findall(Level-Path, 221 ( xpath(DOM, //div(@class=Class), DIV), 222 class_level(Class, Level), 223 xpath(DIV, a(@class=sec,@href=File), _), 224 \+ sub_atom(File, _, _, _, #), 225 directory_file_path(Dir, File, Path) 226 ), 227 Pairs), 228 index_chapters(Pairs, Chapters). 229 230class_level('toc-h1', 1). 231class_level('toc-h2', 2). 232class_level('toc-h3', 3). 233class_level('toc-h4', 4). 234 235index_chapters([], []). 236index_chapters([Level-File|T0], [node(Chapter, Children)|T]) :- 237 html_content_tree(File, Node), 238 Node = node(Chapter, Children0), 239 append(Children0, Sections, Children), 240 index_sections(T0, Level, Sections, T1), 241 index_chapters(T1, T). 242 243index_sections([], _, [], []) :- !. 244index_sections([SLevel-File|T0], Level, [Node|T], Rest) :- 245 SLevel > Level, 246 !, 247 html_content_tree(File, Node), 248 index_sections(T0, Level, T, Rest). 249index_sections(Rest, _, [], Rest).
256man_packages_tree(node(packages, Packages)) :- 257 Section = section(0, _, _, _), 258 findall(File, 259 manual_object(Section, _Title, File, packages, _), 260 Files), 261 maplist(package_node, Files, Packages). 262 263package_node(File, Tree) :- 264 html_content_tree(File, Tree).
node(Object, ListOfTree).
277html_content_tree(FileIn, Tree) :- 278 absolute_file_name(FileIn, File), 279 findall(Offset-Obj, 280 manual_object(Obj, _Summary, File, _Class, Offset), 281 Pairs), 282 keysort(Pairs, Sorted), 283 pairs_values(Sorted, Objects), 284 make_tree(Objects, Trees), 285 assertion(Trees = [_]), 286 Trees = [Tree]. 287 288make_tree([], []). 289make_tree([Obj|T0], [node(Obj, Children)|T]) :- 290 children(T0, Obj, Children, T1), 291 make_tree(T1, T). 292 293children([], _, [], []) :- !. 294children([Obj|T0], Root, [Node|T], Rest) :- 295 section_level(Obj, ObjLevel), 296 section_level(Root, Level), 297 ObjLevel > Level, 298 !, 299 Node = node(Obj, Children), 300 children(T0, Obj, Children, T1), 301 children(T1, Root, T, Rest). 302children([Obj|T0], Root, [Obj|T], Rest) :- 303 \+ section_level(Obj, _), 304 !, 305 children(T0, Root, T, Rest). 306children(Rest, _, [], Rest). 307 308section_level(section(Level, _Nr, _Id, _File), Level). 309 310 311 /******************************* 312 * RETRIEVE * 313 *******************************/
322load_man_object(Obj, ParentSection, Path, DOM) :- 323 resolve_section(Obj, For), 324 For = section(_,SN,_ID,Path), 325 parent_section(For, ParentSection), 326 findall(Nr-Pos, section_start(Path, Nr, Pos), Pairs), 327 ( ( Pairs = [SN-_|_] 328 ; Pairs == [] 329 ) 330 -> !, 331 load_html(Path, DOM, [cdata(string)]) % Load whole file 332 ; append(_, [SN-Start|Rest], Pairs) 333 -> !, 334 ( member(N-End, Rest), 335 \+ sub_atom(N, 0, _, _, SN), 336 Len is End - Start, 337 Options = [content_length(Len)] 338 -> true 339 ; Options = [] 340 ), 341 open(Path, read, In, [type(binary)]), 342 seek(In, Start, bof, _), 343 dtd(html, DTD), 344 new_sgml_parser(Parser, 345 [ dtd(DTD) 346 ]), 347 set_sgml_parser(Parser, file(Path)), 348 set_sgml_parser(Parser, dialect(sgml)), 349 set_sgml_parser(Parser, shorttag(false)), 350 set_sgml_parser(Parser, defaults(false)), 351 call_cleanup(sgml_parse(Parser, 352 [ document(DOM), 353 source(In), 354 syntax_errors(quiet), 355 cdata(string) 356 | Options 357 ]), 358 ( free_sgml_parser(Parser), 359 close(In) 360 )) 361 ). 362load_man_object(For, Parent, Path, DOM) :- 363 object_spec(For, Obj), 364 manual_object(Obj, _, Path, _, Position), 365 ( object_section(Path, Position, Parent) 366 -> true 367 ; Parent = Path 368 ), 369 open(Path, read, In, [type(binary)]), 370 seek(In, Position, bof, _), 371 dtd(html, DTD), 372 new_sgml_parser(Parser, 373 [ dtd(DTD) 374 ]), 375 set_sgml_parser(Parser, file(Path)), 376 set_sgml_parser(Parser, dialect(sgml)), 377 set_sgml_parser(Parser, shorttag(false)), 378 set_sgml_parser(Parser, defaults(false)), 379 call_cleanup(parse_dts_upto_dd(Parser, In, DOM), 380 ( free_sgml_parser(Parser), 381 close(In) 382 )). 383 384parse_dts_upto_dd(Parser, In, Description) :- 385 sgml_parse(Parser, 386 [ document(DOM0), 387 cdata(string), 388 source(In), 389 parse(element), 390 syntax_errors(quiet) 391 ]), 392 ( DOM0 = [Element], 393 Element = element(dt, _, _) 394 -> Description = [Element|More], 395 parse_dts_upto_dd(Parser, In, More) 396 ; Description = DOM0 397 ). 398 399section_start(Path, Nr, Pos) :- 400 manual_object(section(_,Nr,_,_), _, Path, _, Pos).
408resolve_section(section(Level, No, Spec), Section) :- 409 !, 410 resolve_section(section(Level, No, _, Spec), Section). 411resolve_section(section(Level, No, ID, Path), 412 section(Level, No, ID, Path)) :- 413 nonvar(ID), 414 manual_object(section(Level,No,ID,Path), _, _, _, _), 415 !. 416resolve_section(section(Level, No, ID, Spec), 417 section(Level, No, ID, Path)) :- 418 ground(Spec), 419 absolute_file_name(Spec, Path, 420 [ access(read) 421 ]), 422 ( manual_object(section(Level, No, ID, Path), _, _, _, _) 423 -> true 424 ; path_allowed(Path) 425 -> true 426 ; permission_error(read, manual_file, Spec) 427 ). 428 429 430path_allowed(Path) :- % allow all files from swi/doc 431 absolute_file_name(swi(doc), Parent, 432 [ access(read), 433 file_type(directory) 434 ]), 435 sub_atom(Path, 0, _, _, Parent).
445parent_section(section(Level, Nr, _ID, File), Parent) :- 446 integer(Level), 447 Parent = section(PL, PNr, _PID, _PFile), 448 PL is Level - 1, 449 findall(B, sub_atom(Nr, B, _, _, '.'), BL), 450 last(BL, Before), 451 sub_atom(Nr, 0, Before, _, PNr), 452 ( manual_object(Parent, _, File, _, _) 453 -> true 454 ; manual_object(Parent, _, ParentFile, _, _), 455 same_dir(File, ParentFile) 456 -> true 457 ; manual_object(Parent, _, _, _, _) 458 ), 459 !. 460parent_section(section(Level, _, _, File), Parent) :- 461 Parent = section(ParentLevel, _, _, File), 462 manual_object(Parent, _, _, _, _), 463 ParentLevel < Level, 464 !. 465parent_section(section(_, _, _, File), File).
473object_section(Path, Pos, Section) :- 474 Section = section(_,_,_,_), 475 findall(Section, 476 (manual_object(Section, _, Path, _, SecPos), SecPos =< Pos), 477 List), 478 last(List, Section). 479 480same_dir(File1, File2) :- 481 file_directory_name(File1, Dir), 482 file_directory_name(File2, Dir).
489object_spec(Spec, Spec) :- 490 compound(Spec), 491 !. 492object_spec(Atom, Spec) :- 493 catch(atom_to_term(Atom, Spec, _), _, fail), 494 !, 495 Atom \== Spec. 496object_spec(Atom, PI) :- 497 atom_to_object(Atom, PI). 498 499 500 /******************************* 501 * EMIT * 502 *******************************/
Options:
fail, fail instead of displaying a
not-found message.false, omit the synopsis linetrue (default), include links to the parent object;
if false, just emit the manual material.true (default), display the navigation tree, otherwise
suppress it.542man_page(Obj, Options) --> 543 { ground(Obj), 544 special_node(Obj) 545 }, 546 !, 547 html_requires(pldoc), 548 man_links([], Options), 549 man_matches([Obj], Obj, Options). 550man_page(Obj0, Options) --> % Manual stuff 551 { full_page(Obj0, Obj), 552 findall((Parent+Path)-(Obj+DOM), 553 load_man_object(Obj, Parent, Path, DOM), 554 Matches), 555 Matches = [_|_], 556 !, 557 pairs_keys(Matches, ParentPaths), 558 Matches = [Parent+Path-_|_] 559 }, 560 html_requires(pldoc), 561 man_links(ParentPaths, Options), 562 man_matches(Matches, Obj, Options). 563man_page(Obj, Options) --> % PlDoc predicates, etc. 564 { full_object(Obj, Full), 565 findall(Full-File, 566 ( doc_comment(Full, File:_, _, _), 567 \+ private(Full, Options) 568 ), 569 Pairs), 570 Pairs \== [], 571 pairs_keys(Pairs, Objs) 572 }, 573 !, 574 html_requires(pldoc), 575 ( { Pairs = [_-File] } 576 -> object_page_header(File, Options) 577 ; object_page_header(-, Options) 578 ), 579 { merge_options(Options, 580 [ synopsis(true), 581 navtree(true) 582 ], Options2) 583 }, 584 objects(Objs, Options2). 585man_page(Obj, Options) --> % failure 586 { \+ option(no_manual(fail), Options) 587 }, 588 html_requires(pldoc), 589 man_links([], Options), 590 html(p(class(noman), 591 [ 'Sorry, No manual entry for ', 592 b('~w'-[Obj]) 593 ])). 594 595%special_node(manual). % redirected to the Introduction section 596special_node(root). 597special_node(packages). 598 599full_page(Obj, _) :- 600 var(Obj), !, fail. 601full_page(Obj, Obj) :- 602 Obj = section(_,_,_,_), 603 !. 604full_page(section(ID), section(_,_,ID,_)) :- !. 605full_page(manual, section(_,_,'sec:intro',_)) :- !. 606full_page(Obj0, Obj) :- 607 ground(Obj0), 608 alt_obj(Obj0, Obj), 609 manual_object(Obj, _, _, _, _), 610 !. 611full_page(Obj, Obj) :- 612 ground(Obj). 613 614alt_obj(Obj, Obj). 615alt_obj(Name/Arity, Name//DCGArity) :- 616 integer(Arity), 617 Arity >= 2, 618 DCGArity is Arity - 2. 619alt_obj(Name//DCGArity, Name/Arity) :- 620 integer(DCGArity), 621 Arity is DCGArity + 2.
627full_object(Object, M:Obj) :- 628 qualify(Object, M:Obj0), 629 alt_obj(Obj0, Obj), 630 doc_comment(M:Obj, _, _, _), 631 !. 632 633qualify(M:O, M:O). 634qualify(O, _:O).
The tricky part is that there are cases where multiple modules export the same predicate. We must find from the title of the manual section which library is documented.
646man_qualified_object(Text, Parent, LibOpt, Object, Section) :- 647 atom(Text), 648 atom_pi(Text, PI), 649 ground(PI), 650 !, 651 man_qualified_object_2(PI, Parent, LibOpt, Object, Section). 652man_qualified_object(Object0, Parent, LibOpt, Object, Section) :- 653 man_qualified_object_2(Object0, Parent, LibOpt, Object, Section). 654 655man_qualified_object_2(Name/Arity, Parent, 656 LibOpt, Module:Name/Arity, Section) :- 657 object_module(Parent, Module, Section, LibOpt), 658 !. 659man_qualified_object_2(Object, Parent, [], Object, Parent).
667:- public 668 man_synopsis//2. % called from man_match//2 669 670man_synopsis(PI, Section) --> 671 man_synopsis(PI, Section, []). 672 673man_synopsis(PI, Section, Options) --> 674 { object_href(Section, HREF) 675 }, 676 object_synopsis(PI, [href(HREF)|Options]).
682object_module(Section0, Module, Section, [source(Term)]) :- 683 parent_section_ndet(Section0, Section), 684 manual_object(Section, Title, _File, _Class, _Offset), 685 ( once(sub_atom(Title, B, _, _, :)), 686 sub_atom(Title, 0, B, _, Atom), 687 catch(term_to_atom(Term, Atom), _, fail), 688 ground(Term), 689 Term = library(_) 690 -> !, 691 absolute_file_name(Term, PlFile, 692 [ file_type(prolog), 693 access(read), 694 file_errors(fail) 695 ]), 696 ( module_property(Module, file(PlFile)) 697 -> true 698 ; xref_public_list(PlFile, -, % module is not loaded 699 [ module(Module) 700 ]) 701 ) 702 ). 703 704parent_section_ndet(Section, Section). 705parent_section_ndet(Section, Parent) :- 706 parent_section(Section, Parent0), 707 parent_section_ndet(Parent0, Parent). 708 709 710man_matches(Matches, Object, Options) --> 711 { option(navtree(false), Options) }, 712 !, 713 man_matches_nt(Matches, Object, Options). 714man_matches(Matches, Object, Options) --> 715 html([ div(class(navtree), 716 div(class(navwindow), 717 \man_nav_tree(Object, Options))), 718 div(class(navcontent), 719 \man_matches_nt(Matches, Object, Options)) 720 ]). 721 722 723man_matches_nt([Match], Object, Options) --> 724 { option(footer(true), Options, true) }, 725 !, 726 man_match(Match, Object, Options), 727 object_page_footer(Object, []). 728man_matches_nt(Matches, Object, Options) --> 729 man_matches_list(Matches, Object, Options). 730 731man_matches_list([], _, _) --> []. 732man_matches_list([H|T], Obj, Options) --> 733 man_match(H, Obj, Options), 734 man_matches_list(T, Obj, Options).
741man_match(packages, packages, _) --> 742 !, 743 html({|html|| 744 <p> 745 Packages are relatively independent add-on libraries that 746 may not be available in all installations. Packages are 747 part of the source code releases of SWI-Prolog and may be 748 enabled or disabled during the build.</p> 749 750 <p> 751 See also <a href="/pack/list">Add-ons</a> for extensions 752 provided by the community that must be installed separately 753 using 754 <a href="/pldoc/doc_for?object=pack_install/1">pack_install/1</a>.</p> 755 |}). 756man_match(root, root, _) --> 757 !, 758 man_overview([]). 759man_match((Parent+Path)-(Obj+DOM), Obj, Options) --> 760 { \+ option(synopsis(false), Options), 761 DOM = [element(dt,A,C0)|DD], 762 convlist(dt_obj, DOM, Objs), 763 option(link_source(Link), Options, true), 764 man_qualified_object(Obj, Parent, LibOpt, QObj, Section), 765 !, 766 C = [ span(style('float:right;margin-left:5px;'), 767 \object_source_button(QObj, [source_link(Link)])) 768 | C0 769 ] 770 }, 771 dom_list([ element(dt,[],[\man_synopsis(QObj, Section, LibOpt)]), 772 element(dt,A,C) 773 | DD 774 ], Path, Options), 775 object_footer(Objs, Options). 776man_match((_Parent+Path)-(Obj+DOM), Obj, Options) --> 777 dom_list(DOM, Path, Options). 778 779dt_obj(element(dt,_,C), Obj) :- 780 xpath(C, //a(@id=Atom), _), 781 atom_to_object(Atom, Obj). 782 783:- html_meta 784 dom_list(, , , , ). 785 786dom_list(_:[], _, _) --> 787 !, 788 []. 789dom_list(M:[H|T], Path, Options) --> 790 dom(H, Path, Options), 791 dom_list(M:T, Path, Options). 792 793dom(element(E, Atts, Content), Path, Options) --> 794 !, 795 dom_element(E, Atts, Content, Path, Options). 796dom(CDATA, _, _) --> 797 html(CDATA). 798 799dom_element(a, _, [], _, _) --> % Useless back-references 800 !, 801 []. 802dom_element(a, Att, Content, Path, Options) --> 803 { memberchk(href=HREF, Att), 804 ( memberchk(class=Class, Att) 805 -> true 806 ; Class = unknown 807 ), 808 rewrite_ref(Class, HREF, Path, Myref, Options) 809 }, 810 !, 811 html(a(href(Myref), \dom_list(Content, Path, Options))). 812dom_element(span, Att, [CDATA], _, Options) --> 813 { memberchk(class='pred-ext', Att), 814 atom_pi(CDATA, PI), 815 documented(PI), 816 ( option(server(false), Options) 817 -> public_link(predicate(CDATA), HREF) 818 ; http_link_to_id(pldoc_man, [predicate=CDATA], HREF) 819 ) 820 }, 821 !, 822 html(a(href(HREF), CDATA)). 823dom_element(img, Att0, [], Path, _Options) --> 824 { selectchk(src=Src, Att0, Att1), 825 relative_file_name(ImgFile, Path, Src), 826 handler_alias(Handler, DirAlias), 827 absolute_file_name(DirAlias, Dir, 828 [ file_errors(fail), 829 solutions(all), 830 file_type(directory) 831 ]), 832 ensure_slash(Dir, DirS), 833 atom_concat(DirS, NewSrc, ImgFile), 834 !, 835 http_link_to_id(Handler, [], ManRef), 836 directory_file_path(ManRef, NewSrc, NewPath), 837 Begin =.. [img, src(NewPath) | Att1] 838 }, 839 html_begin(Begin), 840 html_end(img). 841dom_element(div, Att, _, _, _) --> 842 { memberchk(class=navigate, Att) }, 843 !. 844dom_element(html, _, Content, Path, Options) --> 845 !, % do not emit a html for the second time 846 dom_list(Content, Path, Options). 847dom_element(head, _, Content, Path, Options) --> 848 !, % do not emit a head for the second time 849 dom_list(Content, Path, Options). 850dom_element(title, _, _, _, _) --> !. 851dom_element(link, _, _, _, _) --> !. 852dom_element(body, _, Content, Path, Options) --> 853 !, % do not emit a body for the second time 854 dom_list(Content, Path, Options). 855dom_element(Name, Attrs, Content, Path, Options) --> 856 { Begin =.. [Name|Attrs] }, 857 html_begin(Begin), 858 dom_list(Content, Path, Options), 859 html_end(Name). 860 861handler_alias(manual_file, swi_man_manual(.)). 862handler_alias(pldoc_package, swi_man_packages(.)). 863 864ensure_slash(Dir, DirS) :- 865 ( sub_atom(Dir, _, _, 0, /) 866 -> DirS = Dir 867 ; atom_concat(Dir, /, DirS) 868 ).
877public_link(predicate(CDATA), HREF) :-
878 uri_encoded(query_value, CDATA, Encoded),
879 atom_concat('https://www.swi-prolog.org/pldoc/doc_for?object=',
880 Encoded, HREF).887documented(PI) :- 888 manual_object(PI, _, _, _, _), 889 !. 890documented(PI) :- 891 full_object(PI, _Obj).
/man?predicate=PI.section(Level, NT, ID, FilePath)section(Level, NT, ID, FilePath)#flag:Namesection(Level, NT, ID, FilePath)#gloss:Name
$ File#Name() Rewrite to /man/CAPI=Name
925rewrite_ref(_Class, Ref, _Path, Ref, Options) :- 926 option(server(false), Options), 927 !. 928rewrite_ref(Class, Ref0, Path, ManRef, _Options) :- 929 rewrite_ref(Class, Ref0, Path, ManRef). 930 931rewrite_ref(pred, Ref0, _, Ref) :- % Predicate/DCG reference 932 sub_atom(Ref0, _, _, A, '#'), 933 !, 934 sub_atom(Ref0, _, A, 0, Fragment), 935 atom_to_object(Fragment, PI), 936 manual_object(PI, _, _, _, _), 937 uri_encoded(query_value, Fragment, Enc), 938 http_location_by_id(pldoc_man, ManHandler), 939 format(string(Ref), '~w?predicate=~w', [ManHandler, Enc]). 940rewrite_ref(function, Ref0, _, Ref) :- % Arithmetic function reference 941 sub_atom(Ref0, _, _, A, '#'), 942 !, 943 sub_atom(Ref0, _, A, 0, Fragment), 944 atom_to_object(Fragment, PI), 945 manual_object(PI, _, _, _, _), 946 PI=f(Name/Arity), 947 format(atom(PIName), '~w/~w', [Name,Arity]), 948 uri_encoded(query_value, PIName, Enc), 949 http_location_by_id(pldoc_man, ManHandler), 950 format(string(Ref), '~w?function=~w', [ManHandler, Enc]). 951rewrite_ref(func, Ref0, _, Ref) :- % C-API reference 952 sub_atom(Ref0, _, _, A, '#'), 953 !, 954 sub_atom(Ref0, _, A, 0, Fragment), 955 atom_to_object(Fragment, Obj), 956 manual_object(Obj, _, _, _, _), 957 Obj = c(Function), 958 uri_encoded(query_value, Function, Enc), 959 http_location_by_id(pldoc_man, ManHandler), 960 format(string(Ref), '~w?CAPI=~w', [ManHandler, Enc]). 961rewrite_ref(sec, Ref0, Path, Ref) :- % Section inside a file 962 sub_atom(Ref0, B, _, A, '#'), 963 !, 964 sub_atom(Ref0, _, A, 0, Fragment), 965 sub_atom(Ref0, 0, B, _, File), 966 referenced_section(Fragment, File, Path, Section), 967 object_href(Section, Ref). 968rewrite_ref(sec, File, Path, Ref) :- % Section is a file 969 file_directory_name(Path, Dir), 970 atomic_list_concat([Dir, /, File], SecPath), 971 Obj = section(_, _, _, SecPath), 972 manual_object(Obj, _, _, _, _), 973 !, 974 object_href(Obj, Ref). 975rewrite_ref(cite, Ref0, Path, Ref) :- % Citation (bit hard-wired) 976 debug(pldoc(cite), 'Cite ref ~q ~q', [Ref0, Path]), 977 sub_atom(Ref0, _, _, A, '#'), 978 !, 979 sub_atom(Ref0, _, A, 0, Fragment), 980 uri_encoded(query_value, Fragment, Enc), 981 http_location_by_id(pldoc_man, ManHandler), 982 format(string(Ref), '~w?section=bibliography#~w', [ManHandler, Enc]). 983rewrite_ref(flag, Ref0, Path, Ref) :- 984 sub_atom(Ref0, B, _, A, '#'), 985 !, 986 sub_atom(Ref0, 0, B, _, File), 987 sub_atom(Ref0, _, A, 0, Fragment), 988 file_directory_name(Path, Dir), 989 atomic_list_concat([Dir, /, File], SecPath), 990 Obj = section(_, _, _, SecPath), 991 manual_object(Obj, _, _, _, _), 992 !, 993 object_href(Obj, Ref1), 994 format(string(Ref), '~w#~w', [Ref1, Fragment]). 995rewrite_ref(gloss, Ref0, Path, Ref) :- 996 sub_atom(Ref0, B, _, A, '#'), 997 !, 998 sub_atom(Ref0, 0, B, _, File), 999 sub_atom(Ref0, _, A, 0, Fragment), 1000 file_directory_name(Path, Dir), 1001 atomic_list_concat([Dir, /, File], SecPath), 1002 Obj = section(_, _, _, SecPath), 1003 manual_object(Obj, _, _, _, _), 1004 !, 1005 object_href(Obj, Ref1), 1006 format(string(Ref), '~w#~w', [Ref1, Fragment]).
1010referenced_section(Fragment, File, Path, section(Level, Nr, ID, SecPath)) :-
1011 atom_concat('sec:', Nr, Fragment),
1012 ( File == ''
1013 -> SecPath = Path
1014 ; file_directory_name(Path, Dir),
1015 atomic_list_concat([Dir, /, File], SecPath)
1016 ),
1017 manual_object(section(Level, Nr, ID, SecPath), _, _, _, _).1024man_links(ParentPaths, Options) --> 1025 prolog:doc_page_header(parents(ParentPaths), Options), 1026 !. 1027man_links(ParentPaths, Options) --> 1028 { option(links(true), Options, true), 1029 option(header(true), Options, true) 1030 }, 1031 !, 1032 html([ div(class(navhdr), 1033 [ div(class(jump), \man_parent(ParentPaths)), 1034 div(class(search), \search_form(Options)), 1035 br(clear(right)) 1036 ]), 1037 p([]) 1038 ]). 1039man_links(_, _) --> 1040 []. 1041 1042man_parent(ParentPaths) --> 1043 { maplist(parent_to_section, ParentPaths, [Section|MoreSections]), 1044 maplist(=(Section), MoreSections) 1045 }, 1046 !, 1047 object_ref(Section, [secref_style(number_title)]). 1048man_parent(_) --> []. 1049 1050parent_to_section(X+_, X) :- 1051 X = section(_,_,_,_), 1052 !. 1053parent_to_section(File+_, Section) :- 1054 atom(File), 1055 manual_object(Section, _Title, File, _Class, _Offset), 1056 !.
number, title or number_title.1065section_link(Section, Options) --> 1066 { option(secref_style(Style), Options, number) 1067 }, 1068 section_link(Style, Section, Options). 1069 1070section_link(number, section(_, Number, _, _), _Options) --> 1071 !, 1072 ( {Number == '0'} % Title. Package? 1073 -> [] 1074 ; html(['Sec. ', Number]) 1075 ). 1076section_link(title, Obj, _Options) --> 1077 !, 1078 { manual_object(Obj, Title, _File, _Class, _Offset) 1079 }, 1080 html(Title). 1081section_link(_, Obj, _Options) --> 1082 !, 1083 { Obj = section(_, Number, _, _), 1084 manual_object(Obj, Title, _File, _Class, _Offset) 1085 }, 1086 ( { Number == '0' } 1087 -> html(Title) 1088 ; html([Number, ' ', Title]) 1089 ).
1095function_link(Function, _) --> 1096 html([Function, '()']). 1097 1098 1099 /******************************* 1100 * INDICES & OVERVIEW * 1101 *******************************/
1108man_overview(Options) --> 1109 { http_absolute_location(pldoc_man(.), RefMan, []) 1110 }, 1111 html([ h1('SWI-Prolog documentation'), 1112 blockquote(class(refman_link), 1113 a(href(RefMan), 1114 'SWI-Prolog reference manual')), 1115 \package_overview(Options), 1116 \paperback(Options) 1117 ]). 1118 1119package_overview(Options) --> 1120 html([ h2(class(package_doc_title), 1121 'SWI-Prolog package documentation'), 1122 blockquote(class(package_overview), 1123 \packages(Options)) 1124 ]). 1125 1126packages(Options) --> 1127 { findall(Pkg, current_package(Pkg), Pkgs) 1128 }, 1129 packages(Pkgs, Options). 1130 1131packages([], _) --> 1132 []. 1133packages([Pkg|T], Options) --> 1134 package(Pkg, Options), 1135 packages(T, Options). 1136 1137package(pkg(Title, HREF, HavePackage), Options) --> 1138 { package_class(HavePackage, Class, Options) 1139 }, 1140 html(div(class(Class), 1141 a([href(HREF)], Title))). 1142 1143package_class(true, pkg_link, _). 1144package_class(false, no_pkg_link, _). 1145 1146current_package(pkg(Title, HREF, HavePackage)) :- 1147 manual_object(section(0, _, _, _), Title, File, packages, _), 1148 file_base_name(File, FileNoDir), 1149 file_name_extension(Base, _, FileNoDir), 1150 ( exists_source(library(Base)) 1151 -> HavePackage = true 1152 ; HavePackage = false 1153 ), 1154 http_absolute_location(pldoc_pkg(FileNoDir), HREF, []). 1155 1156 1157:- if(current_predicate(http_handler/3)). 1158:- http_handler(pldoc(jpl), pldoc_jpl, [prefix]). 1159:- http_handler(pldoc_pkg(.), pldoc_package, [prefix]). 1160:- http_handler(pldoc_man(.), pldoc_refman, [prefix]). 1161:- http_handler(pldoc(packages), pldoc_package_overview, []).
1167pldoc_jpl(Request) :-
1168 memberchk(path_info(JPLFile), Request),
1169 atom_concat('doc/packages/jpl', JPLFile, Path),
1170 http_reply_file(swi(Path), [], Request).1179pldoc_package(Request) :- 1180 ( \+ option(path_info(_), Request) 1181 -> true 1182 ; option(path_info(/), Request) 1183 ), 1184 http_link_to_id(pldoc_object, [object=packages], HREF), 1185 http_redirect(see_other, HREF, Request). 1186pldoc_package(Request) :- 1187 memberchk(path_info(Img), Request), 1188 file_mime_type(Img, image/_), 1189 !, 1190 http_reply_file(swi_man_packages(Img), [], Request). 1191pldoc_package(Request) :- 1192 memberchk(path_info('jpl'), Request), 1193 !, 1194 memberchk(path(Path0), Request), 1195 atom_concat(Path0, /, Path), 1196 http_redirect(moved, Path, Request). 1197pldoc_package(Request) :- 1198 memberchk(path_info(JPLFile), Request), 1199 ( JPLFile == 'jpl/' 1200 -> Path = 'doc/packages/jpl/index.html' 1201 ; sub_atom(JPLFile, 0, _, _, 'jpl/') 1202 -> atom_concat('doc/packages/', JPLFile, Path) 1203 ), 1204 http_reply_file(swi(Path), [], Request). 1205pldoc_package(Request) :- 1206 memberchk(path_info(PkgDoc), Request), 1207 ensure_html_ext(PkgDoc, PkgHtml), 1208 atom_concat('packages/', PkgHtml, Path), 1209 term_to_atom(section(Path), Object), 1210 http_link_to_id(pldoc_object, [object=Object], HREF), 1211 http_redirect(see_other, HREF, Request). 1212 1213ensure_html_ext(Pkg, PkgHtml) :- 1214 file_name_extension(_, html, Pkg), 1215 !, 1216 PkgHtml = Pkg. 1217ensure_html_ext(Pkg, PkgHtml) :- 1218 file_name_extension(Pkg, html, PkgHtml).
1224pldoc_package_overview(_Request) :- 1225 reply_html_page( 1226 pldoc(packages), 1227 title('SWI-Prolog package documentation'), 1228 \package_overview([])). 1229:- endif.
1235paperback(_Options) -->
1236 { expand_url_path(swipl_book(.), HREF)
1237 },
1238 html([ h2('The manual as a book'),
1239 p([ 'A paperback version of the manual is ',
1240 a(href(HREF), 'available'), '.'
1241 ])
1242 ]).1249pldoc_refman(Request) :- 1250 memberchk(path_info(Section), Request), 1251 \+ sub_atom(Section, _, _, _, /), 1252 Obj = section(0,_,_,_), 1253 manual_object(Obj, Title, File, manual, _), 1254 file_base_name(File, Section), 1255 !, 1256 reply_html_page(pldoc(man), 1257 title(Title), 1258 \object_page(Obj, [])). 1259pldoc_refman(Request) :- % server Contents.html 1260 \+ memberchk(path_info(_), Request), 1261 !, 1262 http_link_to_id(pldoc_object, [object(manual)], HREF), 1263 http_redirect(see_other, HREF, Request). 1264pldoc_refman(Request) :- 1265 memberchk(path(Path), Request), 1266 existence_error(http_location, Path). 1267 1268 1269 /******************************* 1270 * HOOK SEARCH * 1271 *******************************/ 1272 1273prologdoc_object_summary(section(ID), Class, File, Summary) :- 1274 nonvar(ID), % when generating, only do full ones 1275 manual_object(section(_Level, _No, ID, _Path), Summary, File, Class, _Offset). 1276prologdoc_object_summary(Obj, Class, File, Summary) :- 1277 manual_object(Obj, Summary, File, Class, _Offset). 1278 1279prologdoc_object_page(Obj, Options) --> 1280 man_page(Obj, [no_manual(fail),footer(false)|Options]).
1286prologdoc_object_link(Obj, Options) --> 1287 { Obj = section(_,_,_,_) }, 1288 !, 1289 section_link(Obj, Options). 1290prologdoc_object_link(Obj0, Options) --> 1291 { Obj0 = section(ID), 1292 Obj = section(_Level, _No, ID, _Path), 1293 manual_object(Obj, _, _, _, _) 1294 }, 1295 !, 1296 section_link(Obj, Options). 1297prologdoc_object_link(Obj, Options) --> 1298 { Obj = c(Function) }, 1299 !, 1300 function_link(Function, Options). 1301prologdoc_object_link(root, _) --> 1302 !, 1303 html('Documentation'). 1304prologdoc_object_link(manual, _Options) --> 1305 !, 1306 html('Reference manual'). 1307prologdoc_object_link(packages, _) --> 1308 html('Packages'). 1309 1310prologdoc_category(manual, 30, 'Reference Manual'). 1311prologdoc_category(packages, 40, 'Packages'). 1312 1313prologdoc_file_index_header(File, Options) --> 1314 { Section = section(_Level, _No, _ID, File), 1315 manual_object(Section, _Summary, File, _Cat, _Offset) 1316 }, 1317 !, 1318 html(tr(th([colspan(3), class(section)], 1319 [ \object_ref(Section, 1320 [ secref_style(number_title) 1321 | Options 1322 ]) 1323 ]))). 1324 1325prologdoc_object_title(Obj, Title) :- 1326 Obj = section(_,_,_,_), 1327 manual_object(Obj, Title, _, _, _), 1328 !. 1329 1330prologdoc_canonical_object(section(_Level, _No, ID, _Path), 1331 section(ID)).
1337prologdoc_object_href(section(ID), HREF) :- 1338 nonvar(ID), 1339 atom_concat('sec:', Sec, ID), 1340 http_link_to_id(pldoc_man, [section(Sec)], HREF). 1341prologdoc_object_href(section(_Level, _No, ID, _Path), HREF) :- 1342 nonvar(ID), 1343 atom_concat('sec:', Sec, ID), 1344 http_link_to_id(pldoc_man, [section(Sec)], HREF). 1345 1346 /******************************* 1347 * NO HTTP * 1348 *******************************/ 1349 1350:- if(\+current_predicate(http_link_to_id/3)). 1351 1352http_link_to_id(Id, Parameters, HREF) :- 1353 must_be(list, Parameters), 1354 format(atom(Location), '/pldoc/~w', [Id]), 1355 ( Parameters == [] 1356 -> HREF = Location 1357 ; uri_data(path, Components, Location), 1358 uri_query_components(String, Parameters), 1359 uri_data(search, Components, String), 1360 uri_components(HREF, Components) 1361 ). 1362 1363:- endif. 1364 1365 /******************************* 1366 * MESSAGES * 1367 *******************************/ 1368 1369:- multifile prolog:message//1. 1370 1371prologmessage(pldoc(no_section_id(File, Title))) --> 1372 [ 'PlDoc: ~w: no id for section "~w"'-[File, Title] ]. 1373prologmessage(pldoc(duplicate_ids(L))) --> 1374 [ 'PlDoc: duplicate manual section IDs:'-[], nl 1375 ], 1376 duplicate_ids(L). 1377 1378duplicate_ids([]) --> []. 1379duplicate_ids([H|T]) --> duplicate_id(H), duplicate_ids(T). 1380 1381duplicate_id(Id) --> 1382 { findall(File, manual_object(section(_,_,Id,File),_,_,_,_), Files) }, 1383 [ ' ~w: ~p'-[Id, Files], nl ]
Process SWI-Prolog HTML manuals
*/