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-2014, 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_index,
   37	  [ doc_for_dir/2,              % +Dir, +Options
   38	    dir_index//2,               % +Dir, +Options, //
   39	    object_summaries//3,        % +Objs, +Section, +Options, //
   40	    file_index_header//2,       % +File, +Options, //
   41	    doc_links//2,               % +Directory, +Options, //
   42	    doc_file_href/2,            % +File, -HREF
   43	    places_menu//1,             % +Dir, //
   44	    source_directory/1          % ?Directory
   45	  ]).   46:- use_module(doc_process).   47:- use_module(doc_html).   48:- use_module(doc_wiki).   49:- use_module(doc_search).   50:- use_module(doc_util).   51
   52:- if(exists_source(library(doc_http))).   53:- use_module(library(http/http_dispatch)).   54:- use_module(library(doc_http), []).   55:- endif.   56
   57:- use_module(library(http/html_write)).   58:- use_module(library(http/html_head)).   59:- use_module(library(readutil)).   60:- use_module(library(url)).   61:- use_module(library(option)).   62:- use_module(library(lists)).   63:- include(hooks).

Create indexes

*/

   68:- predicate_options(dir_index//2, 2,
   69		     [ directory(atom),
   70		       edit(boolean),
   71		       files(list),
   72		       members(list),
   73		       qualify(boolean),
   74		       title(atom),
   75		       if(oneof([true,loaded])),
   76		       recursive(boolean),
   77		       secref_style(oneof([number, title, number_title])),
   78		       pass_to(doc_links/4, 2)
   79		     ]).   80:- predicate_options(doc_links//2, 2,
   81		     [ files(list),
   82		       pass_to(pldoc_search:search_form/3, 1)
   83		     ]).   84:- predicate_options(file_index_header//2, 2,
   85		     [ directory(any),
   86		       files(list),
   87		       qualify(boolean),
   88		       secref_style(oneof([number, title, number_title])),
   89		       pass_to(pldoc_html:edit_button/4, 2),
   90		       pass_to(pldoc_html:source_button/4, 2)
   91		     ]).   92:- predicate_options(object_summaries//3, 3,
   93		     [ edit(boolean),
   94		       files(list),
   95		       module(atom),
   96		       public(list),
   97		       qualify(boolean),
   98		       secref_style(oneof([number, title, number_title]))
   99		     ]).  100:- predicate_options(doc_for_dir/2, 2, [pass_to(dir_index/4, 2)]).
 doc_for_dir(+Dir, +Options) is det
Write summary index for all files in Dir to Out. The result consists of the README file (if any), a table holding with links to objects and summary sentences and finaly the TODO file (if any).
  109doc_for_dir(DirSpec, Options) :-
  110    absolute_file_name(DirSpec,
  111		       [ file_type(directory),
  112			 access(read)
  113		       ],
  114		       Dir),
  115    (   option(title(Title), Options)
  116    ->  true
  117    ;   file_base_name(Dir, Title)
  118    ),
  119    doc_write_page(
  120	pldoc(dir_index),
  121	title(Title),
  122	\dir_index(Dir, Options),
  123	Options).
  124
  125:- html_meta doc_write_page(+, html, html, +).  126
  127doc_write_page(Style, Head, Body, Options) :-
  128    option(files(_), Options),
  129    !,
  130    phrase(page(Style, Head, Body), HTML),
  131    print_html(HTML).
  132doc_write_page(Style, Head, Body, _) :-
  133    reply_html_page(Style, Head, Body).
 dir_index(+Dir, +Options)//
Create an index for all Prolog files appearing in Dir or in any directory contained in Dir. Options:
members(+Members)
Documented members. See doc_files.pl
title(+Title)
Title to use for the index page
  146dir_index(Dir, Options) -->
  147    { dir_source_files(Dir, Files0, Options),
  148      sort(Files0, Files),
  149      maplist(ensure_doc_objects, Files),
  150      directory_file_path(Dir, 'index.html', File),
  151      b_setval(pldoc_file, File)    % for predref
  152    },
  153    html([ \doc_resources(Options),
  154	   \doc_links(Dir, Options),
  155	   \dir_header(Dir, Options),
  156	   \subdir_links(Dir, Options),
  157	   h2(class([wiki,plfiles]), 'Prolog files'),
  158	   table(class(summary),
  159		 \file_indices(Files, [directory(Dir)|Options])),
  160	   \dir_footer(Dir, Options)
  161	 ]).
 dir_source_files(+Dir, -Files, +Options) is det
