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:- use_module(library(debug),[assertion/1,debug/3]). 47 48:- autoload(doc_html, 49 [ object_tree/5, private/2, object_page_header/4, objects/4, 50 object_href/2, object_synopsis/4, object_footer/4, 51 object_page_footer/4, 52 object_ref/4, object_page/4, 53 object_source_button//2 54 ]). 55:- autoload(doc_process,[doc_comment/4]). 56:- autoload(doc_search,[search_form/3]). 57:- autoload(doc_util,[atom_to_object/2,atom_pi/2]). 58:- autoload(man_index,[manual_object/5]). 59:- autoload(library(apply),[maplist/2,maplist/3,convlist/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 *******************************/
f(Name/Arity)
display documentation of an arithmetic functionc(Function)
display documentation of a C API functionsection(Level, Number, Id, File)
Display a section of the manualsec(DocFile#Id)
Display a section of the manual (from short form)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, visible_doc_comment(Full, File, Options), Pairs), 566 Pairs \== [], 567 pairs_keys(Pairs, Objs) 568 }, 569 !, 570 html_requires(pldoc), 571 ( { Pairs = [_-File] } 572 -> object_page_header(File, Options) 573 ; object_page_header(-, Options) 574 ), 575 { merge_options(Options, 576 [ synopsis(true), 577 navtree(true) 578 ], Options2) 579 }, 580 objects(Objs, Options2). 581man_page(Obj, Options) --> % failure 582 { \+ option(no_manual(fail), Options) 583 }, 584 html_requires(pldoc), 585 man_links([], Options), 586 html(p(class(noman), 587 [ 'Sorry, No manual entry for ', 588 b('~w'-[Obj]) 589 ])). 590 591% Show an object if it is not private or it is fully qualified and we 592% want to show all fully qualified objects. Used by help/1. 593 594visible_doc_comment(Obj, File, Options) :- 595 doc_comment(Obj, File:_, _, _), 596 \+ ( private(Obj, Options), 597 \+ ( Obj = _:_, 598 option(qualified(always), Options) 599 ) 600 ). 601 602%special_node(manual). % redirected to the Introduction section 603special_node(root). 604special_node(packages). 605 606full_page(Obj, _) :- 607 var(Obj), !, fail. 608full_page(Obj, Obj) :- 609 Obj = section(_,_,_,_), 610 !. 611full_page(section(ID), section(_,_,ID,_)) :- !. 612full_page(manual, section(_,_,'sec:intro',_)) :- !. 613full_page(Obj0, Obj) :- 614 ground(Obj0), 615 alt_obj(Obj0, Obj), 616 manual_object(Obj, _, _, _, _), 617 !. 618full_page(Obj, Obj) :- 619 ground(Obj). 620 621alt_obj(Obj, Obj). 622alt_obj(Name/Arity, Name//DCGArity) :- 623 integer(Arity), 624 Arity >= 2, 625 DCGArity is Arity - 2. 626alt_obj(Name//DCGArity, Name/Arity) :- 627 integer(DCGArity), 628 Arity is DCGArity + 2.
634full_object(Object, M:Obj) :- 635 qualify(Object, M:Obj0), 636 alt_obj(Obj0, Obj), 637 doc_comment(M:Obj, _, _, _), 638 !. 639 640qualify(M:O, M:O). 641qualify(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.
653man_qualified_object(Text, Parent, LibOpt, Object, Section) :- 654 atom(Text), 655 atom_pi(Text, PI), 656 ground(PI), 657 !, 658 man_qualified_object_2(PI, Parent, LibOpt, Object, Section). 659man_qualified_object(Object0, Parent, LibOpt, Object, Section) :- 660 man_qualified_object_2(Object0, Parent, LibOpt, Object, Section). 661 662man_qualified_object_2(Name/Arity, Parent, 663 LibOpt, Module:Name/Arity, Section) :- 664 object_module(Parent, Module, Section, LibOpt), 665 !. 666man_qualified_object_2(Object, Parent, [], Object, Parent).
674:- public 675 man_synopsis//2. % called from man_match//2 676 677man_synopsis(PI, Section) --> 678 man_synopsis(PI, Section, []). 679 680man_synopsis(PI, Section, Options) --> 681 { object_href(Section, HREF) 682 }, 683 object_synopsis(PI, [href(HREF)|Options]).
689object_module(Section0, Module, Section, [source(Term)]) :- 690 parent_section_ndet(Section0, Section), 691 manual_object(Section, Title, _File, _Class, _Offset), 692 ( once(sub_atom(Title, B, _, _, :)), 693 sub_atom(Title, 0, B, _, Atom), 694 catch(term_to_atom(Term, Atom), _, fail), 695 ground(Term), 696 Term = library(_) 697 -> !, 698 absolute_file_name(Term, PlFile, 699 [ file_type(prolog), 700 access(read), 701 file_errors(fail) 702 ]), 703 ( module_property(Module, file(PlFile)) 704 -> true 705 ; xref_public_list(PlFile, -, % module is not loaded 706 [ module(Module) 707 ]) 708 ) 709 ). 710 711parent_section_ndet(Section, Section). 712parent_section_ndet(Section, Parent) :- 713 parent_section(Section, Parent0), 714 parent_section_ndet(Parent0, Parent). 715 716 717man_matches(Matches, Object, Options) --> 718 { option(navtree(false), Options) }, 719 !, 720 man_matches_nt(Matches, Object, Options). 721man_matches(Matches, Object, Options) --> 722 html([ div(class(navtree), 723 div(class(navwindow), 724 \man_nav_tree(Object, Options))), 725 div(class(navcontent), 726 \man_matches_nt(Matches, Object, Options)) 727 ]). 728 729 730man_matches_nt([Match], Object, Options) --> 731 { option(footer(true), Options, true) }, 732 !, 733 man_match(Match, Object, Options), 734 object_page_footer(Object, []). 735man_matches_nt(Matches, Object, Options) --> 736 man_matches_list(Matches, Object, Options). 737 738man_matches_list([], _, _) --> []. 739man_matches_list([H|T], Obj, Options) --> 740 man_match(H, Obj, Options), 741 man_matches_list(T, Obj, Options).
748man_match(packages, packages, _) --> 749 !, 750 html({|html|| 751 <p> 752 Packages are relatively independent add-on libraries that 753 may not be available in all installations. Packages are 754 part of the source code releases of SWI-Prolog and may be 755 enabled or disabled during the build.</p> 756 757 <p> 758 See also <a href="/pack/list">Add-ons</a> for extensions 759 provided by the community that must be installed separately 760 using 761 <a href="/pldoc/doc_for?object=pack_install/1">pack_install/1</a>.</p> 762 |}). 763man_match(root, root, _) --> 764 !, 765 man_overview([]). 766man_match((Parent+Path)-(Obj+DOM), Obj, Options) --> 767 { \+ option(synopsis(false), Options), 768 DOM = [element(dt,A,C0)|DD], 769 convlist(dt_obj, DOM, Objs), 770 option(link_source(Link), Options, true), 771 man_qualified_object(Obj, Parent, LibOpt, QObj, Section), 772 !, 773 C = [ span(style('float:right;margin-left:5px;'), 774 \object_source_button(QObj, [source_link(Link)])) 775 | C0 776 ] 777 }, 778 dom_list([ element(dt,[],[\man_synopsis(QObj, Section, LibOpt)]), 779 element(dt,A,C) 780 | DD 781 ], Path, Options), 782 object_footer(Objs, Options). 783man_match((_Parent+Path)-(Obj+DOM), Obj, Options) --> 784 dom_list(DOM, Path, Options). 785 786dt_obj(element(dt,_,C), Obj) :- 787 xpath(C, //a(@id=Atom), _), 788 atom_to_object(Atom, Obj). 789 790:- html_meta 791 dom_list( , , , , ). 792 793dom_list(_:[], _, _) --> 794 !, 795 []. 796dom_list(M:[H|T], Path, Options) --> 797 dom(H, Path, Options), 798 dom_list(M:T, Path, Options). 799 800dom(element(E, Atts, Content), Path, Options) --> 801 !, 802 dom_element(E, Atts, Content, Path, Options). 803dom(CDATA, _, _) --> 804 html(CDATA). 805 806dom_element(a, _, [], _, _) --> % Useless back-references 807 !, 808 []. 809dom_element(a, Att, Content, Path, Options) --> 810 { memberchk(href=HREF, Att), 811 ( memberchk(class=Class, Att) 812 -> true 813 ; Class = unknown 814 ), 815 rewrite_ref(Class, HREF, Path, Myref, Options) 816 }, 817 !, 818 html(a(href(Myref), \dom_list(Content, Path, Options))). 819dom_element(span, Att, [CDATA], _, Options) --> 820 { memberchk(class='pred-ext', Att), 821 atom_pi(CDATA, PI), 822 documented(PI), 823 ( option(server(false), Options) 824 -> public_link(predicate(CDATA), HREF) 825 ; http_link_to_id(pldoc_man, [predicate=CDATA], HREF) 826 ) 827 }, 828 !, 829 html(a(href(HREF), CDATA)). 830dom_element(img, Att0, [], Path, _Options) --> 831 { selectchk(src=Src, Att0, Att1), 832 relative_file_name(ImgFile, Path, Src), 833 handler_alias(Handler, DirAlias), 834 absolute_file_name(DirAlias, Dir, 835 [ file_errors(fail), 836 solutions(all), 837 file_type(directory) 838 ]), 839 ensure_slash(Dir, DirS), 840 atom_concat(DirS, NewSrc, ImgFile), 841 !, 842 http_link_to_id(Handler, [], ManRef), 843 directory_file_path(ManRef, NewSrc, NewPath), 844 Begin =.. [img, src(NewPath) | Att1] 845 }, 846 html_begin(Begin), 847 html_end(img). 848dom_element(div, Att, _, _, _) --> 849 { memberchk(class=navigate, Att) }, 850 !. 851dom_element(html, _, Content, Path, Options) --> 852 !, % do not emit a html for the second time 853 dom_list(Content, Path, Options). 854dom_element(head, _, Content, Path, Options) --> 855 !, % do not emit a head for the second time 856 dom_list(Content, Path, Options). 857dom_element(title, _, _, _, _) --> !. 858dom_element(link, _, _, _, _) --> !. 859dom_element(body, _, Content, Path, Options) --> 860 !, % do not emit a body for the second time 861 dom_list(Content, Path, Options). 862dom_element(Name, Attrs, Content, Path, Options) --> 863 { Begin =.. [Name|Attrs] }, 864 html_begin(Begin), 865 dom_list(Content, Path, Options), 866 html_end(Name). 867 868handler_alias(manual_file, swi_man_manual(.)). 869handler_alias(pldoc_package, swi_man_packages(.)). 870 871ensure_slash(Dir, DirS) :- 872 ( sub_atom(Dir, _, _, 0, /) 873 -> DirS = Dir 874 ; atom_concat(Dir, /, DirS) 875 ).
884public_link(predicate(CDATA), HREF) :-
885 uri_encoded(query_value, CDATA, Encoded),
886 atom_concat('https://www.swi-prolog.org/pldoc/doc_for?object=',
887 Encoded, HREF).
894documented(PI) :- 895 manual_object(PI, _, _, _, _), 896 !. 897documented(PI) :- 898 full_object(PI, _Obj).
/man?predicate=PI
.section(Level, NT, ID, FilePath)
section(Level, NT, ID, FilePath)#flag:Name
section(Level, NT, ID, FilePath)#gloss:Name
$ File#Name() Rewrite to /man/CAPI=Name
932rewrite_ref(_Class, Ref, _Path, Ref, Options) :- 933 option(server(false), Options), 934 !. 935rewrite_ref(Class, Ref0, Path, ManRef, _Options) :- 936 rewrite_ref(Class, Ref0, Path, ManRef). 937 938rewrite_ref(pred, Ref0, _, Ref) :- % Predicate/DCG reference 939 sub_atom(Ref0, _, _, A, '#'), 940 !, 941 sub_atom(Ref0, _, A, 0, Fragment), 942 atom_to_object(Fragment, PI), 943 manual_object(PI, _, _, _, _), 944 uri_encoded(query_value, Fragment, Enc), 945 http_location_by_id(pldoc_man, ManHandler), 946 format(string(Ref), '~w?predicate=~w', [ManHandler, Enc]). 947rewrite_ref(function, Ref0, _, Ref) :- % Arithmetic function reference 948 sub_atom(Ref0, _, _, A, '#'), 949 !, 950 sub_atom(Ref0, _, A, 0, Fragment), 951 atom_to_object(Fragment, PI), 952 manual_object(PI, _, _, _, _), 953 PI=f(Name/Arity), 954 format(atom(PIName), '~w/~w', [Name,Arity]), 955 uri_encoded(query_value, PIName, Enc), 956 http_location_by_id(pldoc_man, ManHandler), 957 format(string(Ref), '~w?function=~w', [ManHandler, Enc]). 958rewrite_ref(func, Ref0, _, Ref) :- % C-API reference 959 sub_atom(Ref0, _, _, A, '#'), 960 !, 961 sub_atom(Ref0, _, A, 0, Fragment), 962 atom_to_object(Fragment, Obj), 963 manual_object(Obj, _, _, _, _), 964 Obj = c(Function), 965 uri_encoded(query_value, Function, Enc), 966 http_location_by_id(pldoc_man, ManHandler), 967 format(string(Ref), '~w?CAPI=~w', [ManHandler, Enc]). 968rewrite_ref(sec, Ref0, Path, Ref) :- % Section inside a file 969 sub_atom(Ref0, B, _, A, '#'), 970 !, 971 sub_atom(Ref0, _, A, 0, Fragment), 972 sub_atom(Ref0, 0, B, _, File), 973 referenced_section(Fragment, File, Path, Section), 974 object_href(Section, Ref). 975rewrite_ref(sec, File, Path, Ref) :- % Section is a file 976 file_directory_name(Path, Dir), 977 atomic_list_concat([Dir, /, File], SecPath), 978 Obj = section(_, _, _, SecPath), 979 manual_object(Obj, _, _, _, _), 980 !, 981 object_href(Obj, Ref). 982rewrite_ref(cite, Ref0, Path, Ref) :- % Citation (bit hard-wired) 983 debug(pldoc(cite), 'Cite ref ~q ~q', [Ref0, Path]), 984 sub_atom(Ref0, _, _, A, '#'), 985 !, 986 sub_atom(Ref0, _, A, 0, Fragment), 987 uri_encoded(query_value, Fragment, Enc), 988 http_location_by_id(pldoc_man, ManHandler), 989 format(string(Ref), '~w?section=bibliography#~w', [ManHandler, Enc]). 990rewrite_ref(flag, Ref0, Path, Ref) :- 991 sub_atom(Ref0, B, _, A, '#'), 992 !, 993 sub_atom(Ref0, 0, B, _, File), 994 sub_atom(Ref0, _, A, 0, Fragment), 995 file_directory_name(Path, Dir), 996 atomic_list_concat([Dir, /, File], SecPath), 997 Obj = section(_, _, _, SecPath), 998 manual_object(Obj, _, _, _, _), 999 !, 1000 object_href(Obj, Ref1), 1001 format(string(Ref), '~w#~w', [Ref1, Fragment]). 1002rewrite_ref(gloss, Ref0, Path, Ref) :- 1003 sub_atom(Ref0, B, _, A, '#'), 1004 !, 1005 sub_atom(Ref0, 0, B, _, File), 1006 sub_atom(Ref0, _, A, 0, Fragment), 1007 file_directory_name(Path, Dir), 1008 atomic_list_concat([Dir, /, File], SecPath), 1009 Obj = section(_, _, _, SecPath), 1010 manual_object(Obj, _, _, _, _), 1011 !, 1012 object_href(Obj, Ref1), 1013 format(string(Ref), '~w#~w', [Ref1, Fragment]).
1017referenced_section(Fragment, File, Path, section(Level, Nr, ID, SecPath)) :-
1018 atom_concat('sec:', Nr, Fragment),
1019 ( File == ''
1020 -> SecPath = Path
1021 ; file_directory_name(Path, Dir),
1022 atomic_list_concat([Dir, /, File], SecPath)
1023 ),
1024 manual_object(section(Level, Nr, ID, SecPath), _, _, _, _).
1031man_links(ParentPaths, Options) --> 1032 prolog:doc_page_header(parents(ParentPaths), Options), 1033 !. 1034man_links(ParentPaths, Options) --> 1035 { option(links(true), Options, true), 1036 option(header(true), Options, true) 1037 }, 1038 !, 1039 html([ div(class(navhdr), 1040 [ div(class(jump), \man_parent(ParentPaths)), 1041 div(class(search), \search_form(Options)), 1042 br(clear(right)) 1043 ]), 1044 p([]) 1045 ]). 1046man_links(_, _) --> 1047 []. 1048 1049man_parent(ParentPaths) --> 1050 { maplist(parent_to_section, ParentPaths, [Section|MoreSections]), 1051 maplist(=(Section), MoreSections) 1052 }, 1053 !, 1054 object_ref(Section, [secref_style(number_title)]). 1055man_parent(_) --> []. 1056 1057parent_to_section(X+_, X) :- 1058 X = section(_,_,_,_), 1059 !. 1060parent_to_section(File+_, Section) :- 1061 atom(File), 1062 manual_object(Section, _Title, File, _Class, _Offset), 1063 !.
number
, title
or number_title
.1072section_link(Section, Options) --> 1073 { option(secref_style(Style), Options, number) 1074 }, 1075 section_link(Style, Section, Options). 1076 1077section_link(number, section(_, Number, _, _), _Options) --> 1078 !, 1079 ( {Number == '0'} % Title. Package? 1080 -> [] 1081 ; html(['Sec. ', Number]) 1082 ). 1083section_link(title, Obj, _Options) --> 1084 !, 1085 { manual_object(Obj, Title, _File, _Class, _Offset) 1086 }, 1087 html(Title). 1088section_link(_, Obj, _Options) --> 1089 !, 1090 { Obj = section(_, Number, _, _), 1091 manual_object(Obj, Title, _File, _Class, _Offset) 1092 }, 1093 ( { Number == '0' } 1094 -> html(Title) 1095 ; html([Number, ' ', Title]) 1096 ).
1102function_link(Function, _) --> 1103 html([Function, '()']). 1104 1105 1106 /******************************* 1107 * INDICES & OVERVIEW * 1108 *******************************/
1115man_overview(Options) --> 1116 { http_absolute_location(pldoc_man(.), RefMan, []) 1117 }, 1118 html([ h1('SWI-Prolog documentation'), 1119 blockquote(class(refman_link), 1120 a(href(RefMan), 1121 'SWI-Prolog reference manual')), 1122 \package_overview(Options), 1123 \paperback(Options) 1124 ]). 1125 1126package_overview(Options) --> 1127 html([ h2(class(package_doc_title), 1128 'SWI-Prolog package documentation'), 1129 blockquote(class(package_overview), 1130 \packages(Options)) 1131 ]). 1132 1133packages(Options) --> 1134 { findall(Pkg, current_package(Pkg), Pkgs) 1135 }, 1136 packages(Pkgs, Options). 1137 1138packages([], _) --> 1139 []. 1140packages([Pkg|T], Options) --> 1141 package(Pkg, Options), 1142 packages(T, Options). 1143 1144package(pkg(Title, HREF, HavePackage), Options) --> 1145 { package_class(HavePackage, Class, Options) 1146 }, 1147 html(div(class(Class), 1148 a([href(HREF)], Title))). 1149 1150package_class(true, pkg_link, _). 1151package_class(false, no_pkg_link, _). 1152 1153current_package(pkg(Title, HREF, HavePackage)) :- 1154 manual_object(section(0, _, _, _), Title, File, packages, _), 1155 file_base_name(File, FileNoDir), 1156 file_name_extension(Base, _, FileNoDir), 1157 ( exists_source(library(Base)) 1158 -> HavePackage = true 1159 ; HavePackage = false 1160 ), 1161 http_absolute_location(pldoc_pkg(FileNoDir), HREF, []). 1162 1163 1164:- if(current_predicate(http_handler/3)). 1165:- http_handler(pldoc(jpl), pldoc_jpl, [prefix]). 1166:- http_handler(pldoc_pkg(.), pldoc_package, [prefix]). 1167:- http_handler(pldoc_man(.), pldoc_refman, [prefix]). 1168:- http_handler(pldoc(packages), pldoc_package_overview, []).
1174pldoc_jpl(Request) :-
1175 memberchk(path_info(JPLFile), Request),
1176 atom_concat('doc/packages/jpl', JPLFile, Path),
1177 http_reply_file(swi(Path), [], Request).
1186pldoc_package(Request) :- 1187 ( \+ option(path_info(_), Request) 1188 -> true 1189 ; option(path_info(/), Request) 1190 ), 1191 http_link_to_id(pldoc_object, [object=packages], HREF), 1192 http_redirect(see_other, HREF, Request). 1193pldoc_package(Request) :- 1194 memberchk(path_info(Img), Request), 1195 file_mime_type(Img, image/_), 1196 !, 1197 http_reply_file(swi_man_packages(Img), [], Request). 1198pldoc_package(Request) :- 1199 memberchk(path_info('jpl'), Request), 1200 !, 1201 memberchk(path(Path0), Request), 1202 atom_concat(Path0, /, Path), 1203 http_redirect(moved, Path, Request). 1204pldoc_package(Request) :- 1205 memberchk(path_info(JPLFile), Request), 1206 ( JPLFile == 'jpl/' 1207 -> Path = 'doc/packages/jpl/index.html' 1208 ; sub_atom(JPLFile, 0, _, _, 'jpl/') 1209 -> atom_concat('doc/packages/', JPLFile, Path) 1210 ), 1211 http_reply_file(swi(Path), [], Request). 1212pldoc_package(Request) :- 1213 memberchk(path_info(PkgDoc), Request), 1214 ensure_html_ext(PkgDoc, PkgHtml), 1215 atom_concat('packages/', PkgHtml, Path), 1216 term_to_atom(section(Path), Object), 1217 http_link_to_id(pldoc_object, [object=Object], HREF), 1218 http_redirect(see_other, HREF, Request). 1219 1220ensure_html_ext(Pkg, PkgHtml) :- 1221 file_name_extension(_, html, Pkg), 1222 !, 1223 PkgHtml = Pkg. 1224ensure_html_ext(Pkg, PkgHtml) :- 1225 file_name_extension(Pkg, html, PkgHtml).
1231pldoc_package_overview(_Request) :- 1232 reply_html_page( 1233 pldoc(packages), 1234 title('SWI-Prolog package documentation'), 1235 \package_overview([])). 1236:- endif.
1242paperback(_Options) -->
1243 { expand_url_path(swipl_book(.), HREF)
1244 },
1245 html([ h2('The manual as a book'),
1246 p([ 'A paperback version of the manual is ',
1247 a(href(HREF), 'available'), '.'
1248 ])
1249 ]).
1256pldoc_refman(Request) :- 1257 memberchk(path_info(Section), Request), 1258 \+ sub_atom(Section, _, _, _, /), 1259 Obj = section(0,_,_,_), 1260 manual_object(Obj, Title, File, manual, _), 1261 file_base_name(File, Section), 1262 !, 1263 reply_html_page(pldoc(man), 1264 title(Title), 1265 \object_page(Obj, [])). 1266pldoc_refman(Request) :- % server Contents.html 1267 \+ memberchk(path_info(_), Request), 1268 !, 1269 http_link_to_id(pldoc_object, [object(manual)], HREF), 1270 http_redirect(see_other, HREF, Request). 1271pldoc_refman(Request) :- 1272 memberchk(path(Path), Request), 1273 existence_error(http_location, Path). 1274 1275 1276 /******************************* 1277 * HOOK SEARCH * 1278 *******************************/ 1279 1280prologdoc_object_summary(section(ID), Class, File, Summary) :- 1281 nonvar(ID), % when generating, only do full ones 1282 manual_object(section(_Level, _No, ID, _Path), Summary, File, Class, _Offset). 1283prologdoc_object_summary(Obj, Class, File, Summary) :- 1284 manual_object(Obj, Summary, File, Class, _Offset). 1285 1286prologdoc_object_page(Obj, Options) --> 1287 man_page(Obj, [no_manual(fail),footer(false)|Options]).
1293prologdoc_object_link(Obj, Options) --> 1294 { Obj = section(_,_,_,_) }, 1295 !, 1296 section_link(Obj, Options). 1297prologdoc_object_link(Obj0, Options) --> 1298 { Obj0 = section(ID), 1299 Obj = section(_Level, _No, ID, _Path), 1300 manual_object(Obj, _, _, _, _) 1301 }, 1302 !, 1303 section_link(Obj, Options). 1304prologdoc_object_link(Obj, Options) --> 1305 { Obj = c(Function) }, 1306 !, 1307 function_link(Function, Options). 1308prologdoc_object_link(root, _) --> 1309 !, 1310 html('Documentation'). 1311prologdoc_object_link(manual, _Options) --> 1312 !, 1313 html('Reference manual'). 1314prologdoc_object_link(packages, _) --> 1315 html('Packages'). 1316 1317prologdoc_category(manual, 30, 'Reference Manual'). 1318prologdoc_category(packages, 40, 'Packages'). 1319 1320prologdoc_file_index_header(File, Options) --> 1321 { Section = section(_Level, _No, _ID, File), 1322 manual_object(Section, _Summary, File, _Cat, _Offset) 1323 }, 1324 !, 1325 html(tr(th([colspan(3), class(section)], 1326 [ \object_ref(Section, 1327 [ secref_style(number_title) 1328 | Options 1329 ]) 1330 ]))). 1331 1332prologdoc_object_title(Obj, Title) :- 1333 Obj = section(_,_,_,_), 1334 manual_object(Obj, Title, _, _, _), 1335 !. 1336 1337prologdoc_canonical_object(section(_Level, _No, ID, _Path), 1338 section(ID)).
1344prologdoc_object_href(section(ID), HREF) :- 1345 nonvar(ID), 1346 atom_concat('sec:', Sec, ID), 1347 http_link_to_id(pldoc_man, [section(Sec)], HREF). 1348prologdoc_object_href(section(_Level, _No, ID, _Path), HREF) :- 1349 nonvar(ID), 1350 atom_concat('sec:', Sec, ID), 1351 http_link_to_id(pldoc_man, [section(Sec)], HREF). 1352 1353 /******************************* 1354 * NO HTTP * 1355 *******************************/ 1356 1357:- if(\+current_predicate(http_link_to_id/3)). 1358 1359http_link_to_id(Id, Parameters, HREF) :- 1360 must_be(list, Parameters), 1361 format(atom(Location), '/pldoc/~w', [Id]), 1362 ( Parameters == [] 1363 -> HREF = Location 1364 ; uri_data(path, Components, Location), 1365 uri_query_components(String, Parameters), 1366 uri_data(search, Components, String), 1367 uri_components(HREF, Components) 1368 ). 1369 1370:- endif. 1371 1372 /******************************* 1373 * MESSAGES * 1374 *******************************/ 1375 1376:- multifile prolog:message//1. 1377 1378prologmessage(pldoc(no_section_id(File, Title))) --> 1379 [ 'PlDoc: ~w: no id for section "~w"'-[File, Title] ]. 1380prologmessage(pldoc(duplicate_ids(L))) --> 1381 [ 'PlDoc: duplicate manual section IDs:'-[], nl 1382 ], 1383 duplicate_ids(L). 1384 1385duplicate_ids([]) --> []. 1386duplicate_ids([H|T]) --> duplicate_id(H), duplicate_ids(T). 1387 1388duplicate_id(Id) --> 1389 { findall(File, manual_object(section(_,_,Id,File),_,_,_,_), Files) }, 1390 [ ' ~w: ~p'-[Id, Files], nl ]
Process SWI-Prolog HTML manuals
*/