View source with raw comments or as raw
    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-2017, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(pldoc_http,
   37          [ doc_enable/1,               % +Boolean
   38            doc_server/1,               % ?Port
   39            doc_server/2,               % ?Port, +Options
   40            doc_browser/0,
   41            doc_browser/1               % +What
   42          ]).   43:- use_module(library(pldoc)).   44:- if(exists_source(library(http/thread_httpd))).   45:- use_module(library(http/thread_httpd)).   46:- endif.   47:- use_module(library(http/http_parameters)).   48:- use_module(library(http/html_write)).   49:- use_module(library(http/mimetype)).   50:- use_module(library(dcg/basics)).   51:- use_module(library(http/http_dispatch)).   52:- use_module(library(http/http_hook)).   53:- use_module(library(http/http_path)).   54:- use_module(library(http/http_wrapper)).   55:- use_module(library(uri)).   56:- use_module(library(debug)).   57:- use_module(library(lists)).   58:- use_module(library(url)).   59:- use_module(library(socket)).   60:- use_module(library(option)).   61:- use_module(library(error)).   62:- use_module(library(www_browser)).   63:- use_module(pldoc(doc_process)).   64:- use_module(pldoc(doc_htmlsrc)).   65:- use_module(pldoc(doc_html)).   66:- use_module(pldoc(doc_index)).   67:- use_module(pldoc(doc_search)).   68:- use_module(pldoc(doc_man)).   69:- use_module(pldoc(doc_wiki)).   70:- use_module(pldoc(doc_util)).   71:- use_module(pldoc(doc_access)).   72:- use_module(pldoc(doc_pack)).   73:- use_module(pldoc(man_index)).

Documentation server

The module library(pldoc/http) provides an embedded HTTP documentation server that allows for browsing the documentation of all files loaded after library(pldoc) has been loaded. */

   82:- dynamic
   83    doc_server_port/1,
   84    doc_enabled/0.   85
   86http:location(pldoc, root(pldoc), []).
   87http:location(pldoc_man, pldoc(refman), []).
   88http:location(pldoc_pkg, pldoc(package), []).
   89http:location(pldoc_resource, Path, []) :-
   90    http_location_by_id(pldoc_resource, Path).
 doc_enable(+Boolean)
Actually activate the PlDoc server. Merely loading the server does not do so to avoid incidental loading in a user HTTP server making the documentation available.
   98doc_enable(true) :-
   99    (   doc_enabled
  100    ->  true
  101    ;   assertz(doc_enabled)
  102    ).
  103doc_enable(false) :-
  104    retractall(doc_enabled).
 doc_server(?Port) is det
 doc_server(?Port, +Options) is det
Start a documentation server in the current Prolog process. The server is started in a separate thread. Options are handed to http_server/2. In addition, the following options are recognised:
allow(HostOrIP)
Allow connections from HostOrIP. If HostOrIP is an atom it is matched to the hostname. It if starts with a ., suffix match is done, matching the domain. Finally it can be a term ip(A,B,C,D). See tcp_host_to_address/2 for details.
deny(HostOrIP)
See allow(HostOrIP).
edit(Bool)
Allow editing from localhost connections? Default: true.

The predicate doc_server/1 is defined as below, which provides a good default for development.

doc_server(Port) :-
        doc_server(Port,
                   [ allow(localhost)
                   ]).
See also
- doc_browser/1
  140doc_server(Port) :-
  141    doc_server(Port,
  142               [ allow(localhost),
  143                 allow(ip(127,0,0,1)) % Windows ip-->host often fails
  144               ]).
  145
  146doc_server(Port, _) :-
  147    doc_enable(true),
  148    catch(doc_current_server(Port), _, fail),
  149    !.
  150:- if(current_predicate(http_server/2)).  151doc_server(Port, Options) :-
  152    doc_enable(true),
  153    prepare_editor,
  154    host_access_options(Options, ServerOptions),
  155    http_absolute_location(pldoc('.'), Entry, []),
  156    merge_options(ServerOptions,
  157                  [ port(Port),
  158                    entry_page(Entry)
  159                  ], HTTPOptions),
  160    http_server(http_dispatch, HTTPOptions),
  161    assertz(doc_server_port(Port)).
  162:- endif.
 doc_current_server(-Port) is det