Create a list of source-files to be documented as part of Dir.
  167dir_source_files(_, Files, Options) :-
  168    option(members(Members), Options),
  169    !,
  170    findall(F, member(file(F,_Doc), Members), Files).
  171dir_source_files(Dir, Files, Options) :-
  172    directory_source_files(Dir, Files, Options).
 subdir_links(+Dir, +Options)// is det
Create links to subdirectories
  178subdir_links(Dir, Options) -->
  179    { option(members(Members), Options),
  180      findall(SubDir, member(directory(SubDir, _, _, _), Members), SubDirs),
  181      SubDirs \== []
  182    },
  183    html([ h2(class([wiki,subdirs]), 'Sub directories'),
  184	   table(class(subdirs),
  185		 \subdir_link_rows(SubDirs, Dir))
  186	 ]).
  187subdir_links(_, _) --> [].
  188
  189subdir_link_rows([], _) --> [].
  190subdir_link_rows([H|T], Dir) -->
  191    subdir_link_row(H, Dir),
  192    subdir_link_rows(T, Dir).
  193
  194subdir_link_row(Dir, From) -->
  195    { directory_file_path(Dir, 'index.html', Index),
  196      relative_file_name(Index, From, Link),
  197      file_base_name(Dir, Base)
  198    },
  199    html(tr(td(a([class(subdir), href(Link)], ['[dir] ', Base])))).
 dir_header(+Dir, +Options)// is det
Create header for directory. Options:
readme(File)
Include File as introduction to the directory header.
  208dir_header(Dir, Options) -->
  209    wiki_file(Dir, readme, Options),
  210    !.
  211dir_header(Dir, Options) -->
  212    { (   option(title(Title), Options)
  213      ->  true
  214      ;   file_base_name(Dir, Title)
  215      )
  216    },
  217    html(h1(class=dir, Title)).
 dir_footer(+Dir, +Options)// is det
Create footer for directory. The footer contains the TODO file if provided. Options:
todo(File)
Include File as TODO file in the footer.
  227dir_footer(Dir, Options) -->
  228    wiki_file(Dir, todo, Options),
  229    !.
  230dir_footer(_, _) -->
  231    [].
 wiki_file(+Dir, +Type, +Options)// is semidet
Include text from a Wiki text-file.
  237wiki_file(Dir, Type, Options) -->
  238    { (   Opt =.. [Type,WikiFile],
  239	  option(Opt, Options)
  240      ->  true
  241      ;   directory_files(Dir, Files),
  242	  member(File, Files),
  243	  wiki_file_type(Type, Pattern),
  244	  downcase_atom(File, Pattern),
  245	  directory_file_path(Dir, File, WikiFile)
  246      ),
  247      access_file(WikiFile, read),
  248      !,
  249      read_file_to_codes(WikiFile, String, []),
  250      wiki_codes_to_dom(String, [], DOM)
  251    },
  252    pldoc_html:html(DOM).
 wiki_file_type(+Category, -File) is nondet
Declare file pattern names that are included for README and TODO for a directory. Files are matched case-insensitively.
  259wiki_file_type(readme, 'readme').
  260wiki_file_type(readme, 'readme.md').
  261wiki_file_type(readme, 'readme.txt').
  262wiki_file_type(todo,   'todo').
  263wiki_file_type(todo,   'todo.md').
  264wiki_file_type(todo,   'todo.txt').
 file_indices(+Files, +Options)// is det
Provide a file-by-file index of the contents of each member of Files.
  271file_indices([], _) -->
  272    [].
  273file_indices([H|T], Options) -->
  274    file_index(H, Options),
  275    file_indices(T, Options).
 file_index(+File, +Options)// is det
Create an index for File.
  281file_index(File, Options) -->
  282    { doc_summaries(File, Objs0),
  283      module_info(File, ModuleOptions, Options),
  284      doc_hide_private(Objs0, Objs1, ModuleOptions),
  285      sort(Objs1, Objs)
  286    },
  287    html([ \file_index_header(File, Options)
  288	 | \object_summaries(Objs, File, ModuleOptions)
  289	 ]).
  290
  291doc_summaries(File, Objects) :-
  292    xref_current_source(FileSpec),
  293    xref_option(FileSpec, comments(collect)),
  294    !,
  295    Pos = File:0,
  296    findall(doc(Obj,Pos,Summary),
  297	    xref_doc_summary(Obj, Pos, Summary), Objects).
  298doc_summaries(File, Objects) :-
  299    Pos = File:_Line,
  300    findall(doc(Obj,Pos,Summary),
  301	    doc_comment(Obj, Pos, Summary, _), Objects).
  302
  303xref_doc_summary(M:Name/Arity, File:_, Summary) :-
  304    xref_comment(File, Head, Summary, _Comment),
  305    xref_module(File, Module),
  306    strip_module(Module:Head, M, Plain),
  307    functor(Plain, Name, Arity).
 file_index_header(+File, +Options)// is det
Create an entry in a summary-table for File.
  313file_index_header(File, Options) -->
  314    prolog:doc_file_index_header(File, Options),
  315    !.
  316file_index_header(File, Options) -->
  317    { (   option(directory(Dir), Options),
  318	  directory_file_path(Dir, Label, File)
  319      ->  true
  320      ;   file_base_name(File, Label)
  321      ),
  322      doc_file_href(File, HREF, Options)
  323    },
  324    html(tr(th([colspan(3), class(file)],
  325	       [ span(style('float:left'), a(href(HREF), Label)),
  326		 \file_module_title(File),
  327		 span(style('float:right'),
  328		      [ \source_button(File, Options),
  329			\edit_button(File, Options)
  330		      ])
  331	       ]))).
  332
  333file_module_title(File) -->
  334    { (   module_property(M, file(File))
  335      ;   xref_module(File, M)
  336      ),
  337      doc_comment(M:module(Title), _, _, _)
  338    },
  339    !,
  340    html([&(nbsp), ' -- ', Title]).
  341file_module_title(_) -->
  342    [].
 doc_file_href(+File, -HREF, +Options) is det
HREF is reference to documentation of File.
  349doc_file_href(File, HREF, Options) :-
  350    option(directory(Dir), Options),
  351    atom_concat(Dir, Local0, File),
  352    atom_concat(/, Local, Local0),
  353    !,
  354    (   option(files(Map), Options),        % generating files
  355	memberchk(file(File, DocFile), Map)
  356    ->  file_base_name(DocFile, HREF)
  357    ;   HREF = Local
  358    ).
  359doc_file_href(File, HREF, _) :-
  360    doc_file_href(File, HREF).
 doc_file_href(+Path, -HREF) is det
Create a /doc HREF from Path. There are some nasty things we should take care of.
  372doc_file_href(File0, HREF) :-
  373    insert_alias(File0, File),
  374    ensure_slash_start(File, SlashFile),
  375    http_location([path(SlashFile)], Escaped),
  376    http_location_by_id(pldoc_doc, DocRoot),
  377    atom_concat(DocRoot, Escaped, HREF).
 ensure_slash_start(+File0, -File) is det
Ensure File starts with a /. This maps C:/foobar into /C:/foobar, so our paths start with /doc/ again ...
  385ensure_slash_start(File, File) :-
  386    sub_atom(File, 0, _, _, /),
  387    !.
  388ensure_slash_start(File0, File) :-
  389    atom_concat(/, File0, File).
 object_summaries(+Objects, +Section, +Options)// is det
Create entries in a summary table for Objects.
  396object_summaries(Objects, Section, Options) -->
  397    { tag_pub_priv(Objects, Tagged, Options),
  398      keysort(Tagged, Ordered)
  399    },
  400    obj_summaries(Ordered, Section, Options).
  401
  402obj_summaries([], _, _) -->
  403    [].
  404obj_summaries([_Tag-H|T], Section, Options) -->
  405    object_summary(H, Section, Options),
  406    obj_summaries(T, Section, Options).
  407
  408tag_pub_priv([], [], _).
  409tag_pub_priv([H|T0], [Tag-H|T], Options) :-
  410    (   private(H, Options)
  411    ->  Tag = z_private
  412    ;   Tag = a_public
  413    ),
  414    tag_pub_priv(T0, T, Options).
 object_summary(+Object, +Section, +Options)// is det