TCP/IP port of the documentation server. Fails if no server is running. Note that in the current infrastructure we can easily be embedded into another Prolog HTTP server. If we are not started from doc_server/2, we return the port of a running HTTP server.
Errors
- existence_error(http_server, pldoc)
To be done
- Trap destruction of the server.
  175doc_current_server(Port) :-
  176    (   doc_server_port(P)
  177    ->  Port = P
  178    ;   http_current_server(_:_, P)
  179    ->  Port = P
  180    ;   existence_error(http_server, pldoc)
  181    ).
  182
  183:- if(\+current_predicate(http_current_server/2)).  184http_current_server(_,_) :- fail.
  185:- endif.
 doc_browser is det
 doc_browser(+What) is semidet
Open user's default browser on the documentation server.
  192doc_browser :-
  193    doc_browser([]).
  194doc_browser(Spec) :-
  195    catch(doc_current_server(Port),
  196          error(existence_error(http_server, pldoc), _),
  197          doc_server(Port)),
  198    browser_url(Spec, Request),
  199    format(string(URL), 'http://localhost:~w~w', [Port, Request]),
  200    www_open_url(URL).
  201
  202browser_url([], Root) :-
  203    !,
  204    http_location_by_id(pldoc_root, Root).
  205browser_url(Name, URL) :-
  206    atom(Name),
  207    !,
  208    browser_url(Name/_, URL).
  209browser_url(Name//Arity, URL) :-
  210    must_be(atom, Name),
  211    integer(Arity),
  212    !,
  213    PredArity is Arity+2,
  214    browser_url(Name/PredArity, URL).
  215browser_url(Name/Arity, URL) :-
  216    !,
  217    must_be(atom, Name),
  218    (   man_object_property(Name/Arity, summary(_))
  219    ->  format(string(S), '~q/~w', [Name, Arity]),
  220        http_link_to_id(pldoc_man, [predicate=S], URL)
  221    ;   browser_url(_:Name/Arity, URL)
  222    ).
  223browser_url(Spec, URL) :-
  224    !,
  225    Spec = M:Name/Arity,
  226    doc_comment(Spec, _Pos, _Summary, _Comment),
  227    !,
  228    (   var(M)
  229    ->  format(string(S), '~q/~w', [Name, Arity])
  230    ;   format(string(S), '~q:~q/~w', [M, Name, Arity])
  231    ),
  232    http_link_to_id(pldoc_object, [object=S], URL).
 prepare_editor
Start XPCE as edit requests comming from the document server can only be handled if XPCE is running.
  239prepare_editor :-
  240    current_prolog_flag(editor, pce_emacs),
  241    !,
  242    start_emacs.
  243prepare_editor.
  244
  245
  246                 /*******************************
  247                 *          USER REPLIES        *
  248                 *******************************/
  249
  250:- http_handler(pldoc(.),          pldoc_root,
  251                [ prefix,
  252                  authentication(pldoc(read)),
  253                  condition(doc_enabled)
  254                ]).  255:- http_handler(pldoc('index.html'), pldoc_index,   []).  256:- http_handler(pldoc(file),       pldoc_file,     []).  257:- http_handler(pldoc(place),      go_place,       []).  258:- http_handler(pldoc(edit),       pldoc_edit,
  259                [authentication(pldoc(edit))]).  260:- http_handler(pldoc(doc),        pldoc_doc,      [prefix]).  261:- http_handler(pldoc(man),        pldoc_man,      []).  262:- http_handler(pldoc(doc_for),    pldoc_object,   [id(pldoc_doc_for)]).  263:- http_handler(pldoc(search),     pldoc_search,   []).  264:- http_handler(pldoc('res/'),     pldoc_resource, [prefix]).
 pldoc_root(+Request)
Reply using the index-page of the Prolog working directory. There are various options for the start directory. For example we could also use the file or directory of the file that would be edited using edit/0.
  274pldoc_root(Request) :-
  275    http_parameters(Request,
  276                    [ empty(Empty, [ oneof([true,false]),
  277                                     default(false)
  278                                   ])
  279                    ]),
  280    pldoc_root(Request, Empty).
  281
  282pldoc_root(Request, false) :-
  283    http_location_by_id(pldoc_root, Root),
  284    memberchk(path(Path), Request),
  285    Root \== Path,
  286    !,
  287    existence_error(http_location, Path).
  288pldoc_root(_Request, false) :-
  289    working_directory(Dir0, Dir0),
  290    allowed_directory(Dir0),
  291    !,
  292    ensure_slash_end(Dir0, Dir1),
  293    doc_file_href(Dir1, Ref0),
  294    atom_concat(Ref0, 'index.html', Index),
  295    throw(http_reply(see_other(Index))).
  296pldoc_root(Request, _) :-
  297    pldoc_index(Request).
 pldoc_index(+Request)
HTTP handle for /index.html, providing an overall overview of the available documentation.
  305pldoc_index(_Request) :-
  306    reply_html_page(pldoc(index),
  307                    title('SWI-Prolog documentation'),
  308                    [ \doc_links('', []),
  309                       h1('SWI-Prolog documentation'),
  310                      \man_overview([])
  311                    ]).
 pldoc_file(+Request)
Hander for /file?file=File, providing documentation for File.
  318pldoc_file(Request) :-
  319    http_parameters(Request,
  320                    [ file(File, [])
  321                    ]),
  322    (   source_file(File)
  323    ->  true
  324    ;   throw(http_reply(forbidden(File)))
  325    ),
  326    doc_for_file(File, []).
 pldoc_edit(+Request)
HTTP handler that starts the user's default editor on the host running the server. This handler can only accessed if the browser connection originates from localhost. The call can edit files using the file attribute or a predicate if both name and arity is given and optionally module.
  336pldoc_edit(Request) :-
  337    http:authenticate(pldoc(edit), Request, _),
  338    http_parameters(Request,
  339                    [ file(File,
  340                           [ optional(true),
  341                             description('Name of the file to edit')
  342                           ]),
  343                      line(Line,
  344                           [ optional(true),
  345                             integer,
  346                             description('Line in the file')
  347                           ]),
  348                      name(Name,
  349                           [ optional(true),
  350                             description('Name of a Prolog predicate to edit')
  351                           ]),
  352                      arity(Arity,
  353                            [ integer,
  354                              optional(true),
  355                              description('Arity of a Prolog predicate to edit')
  356                            ]),
  357                      module(Module,
  358                             [ optional(true),
  359                               description('Name of a Prolog module to search for predicate')
  360                             ])
  361                    ]),
  362    (   atom(File)
  363    ->  allowed_file(File)
  364    ;   true
  365    ),
  366    (   atom(File), integer(Line)
  367    ->  Edit = file(File, line(Line))
  368    ;   atom(File)
  369    ->  Edit = file(File)
  370    ;   atom(Name), integer(Arity)
  371    ->  (   atom(Module)
  372        ->  Edit = (Module:Name/Arity)
  373        ;   Edit = (Name/Arity)
  374        )
  375    ),
  376    edit(Edit),
  377    format('Content-type: text/plain~n~n'),
  378    format('Started ~q~n', [edit(Edit)]).
  379pldoc_edit(_Request) :-
  380    http_location_by_id(pldoc_edit, Location),
  381    throw(http_reply(forbidden(Location))).
 go_place(+Request)
HTTP handler to handle the places menu.
  388go_place(Request) :-
  389    http_parameters(Request,
  390                    [ place(Place, [])
  391                    ]),
  392    places(Place).
  393
  394places(':packs:') :-
  395    !,
  396    http_link_to_id(pldoc_pack, [], HREF),
  397    throw(http_reply(moved(HREF))).
  398places(Dir0) :-
  399    expand_alias(Dir0, Dir),
  400    (   allowed_directory(Dir)
  401    ->  format(string(IndexFile), '~w/index.html', [Dir]),
  402        doc_file_href(IndexFile, HREF),
  403        throw(http_reply(moved(HREF)))
  404    ;   throw(http_reply(forbidden(Dir)))
  405    ).
 allowed_directory(+Dir) is semidet
True if we are allowed to produce and index for Dir.
  412allowed_directory(Dir) :-
  413    source_directory(Dir),
  414    !.
  415allowed_directory(Dir) :-
  416    working_directory(CWD, CWD),
  417    same_file(CWD, Dir).
  418allowed_directory(Dir) :-
  419    prolog:doc_directory(Dir).
 allowed_file(+File) is semidet
True if we are allowed to serve File. Currently means we have predicates loaded from File or the directory must be allowed.
  427allowed_file(File) :-
  428    source_file(_, File),
  429    !.
  430allowed_file(File) :-
  431    absolute_file_name(File, Canonical),
  432    file_directory_name(Canonical, Dir),
  433    allowed_directory(Dir).
 pldoc_resource(+Request)
Handler for /res/File, serving CSS, JS and image files.
  440pldoc_resource(Request) :-
  441    http_location_by_id(pldoc_resource, ResRoot),
  442    memberchk(path(Path), Request),
  443    atom_concat(ResRoot, File, Path),
  444    file(File, Local),
  445    http_reply_file(pldoc(Local), [], Request).
  446
  447file('pldoc.css',     'pldoc.css').
  448file('pllisting.css', 'pllisting.css').
  449file('pldoc.js',      'pldoc.js').
  450file('edit.png',      'edit.png').
  451file('editpred.png',  'editpred.png').
  452file('up.gif',        'up.gif').
  453file('source.png',    'source.png').
  454file('public.png',    'public.png').
  455file('private.png',   'private.png').
  456file('reload.png',    'reload.png').
  457file('favicon.ico',   'favicon.ico').
  458file('h1-bg.png',     'h1-bg.png').
  459file('h2-bg.png',     'h2-bg.png').
  460file('pub-bg.png',    'pub-bg.png').
  461file('priv-bg.png',   'priv-bg.png').
  462file('multi-bg.png',  'multi-bg.png').
 pldoc_doc(+Request)
Handler for /doc/Path

Reply documentation of a file. Path is the absolute path of the file for which to return the documentation. Extension is either none, the Prolog extension or the HTML extension.

Note that we reply with pldoc.css if the file basename is pldoc.css to allow for a relative link from any directory.

  476pldoc_doc(Request) :-
  477    memberchk(path(ReqPath), Request),
  478    http_location_by_id(pldoc_doc, Me),
  479    atom_concat(Me, AbsFile0, ReqPath),
  480    (   sub_atom(ReqPath, _, _, 0, /)
  481    ->  atom_concat(ReqPath, 'index.html', File),
  482        throw(http_reply(moved(File)))
  483    ;   clean_path(AbsFile0, AbsFile1),
  484        expand_alias(AbsFile1, AbsFile),
  485        is_absolute_file_name(AbsFile)
  486    ->  documentation(AbsFile, Request)
  487    ).
  488
  489documentation(Path, Request) :-
  490    file_base_name(Path, Base),
  491    file(_, Base),                         % serve pldoc.css, etc.
  492    !,
  493    http_reply_file(pldoc(Base), [], Request).
  494documentation(Path, Request) :-
  495    file_name_extension(_, Ext, Path),
  496    autolink_extension(Ext, image),
  497    http_reply_file(Path, [unsafe(true)], Request).
  498documentation(Path, Request) :-
  499    Index = '/index.html',
  500    sub_atom(Path, _, _, 0, Index),
  501    atom_concat(Dir, Index, Path),
  502    exists_directory(Dir),                 % Directory index
  503    !,
  504    (   allowed_directory(Dir)
  505    ->  edit_options(Request, EditOptions),
  506        doc_for_dir(Dir, EditOptions)
  507    ;   throw(http_reply(forbidden(Dir)))
  508    ).
  509documentation(File, Request) :-
  510    wiki_file(File, WikiFile),
  511    !,
  512    (   allowed_file(WikiFile)
  513    ->  true
  514    ;   throw(http_reply(forbidden(File)))
  515    ),
  516    edit_options(Request, Options),
  517    doc_for_wiki_file(WikiFile, Options).
  518documentation(Path, Request) :-
  519    pl_file(Path, File),
  520    !,
  521    (   allowed_file(File)
  522    ->  true
  523    ;   throw(http_reply(forbidden(File)))
  524    ),
  525    doc_reply_file(File, Request).
  526documentation(Path, _) :-
  527    throw(http_reply(not_found(Path))).
  528
  529:- public
  530    doc_reply_file/2.  531
  532doc_reply_file(File, Request) :-
  533    http_parameters(Request,
  534                    [ public_only(Public),
  535                      reload(Reload),
  536                      show(Show),
  537                      format_comments(FormatComments)
  538                    ],
  539                    [ attribute_declarations(param)
  540                    ]),
  541    (   exists_file(File)
  542    ->  true
  543    ;   throw(http_reply(not_found(File)))
  544    ),
  545    (   Reload == true,
  546        source_file(File)
  547    ->  load_files(File, [if(changed), imports([])])
  548    ;   true
  549    ),
  550    edit_options(Request, EditOptions),
  551    (   Show == src
  552    ->  format('Content-type: text/html~n~n', []),
  553        source_to_html(File, stream(current_output),
  554                       [ skin(src_skin(Request, Show, FormatComments)),
  555                         format_comments(FormatComments)
  556                       ])
  557    ;   Show == raw
  558    ->  http_reply_file(File,
  559                        [ unsafe(true), % is already validated
  560                          mime_type(text/plain)
  561                        ], Request)
  562    ;   doc_for_file(File,
  563                     [ public_only(Public),
  564                       source_link(true)
  565                     | EditOptions
  566                     ])
  567    ).
  568
  569
  570:- public src_skin/5.                   % called through source_to_html/3.
  571
  572src_skin(Request, _Show, FormatComments, header, Out) :-
  573    memberchk(request_uri(ReqURI), Request),
  574    negate(FormatComments, AltFormatComments),
  575    replace_parameters(ReqURI, [show(raw)], RawLink),
  576    replace_parameters(ReqURI, [format_comments(AltFormatComments)], CmtLink),
  577    phrase(html(div(class(src_formats),
  578                    [ 'View source with ',
  579                      a(href(CmtLink), \alt_view(AltFormatComments)),
  580                      ' or as ',
  581                      a(href(RawLink), raw)
  582                    ])), Tokens),
  583    print_html(Out, Tokens).
  584
  585alt_view(true) -->
  586    html('formatted comments').
  587alt_view(false) -->
  588    html('raw comments').
  589
  590negate(true, false).
  591negate(false, true).
  592
  593replace_parameters(ReqURI, Extra, URI) :-
  594    uri_components(ReqURI, C0),
  595    uri_data(search, C0, Search0),
  596    (   var(Search0)
  597    ->  uri_query_components(Search, Extra)
  598    ;   uri_query_components(Search0, Form0),
  599        merge_options(Extra, Form0, Form),
  600        uri_query_components(Search, Form)
  601    ),
  602    uri_data(search, C0, Search, C),
  603    uri_components(URI, C).
 edit_options(+Request, -Options) is det
Return edit(true) in Options if the connection is from the localhost.
  611edit_options(Request, [edit(true)]) :-
  612    catch(http:authenticate(pldoc(edit), Request, _), _, fail),
  613    !.
  614edit_options(_, []).
 pl_file(+File, -PlFile) is semidet
  619pl_file(File, PlFile) :-
  620    file_name_extension(Base, html, File),
  621    !,
  622    absolute_file_name(Base,
  623                       PlFile,
  624                       [ file_errors(fail),
  625                         file_type(prolog),
  626                         access(read)
  627                       ]).
  628pl_file(File, File).
 wiki_file(+File, -TxtFile) is semidet
True if TxtFile is an existing file that must be served as wiki file.
  635wiki_file(File, TxtFile) :-
  636    file_name_extension(_, Ext, File),
  637    wiki_file_extension(Ext),
  638    !,
  639    TxtFile = File.
  640wiki_file(File, TxtFile) :-
  641    file_base_name(File, Base),
  642    autolink_file(Base, wiki),
  643    !,
  644    TxtFile = File.
  645wiki_file(File, TxtFile) :-
  646    file_name_extension(Base, html, File),
  647    wiki_file_extension(Ext),
  648    file_name_extension(Base, Ext, TxtFile),
  649    access_file(TxtFile, read).
  650
  651wiki_file_extension(md).
  652wiki_file_extension(txt).
 clean_path(+AfterDoc, -AbsPath)
Restore the path, Notably deals Windows issues
  659clean_path(Path0, Path) :-
  660    current_prolog_flag(windows, true),
  661    sub_atom(Path0, 2, _, _, :),
  662    !,
  663    sub_atom(Path0, 1, _, 0, Path).
  664clean_path(Path, Path).
 pldoc_man(+Request)
Handler for /man, offering one of the parameters:
predicate=PI
providing documentation from the manual on the predicate PI.
function=PI
providing documentation from the manual on the function PI.
CAPI=F
providing documentation from the manual on the C-function F.
  678pldoc_man(Request) :-
  679    http_parameters(Request,
  680                    [ predicate(PI, [optional(true)]),
  681                      function(Fun, [optional(true)]),
  682                      'CAPI'(F,     [optional(true)]),
  683                      section(Sec,  [optional(true)])
  684                    ]),
  685    (   ground(PI)
  686    ->  atom_pi(PI, Obj)
  687    ;   ground(Fun)
  688    ->  atomic_list_concat([Name,ArityAtom], /, Fun),
  689        atom_number(ArityAtom, Arity),
  690        Obj = f(Name/Arity)
  691    ;   ground(F)
  692    ->  Obj = c(F)
  693    ;   ground(Sec)
  694    ->  atom_concat('sec:', Sec, SecID),
  695        Obj = section(SecID)
  696    ),
  697    man_title(Obj, Title),
  698    reply_html_page(
  699        pldoc(object(Obj)),
  700        title(Title),
  701        \man_page(Obj, [])).
  702
  703man_title(f(Obj), Title) :-
  704    !,
  705    format(atom(Title), 'SWI-Prolog -- function ~w', [Obj]).
  706man_title(c(Obj), Title) :-
  707    !,
  708    format(atom(Title), 'SWI-Prolog -- API-function ~w', [Obj]).
  709man_title(section(_Id), Title) :-
  710    !,
  711    format(atom(Title), 'SWI-Prolog -- Manual', []).
  712man_title(Obj, Title) :-
  713    format(atom(Title), 'SWI-Prolog -- ~w', [Obj]).
 pldoc_object(+Request)
Handler for /doc_for?object=Term, Provide documentation for the given term.
  720pldoc_object(Request) :-
  721    http_parameters(Request,
  722                    [ object(Atom, []),
  723                      header(Header, [default(true)])
  724                    ]),
  725    (   catch(atom_to_term(Atom, Obj, _), error(_,_), fail)
  726    ->  true
  727    ;   atom_to_object(Atom, Obj)
  728    ),
  729    (   prolog:doc_object_title(Obj, Title)
  730    ->  true
  731    ;   Title = Atom
  732    ),
  733    edit_options(Request, EditOptions),
  734    reply_html_page(
  735        pldoc(object(Obj)),
  736        title(Title),
  737        \object_page(Obj, [header(Header)|EditOptions])).
 pldoc_search(+Request)
Search the collected PlDoc comments and Prolog manual.
  744pldoc_search(Request) :-
  745    http_parameters(Request,
  746                    [ for(For,
  747                          [ optional(true),
  748                            description('String to search for')
  749                          ]),
  750                      page(Page,
  751                           [ integer,
  752                             default(1),
  753                             description('Page of search results to view')
  754                           ]),
  755                      in(In,
  756                         [ oneof([all,app,noapp,man,lib,pack,wiki]),
  757                           default(all),
  758                           description('Search everying, application only or manual only')
  759                         ]),
  760                      match(Match,
  761                            [ oneof([name,summary]),
  762                              default(summary),
  763                              description('Match only the name or also the summary')
  764                            ]),
  765                      resultFormat(Format,
  766                                   [ oneof(long,summary),
  767                                     default(summary),
  768                                     description('Return full documentation or summary-lines')
  769                                   ])
  770                    ]),
  771    edit_options(Request, EditOptions),
  772    format(string(Title), 'Prolog search -- ~w', [For]),
  773    reply_html_page(pldoc(search(For)),
  774                    title(Title),
  775                    \search_reply(For,
  776                                  [ resultFormat(Format),
  777                                    search_in(In),
  778                                    search_match(Match),
  779                                    page(Page)
  780                                  | EditOptions
  781                                  ])).
  782
  783
  784                 /*******************************
  785                 *     HTTP PARAMETER TYPES     *
  786                 *******************************/
  787
  788:- public
  789    param/2.                        % used in pack documentation server
  790
  791param(public_only,
  792      [ boolean,
  793        default(true),
  794        description('If true, hide private predicates')
  795      ]).
  796param(reload,
  797      [ boolean,
  798        default(false),
  799        description('Reload the file and its documentation')
  800      ]).
  801param(show,
  802      [ oneof([doc,src,raw]),
  803        default(doc),
  804        description('How to show the file')
  805      ]).
  806param(format_comments,
  807      [ boolean,
  808        default(true),
  809        description('If true, use PlDoc for rendering structured comments')
  810      ])