Create a summary for Object. Summary consists of a link to the Object and a summary text as a table-row.
To be done
- Hacky interface. Do we demand Summary to be in Wiki?
  424object_summary(q(_Q,Obj), Section, Options) -->
  425    { nonvar(Obj) },
  426    !,
  427    object_summary(Obj, Section, Options).
  428object_summary(doc(Obj, _Pos, _Summary), wiki, Options) -->
  429    !,
  430    html(tr(class(wiki),
  431	    [ td(colspan(3), \object_ref(Obj, Options))
  432	    ])).
  433object_summary(doc(Obj, _Pos, Summary), _Section, Options) -->
  434    !,
  435    (   { string_codes(Summary, Codes),
  436	  wiki_codes_to_dom(Codes, [], DOM0),
  437	  strip_leading_par(DOM0, DOM),
  438	  (   private(Obj, Options)
  439	  ->  Class = private               % private definition
  440	  ;   Class = public                % public definition
  441	  )
  442	}
  443    ->  html(tr(class(Class),
  444		[ td(\object_ref(Obj, Options)),
  445		  td(class(summary), DOM),
  446		  td([align(right)],
  447		     span(style('white-space: nowrap'),
  448			  [ \object_source_button(Obj, Options),
  449			    \object_edit_button(Obj, Options)
  450			  ]))
  451		]))
  452    ;   []
  453    ).
  454object_summary(Obj, Section, Options) -->
  455    { prolog:doc_object_summary(Obj, _Cat, Section, Summary)
  456    },
  457    !,
  458    object_summary(doc(Obj, _, Summary), Section, Options).
  459object_summary(_, _, _) -->
  460    [].
  461
  462
  463		 /*******************************
  464		 *          NAVIGATION          *
  465		 *******************************/
 doc_links(+Directory, +Options)// is det
Provide overview links and search facilities.
  471doc_links(_Directory, Options) -->
  472    { option(files(_), Options), !
  473    }.
  474doc_links(Directory, Options) -->
  475    prolog:doc_links(Directory, Options),
  476    !,
  477    { option(html_resources(Resoures), Options, pldoc) },
  478    html_requires(Resoures).
  479doc_links(Directory, Options) -->
  480    {   (   Directory == ''
  481	->  working_directory(Dir, Dir)
  482	;   Dir = Directory
  483	),
  484	option(html_resources(Resoures), Options, pldoc)
  485    },
  486    html([ \html_requires(Resoures),
  487	   div(class(navhdr),
  488	       [ div(class(jump),
  489		      div([ \places_menu(Dir),
  490			    \plversion
  491			  ])),
  492		 div(class(search), \search_form(Options)),
  493		 br(clear(right))
  494	       ])
  495	 ]).
 version// is det
Prolog version
  502plversion -->
  503    { current_prolog_flag(version_data, swi(Major, Minor, Patch, _))
  504    },
  505    !,
  506    html(a([ class(prolog_version),
  507	     href('http://www.swi-prolog.org')
  508	   ],
  509	   [' SWI-Prolog ', Major, '.', Minor, '.', Patch])).
  510
  511plversion -->
  512    { current_prolog_flag(version_data, yap(Major, Minor, Patch, _))
  513    },
  514    html(a([ class(prolog_version),
  515	     href('http://www.dcc.fc.up.pt/~vsc')
  516	   ],
  517	   [' YAP ', Major, '.', Minor, '.', Patch])).
 places_menu(Current)// is det
Create a select menu with entries for all loaded directories
  524places_menu(Dir) -->
  525    prolog:doc_places_menu(Dir),
  526    !.
  527places_menu(Dir) -->
  528    { findall(D, source_directory(D), List),
  529      sort(List, Dirs)
  530    },
  531    html(form([ action(location_by_id(go_place))
  532	      ],
  533	      [ input([type(submit), value('Go')]),
  534		select(name(place),
  535		       \packs_source_dirs(Dirs, Dir))
  536	      ])).
  537
  538packs_source_dirs(Dirs, Dir) -->
  539    packs_link,
  540    source_dirs(Dirs, Dir).
  541
  542source_dirs([], _) -->
  543    [].
  544source_dirs([H|T], WD) -->
  545    { (   H == WD
  546      ->  Attrs = [selected]
  547      ;   Attrs = []
  548      ),
  549      format(string(IndexFile), '~w/index.html', [H]),
  550      doc_file_href(IndexFile, HREF),
  551      format(string(Call), 'document.location=\'~w\';', [HREF])
  552    },
  553    html(option([onClick(Call)|Attrs], H)),
  554    source_dirs(T, WD).
  555
  556packs_link -->
  557    { pack_property(_,_),
  558      !,
  559      http_link_to_id(pldoc_pack, [], HREF),
  560      format(atom(Call), 'document.location=\'~w\';', [HREF])
  561    },
  562    html(option([ class(packs),
  563		  onClick(Call),
  564		  value(':packs:')
  565		],
  566		'List extension packs')).
  567packs_link -->
  568    [].
 source_directory(+Dir) is semidet
source_directory(-Dir) is nondet
True if Dir is a directory from which we have loaded Prolog sources.
  576source_directory(Dir) :-
  577    (   ground(Dir)
  578    ->  '$time_source_file'(File, _Time1, _System1),
  579	file_directory_name(File, Dir), !
  580    ;   '$time_source_file'(File, _Time2, _System2),
  581	file_directory_name(File, Dir)
  582    )