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)  2007-2015, 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_latex,
   37          [ doc_latex/3,                % +Items, +OutFile, +Options
   38            latex_for_file/3,           % +FileSpec, +Out, +Options
   39            latex_for_wiki_file/3,      % +FileSpec, +Out, +Options
   40            latex_for_predicates/3      % +PI, +Out, +Options
   41          ]).   42:- use_module(library(pldoc)).   43:- use_module(library(readutil)).   44:- use_module(library(error)).   45:- use_module(library(apply)).   46:- use_module(library(option)).   47:- use_module(library(lists)).   48:- use_module(library(debug)).   49:- use_module(pldoc(doc_wiki)).   50:- use_module(pldoc(doc_process)).   51:- use_module(pldoc(doc_modes)).   52:- use_module(pldoc(doc_html),          % we cannot import all as the
   53              [ doc_file_objects/5,     % \commands have the same name
   54                unquote_filespec/2,
   55                doc_tag_title/2,
   56                existing_linked_file/2,
   57                pred_anchor_name/3,
   58                private/2,
   59                (multifile)/2,
   60                is_pi/1,
   61                is_op_type/2
   62              ]).

PlDoc LaTeX backend

This module translates the Herbrand term from the documentation extracting module doc_wiki.pl into a LaTeX document for us with the pl.sty LaTeX style file. The function of this module is very similar to doc_html.pl, providing the HTML backend, and the implementation follows the same paradigm. The module can

author
- Jan Wielemaker */
To be done
- See TODO
   85:- predicate_options(doc_latex/3, 3,
   86                     [ stand_alone(boolean),
   87                       public_only(boolean),
   88                       section_level(oneof([section,subsection,subsubsection])),
   89                       summary(atom)
   90                     ]).   91:- predicate_options(latex_for_file/3, 3,
   92                     [ stand_alone(boolean),
   93                       public_only(boolean),
   94                       section_level(oneof([section,subsection,subsubsection]))
   95                     ]).   96:- predicate_options(latex_for_predicates/3, 3,
   97                     [                          % no options
   98                     ]).   99:- predicate_options(latex_for_wiki_file/3, 3,
  100                     [ stand_alone(boolean),
  101                       public_only(boolean),
  102                       section_level(oneof([section,subsection,subsubsection]))
  103                     ]).  104
  105
  106:- thread_local
  107    options/1,
  108    documented/1.  109
  110current_options(Options) :-
  111    options(Current),
  112    !,
  113    Options = Current.
  114current_options([]).
 doc_latex(+Spec, +OutFile, +Options) is det
Process one or more objects, writing the LaTeX output to OutFile. Spec is one of:
Name / Arity
Generate documentation for predicate
Name // Arity
Generate documentation for DCG rule
File
If File is a prolog file (as defined by prolog_file_type/2), process using latex_for_file/3, otherwise process using latex_for_wiki_file/3.

Typically Spec is either a list of filenames or a list of predicate indicators. Defined options are:

stand_alone(+Bool)
If true (default), create a document that can be run through LaTeX. If false, produce a document to be included in another LaTeX document.
public_only(+Bool)
If true (default), only emit documentation for exported predicates.
section_level(+Level)
Outermost section level produced. Level is the name of a LaTeX section command. Default is section.
summary(+File)
Write summary declarations to the named File.
modules(+List)
If [[Name/Arity]] needs to be resolved, search for the predicates in the given modules.
module(+Module)
Same as modules([Module]).
  152doc_latex(Spec, OutFile, Options) :-
  153    load_urldefs,
  154    merge_options(Options,
  155                  [ include_reexported(true)
  156                  ],
  157                  Options1),
  158    retractall(documented(_)),
  159    setup_call_cleanup(
  160        asserta(options(Options), Ref),
  161        phrase(process_items(Spec, [body], Options1), Tokens),
  162        erase(Ref)),
  163    setup_call_cleanup(
  164        open(OutFile, write, Out),
  165        print_latex(Out, Tokens, Options1),
  166        close(Out)),
  167    latex_summary(Options).
  168
  169process_items([], Mode, _) -->
  170    !,
  171    pop_mode(body, Mode, _).
  172process_items([H|T], Mode, Options) -->
  173    process_items(H, Mode, Mode1, Options),
  174    process_items(T, Mode1, Options).
  175process_items(Spec, Mode, Options) -->
  176    {Mode = [Mode0|_]},
  177    process_items(Spec, Mode, Mode1, Options),
  178    pop_mode(Mode0, Mode1, _).
  179
  180process_items(PI, Mode0, Mode, Options) -->
  181    { is_pi(PI) },
  182    !,
  183    need_mode(description, Mode0, Mode),
  184    latex_tokens_for_predicates(PI, Options).
  185process_items(FileSpec, Mode0, Mode, Options) -->
  186    {   (   absolute_file_name(FileSpec,
  187                               [ file_type(prolog),
  188                                 access(read),
  189                                 file_errors(fail)
  190                               ],
  191                               File)
  192        ->  true
  193        ;   absolute_file_name(FileSpec,
  194                               [ access(read)
  195                               ],
  196                               File)
  197        ),
  198        file_name_extension(_Base, Ext, File)
  199    },
  200    need_mode(body, Mode0, Mode),
  201    (   { user:prolog_file_type(Ext, prolog) }
  202    ->  latex_tokens_for_file(File, Options)
  203    ;   latex_tokens_for_wiki_file(File, Options)
  204    ).
 latex_for_file(+File, +Out, +Options) is det
Generate a LaTeX description of all commented predicates in File, writing the LaTeX text to the stream Out. Supports the options stand_alone, public_only and section_level. See doc_latex/3 for a description of the options.
  214latex_for_file(FileSpec, Out, Options) :-
  215    load_urldefs,
  216    phrase(latex_tokens_for_file(FileSpec, Options), Tokens),
  217    print_latex(Out, Tokens, Options).
 latex_tokens_for_file(+FileSpec, +Options)//
  222latex_tokens_for_file(FileSpec, Options, Tokens, Tail) :-
  223    absolute_file_name(FileSpec,
  224                       [ file_type(prolog),
  225                         access(read)
  226                       ],
  227                       File),
  228    doc_file_objects(FileSpec, File, Objects, FileOptions, Options),
  229    asserta(options(Options), Ref),
  230    call_cleanup(phrase(latex([ \file_header(File, FileOptions)
  231                              | \objects(Objects, FileOptions)
  232                              ]),
  233                        Tokens, Tail),
  234                 erase(Ref)).
 latex_for_wiki_file(+File, +Out, +Options) is det
Write a LaTeX translation of a Wiki file to the steam Out. Supports the options stand_alone, public_only and section_level. See doc_latex/3 for a description of the options.
  244latex_for_wiki_file(FileSpec, Out, Options) :-
  245    load_urldefs,
  246    phrase(latex_tokens_for_wiki_file(FileSpec, Options), Tokens),
  247    print_latex(Out, Tokens, Options).
  248
  249latex_tokens_for_wiki_file(FileSpec, Options, Tokens, Tail) :-
  250    absolute_file_name(FileSpec, File,
  251                       [ access(read)
  252                       ]),
  253    read_file_to_codes(File, String, []),
  254    b_setval(pldoc_file, File),
  255    asserta(options(Options), Ref),
  256    call_cleanup((wiki_codes_to_dom(String, [], DOM),
  257                  phrase(latex(DOM), Tokens, Tail)
  258                 ),
  259                 (nb_delete(pldoc_file),
  260                  erase(Ref))).
 latex_for_predicates(+PI:list, +Out, +Options) is det
Generate LaTeX for a list of predicate indicators. This does not produce the \begin{description}...\end{description} environment, just a plain list of \predicate, etc. statements. The current implementation ignores Options.
  270latex_for_predicates(Spec, Out, Options) :-
  271    load_urldefs,
  272    phrase(latex_tokens_for_predicates(Spec, Options), Tokens),
  273    print_latex(Out, [nl_exact(0)|Tokens], Options).
  274
  275latex_tokens_for_predicates([], _Options) --> !.
  276latex_tokens_for_predicates([H|T], Options) -->
  277    !,
  278    latex_tokens_for_predicates(H, Options),
  279    latex_tokens_for_predicates(T, Options).
  280latex_tokens_for_predicates(PI, Options) -->
  281    { generic_pi(PI),
  282      !,
  283      (   doc_comment(PI, Pos, _Summary, Comment)
  284      ->  true
  285      ;   Comment = ''
  286      )
  287    },
  288    object(PI, Pos, Comment, [description], _, Options).
  289latex_tokens_for_predicates(Spec, Options) -->
  290    { findall(PI, documented_pi(Spec, PI, Options), List),
  291      (   List == []
  292      ->  print_message(warning, pldoc(no_predicates_from(Spec)))
  293      ;   true
  294      )
  295    },
  296    latex_tokens_for_predicates(List, Options).
  297
  298documented_pi(Spec, PI, Options) :-
  299    option(modules(List), Options),
  300    member(M, List),
  301    generalise_spec(Spec, PI, M),
  302    doc_comment(PI, _Pos, _Summary, _Comment),
  303    !.
  304documented_pi(Spec, PI, Options) :-
  305    option(module(M), Options),
  306    generalise_spec(Spec, PI, M),
  307    doc_comment(PI, _Pos, _Summary, _Comment),
  308    !.
  309documented_pi(Spec, PI, _Options) :-
  310    generalise_spec(Spec, PI, _),
  311    doc_comment(PI, _Pos, _Summary, _Comment).
  312
  313generic_pi(Module:Name/Arity) :-
  314    atom(Module), atom(Name), integer(Arity),
  315    !.
  316generic_pi(Module:Name//Arity) :-
  317    atom(Module), atom(Name), integer(Arity).
  318
  319generalise_spec(Name/Arity, M:Name/Arity, M).
  320generalise_spec(Name//Arity, M:Name//Arity, M).
  321
  322
  323                 /*******************************
  324                 *       LATEX PRODUCTION       *
  325                 *******************************/
  326
  327:- thread_local
  328    fragile/0.                      % provided when in fragile mode
  329
  330latex([]) -->
  331    !,
  332    [].
  333latex(Atomic) -->
  334    { string(Atomic),
  335      atom_string(Atom, Atomic),
  336      sub_atom(Atom, 0, _, 0, 'LaTeX')
  337    },
  338    !,
  339    [ latex('\\LaTeX{}') ].
  340latex(Atomic) -->                       % can this actually happen?
  341    { atomic(Atomic),
  342      !,
  343      atom_string(Atom, Atomic),
  344      findall(x, sub_atom(Atom, _, _, _, '\n'), Xs),
  345      length(Xs, Lines)
  346    },
  347    (   {Lines == 0}
  348    ->  [ Atomic ]
  349    ;   [ nl(Lines) ]
  350    ).
  351latex(List) -->
  352    latex_special(List, Rest),
  353    !,
  354    latex(Rest).
  355latex(w(Word)) -->
  356    [ Word ].
  357latex([H|T]) -->
  358    !,
  359    (   latex(H)
  360    ->  latex(T)
  361    ;   { print_message(error, latex(failed(H))) },
  362        latex(T)
  363    ).
  364
  365% high level commands
  366latex(h1(Attrs, Content)) -->
  367    latex_section(0, Attrs, Content).
  368latex(h2(Attrs, Content)) -->
  369    latex_section(1, Attrs, Content).
  370latex(h3(Attrs, Content)) -->
  371    latex_section(2, Attrs, Content).
  372latex(h4(Attrs, Content)) -->
  373    latex_section(3, Attrs, Content).
  374latex(p(Content)) -->
  375    [ nl_exact(2) ],
  376    latex(Content).
  377latex(blockquote(Content)) -->
  378    latex(cmd(begin(quote))),
  379    latex(Content),
  380    latex(cmd(end(quote))).
  381latex(center(Content)) -->
  382    latex(cmd(begin(center))),
  383    latex(Content),
  384    latex(cmd(end(center))).
  385latex(a(Attrs, Content)) -->
  386    { attribute(href(HREF), Attrs) },
  387    (   {HREF == Content}
  388    ->  latex(cmd(url(no_escape(HREF))))
  389    ;   { atom_concat(#,Sec,HREF) }
  390    ->  latex([Content, ' (', cmd(secref(Sec)), ')'])
  391    ;   latex(cmd(href(no_escape(HREF), Content)))
  392    ).
  393latex(br(_)) -->
  394    latex(latex(\\)).
  395latex(hr(_)) -->
  396    latex(cmd(hrule)).
  397latex(code(CodeList)) -->
  398    { is_list(CodeList),
  399      !,
  400      atomic_list_concat(CodeList, Atom)
  401    },
  402    (   {fragile}
  403    ->  latex(cmd(const(Atom)))
  404    ;   [ verb(Atom) ]
  405    ).
  406latex(code(Code)) -->
  407    { identifier(Code) },
  408    !,
  409    latex(cmd(const(Code))).
  410latex(code(Code)) -->
  411    (   {fragile}
  412    ->  latex(cmd(const(Code)))
  413    ;   [ verb(Code) ]
  414    ).
  415latex(b(Code)) -->
  416    latex(cmd(textbf(Code))).
  417latex(strong(Code)) -->
  418    latex(cmd(textbf(Code))).
  419latex(i(Code)) -->
  420    latex(cmd(textit(Code))).
  421latex(var(Var)) -->
  422    latex(cmd(arg(Var))).
  423latex(pre(_Class, Code)) -->
  424    [ nl_exact(2), code(Code), nl_exact(2) ].
  425latex(ul(Content)) -->
  426    { if_short_list(Content, shortlist, itemize, Env) },
  427    latex(cmd(begin(Env))),
  428    latex(Content),
  429    latex(cmd(end(Env))).
  430latex(ol(Content)) -->
  431    latex(cmd(begin(enumerate))),
  432    latex(Content),
  433    latex(cmd(end(enumerate))).
  434latex(li(Content)) -->
  435    latex(cmd(item)),
  436    latex(Content).
  437latex(dl(_, Content)) -->
  438    latex(cmd(begin(description))),
  439    latex(Content),
  440    latex(cmd(end(description))).
  441latex(dd(_, Content)) -->
  442    latex(Content).
  443latex(dd(Content)) -->
  444    latex(Content).
  445latex(dt(class=term, \term(Text, Term, Bindings))) -->
  446    termitem(Text, Term, Bindings).
  447latex(dt(Content)) -->
  448    latex(cmd(item(opt(Content)))).
  449latex(table(Attrs, Content)) -->
  450    latex_table(Attrs, Content).
  451latex(\Cmd, List, Tail) :-
  452    call(Cmd, List, Tail).
  453
  454% low level commands
  455latex(latex(Text)) -->
  456    [ latex(Text) ].
  457latex(cmd(Term)) -->
  458    { Term =.. [Cmd|Args] },
  459    indent(Cmd),
  460    [ cmd(Cmd) ],
  461    latex_arguments(Args),
  462    outdent(Cmd).
  463
  464indent(begin) --> !,           [ nl(2) ].
  465indent(end) --> !,             [ nl_exact(1) ].
  466indent(section) --> !,         [ nl(2) ].
  467indent(subsection) --> !,      [ nl(2) ].
  468indent(subsubsection) --> !,   [ nl(2) ].
  469indent(item) --> !,            [ nl(1), indent(4) ].
  470indent(definition) --> !,      [ nl(1), indent(4) ].
  471indent(tag) --> !,             [ nl(1), indent(4) ].
  472indent(termitem) --> !,        [ nl(1), indent(4) ].
  473indent(prefixtermitem) --> !,  [ nl(1), indent(4) ].
  474indent(infixtermitem) --> !,   [ nl(1), indent(4) ].
  475indent(postfixtermitem) --> !, [ nl(1), indent(4) ].
  476indent(predicate) --> !,       [ nl(1), indent(4) ].
  477indent(dcg) --> !,             [ nl(1), indent(4) ].
  478indent(infixop) --> !,         [ nl(1), indent(4) ].
  479indent(prefixop) --> !,        [ nl(1), indent(4) ].
  480indent(postfixop) --> !,       [ nl(1), indent(4) ].
  481indent(predicatesummary) --> !,[ nl(1) ].
  482indent(dcgsummary) --> !,      [ nl(1) ].
  483indent(oppredsummary) --> !,   [ nl(1) ].
  484indent(hline) --> !,           [ nl(1) ].
  485indent(_) -->                  [].
  486
  487outdent(begin) --> !,           [ nl_exact(1) ].
  488outdent(end) --> !,             [ nl(2) ].
  489outdent(item) --> !,            [ ' ' ].
  490outdent(tag) --> !,             [ nl(1) ].
  491outdent(termitem) --> !,        [ nl(1) ].
  492outdent(prefixtermitem) --> !,  [ nl(1) ].
  493outdent(infixtermitem) --> !,   [ nl(1) ].
  494outdent(postfixtermitem) --> !, [ nl(1) ].
  495outdent(definition) --> !,      [ nl(1) ].
  496outdent(section) --> !,         [ nl(2) ].
  497outdent(subsection) --> !,      [ nl(2) ].
  498outdent(subsubsection) --> !,   [ nl(2) ].
  499outdent(predicate) --> !,       [ nl(1) ].
  500outdent(dcg) --> !,             [ nl(1) ].
  501outdent(infixop) --> !,         [ nl(1) ].
  502outdent(prefixop) --> !,        [ nl(1) ].
  503outdent(postfixop) --> !,       [ nl(1) ].
  504outdent(predicatesummary) --> !,[ nl(1) ].
  505outdent(dcgsummary) --> !,      [ nl(1) ].
  506outdent(oppredsummary) --> !,   [ nl(1) ].
  507outdent(hline) --> !,           [ nl(1) ].
  508outdent(_) -->                  [].
 latex_special(String, Rest)// is semidet
Deals with special sequences of symbols.
  514latex_special(In, Rest) -->
  515    { url_chars(In, Chars, Rest),
  516      special(Chars),
  517      atom_chars(Atom, Chars),
  518      urldef_name(Atom, Name)
  519    },
  520    !,
  521    latex([cmd(Name), latex('{}')]).
  522
  523special(Chars) :-
  524    memberchk(\, Chars),
  525    !.
  526special(Chars) :-
  527    length(Chars, Len),
  528    Len > 1.
  529
  530url_chars([H|T0], [H|T], Rest) :-
  531    urlchar(H),
  532    !,
  533    url_chars(T0, T, Rest).
  534url_chars(L, [], L).
 latex_arguments(+Args:list)// is det
Write LaTeX command arguments. If an argument is of the form opt(Arg) it is written as [Arg], Otherwise it is written as {Arg}. Note that opt([]) is omitted. I think no LaTeX command is designed to handle an empty optional argument special.

During processing the arguments it asserts fragile/0 to allow is taking care of LaTeX fragile constructs (i.e. constructs that are not allows inside {...}).

  548latex_arguments(List, Out, Tail) :-
  549    asserta(fragile, Ref),
  550    call_cleanup(fragile_list(List, Out, Tail),
  551                 erase(Ref)).
  552
  553fragile_list([]) --> [].
  554fragile_list([opt([])|T]) -->
  555    !,
  556    fragile_list(T).
  557fragile_list([opt(H)|T]) -->
  558    !,
  559    [ '[' ],
  560    latex_arg(H),
  561    [ ']' ],
  562    fragile_list(T).
  563fragile_list([H|T]) -->
  564    [ curl(open) ],
  565    latex_arg(H),
  566    [ curl(close) ],
  567    fragile_list(T).
 latex_arg(+In)//
Write a LaTeX argument. If we can, we will use a defined urldef_name/2.
  574latex_arg(H) -->
  575    { atomic(H),
  576      atom_string(Atom, H),
  577      urldef_name(Atom, Name)
  578    },
  579    !,
  580    latex(cmd(Name)).
  581latex_arg(H) -->
  582    { maplist(atom, H),
  583      atomic_list_concat(H, Atom),
  584      urldef_name(Atom, Name)
  585    },
  586    !,
  587    latex(cmd(Name)).
  588latex_arg(no_escape(Text)) -->
  589    !,
  590    [no_escape(Text)].
  591latex_arg(H) -->
  592    latex(H).
  593
  594attribute(Att, Attrs) :-
  595    is_list(Attrs),
  596    !,
  597    option(Att, Attrs).
  598attribute(Att, One) :-
  599    option(Att, [One]).
  600
  601if_short_list(Content, If, Else, Env) :-
  602    (   short_list(Content)
  603    ->  Env = If
  604    ;   Env = Else
  605    ).
 short_list(+Content) is semidet
True if Content describes the content of a dl or ul/ol list where each elemenent has short content.
  612short_list([]).
  613short_list([_,dd(Content)|T]) :-
  614    !,
  615    short_content(Content),
  616    short_list(T).
  617short_list([_,dd(_, Content)|T]) :-
  618    !,
  619    short_content(Content),
  620    short_list(T).
  621short_list([li(Content)|T]) :-
  622    short_content(Content),
  623    short_list(T).
  624
  625short_content(Content) :-
  626    phrase(latex(Content), Tokens),
  627    summed_string_len(Tokens, 0, Len),
  628    Len < 50.
  629
  630summed_string_len([], Len, Len).
  631summed_string_len([H|T], L0, L) :-
  632    atomic(H),
  633    !,
  634    atom_length(H, AL),
  635    L1 is L0 + AL,
  636    summed_string_len(T, L1, L).
  637summed_string_len([_|T], L0, L) :-
  638    summed_string_len(T, L0, L).
 latex_section(+Level, +Attributes, +Content)// is det
Emit a LaTeX section, keeping track of the desired highest section level.
Arguments:
Level- Desired level, relative to the base-level. Must be a non-negative integer.
  649latex_section(Level, Attrs, Content) -->
  650    { current_options(Options),
  651      option(section_level(LaTexSection), Options, section),
  652      latex_section_level(LaTexSection, BaseLevel),
  653      FinalLevel is BaseLevel+Level,
  654      (   latex_section_level(SectionCommand, FinalLevel)
  655      ->  Term =.. [SectionCommand, Content]
  656      ;   domain_error(latex_section_level, FinalLevel)
  657      )
  658    },
  659    latex(cmd(Term)),
  660    section_label(Attrs).
  661
  662section_label(Attrs) -->
  663    { is_list(Attrs),
  664      memberchk(id(Name), Attrs),
  665      !,
  666      delete_unsafe_label_chars(Name, SafeName),
  667      atom_concat('sec:', SafeName, Label)
  668    },
  669    latex(cmd(label(Label))).
  670section_label(_) -->
  671    [].
  672
  673latex_section_level(chapter,       0).
  674latex_section_level(section,       1).
  675latex_section_level(subsection,    2).
  676latex_section_level(subsubsection, 3).
  677latex_section_level(paragraph,     4).
  678
  679deepen_section_level(Level0, Level1) :-
  680    latex_section_level(Level0, N),
  681    N1 is N + 1,
  682    latex_section_level(Level1, N1).
 delete_unsafe_label_chars(+LabelIn, -LabelOut)
delete unsafe characters from LabelIn. Currently only deletes _, as this appears commonly through filenames, but cannot be handled through the LaTeX processing chain.
  690delete_unsafe_label_chars(LabelIn, LabelOut) :-
  691    atom_chars(LabelIn, Chars),
  692    delete(Chars, '_', CharsOut),
  693    atom_chars(LabelOut, CharsOut).
  694
  695
  696                 /*******************************
  697                 *         \ COMMANDS           *
  698                 *******************************/
 include(+File, +Type, +Options)// is det
Called from [[File]].
  704include(PI, predicate, _) -->
  705    !,
  706    (   {   options(Options)
  707        ->  true
  708        ;   Options = []
  709        },
  710        latex_tokens_for_predicates(PI, Options)
  711    ->  []
  712    ;   latex(cmd(item(['[[', \predref(PI), ']]'])))
  713    ).
  714include(File, Type, Options) -->
  715    { existing_linked_file(File, Path) },
  716    !,
  717    include_file(Path, Type, Options).
  718include(File, _, _) -->
  719    latex(code(['[[', File, ']]'])).
  720
  721include_file(Path, image, Options) -->
  722    { option(caption(Caption), Options) },
  723    !,
  724    latex(cmd(begin(figure, [no_escape(htbp)]))),
  725    latex(cmd(begin(center))),
  726    latex(cmd(includegraphics(Path))),
  727    latex(cmd(end(center))),
  728    latex(cmd(caption(Caption))),
  729    latex(cmd(end(figure))).
  730include_file(Path, image, _) -->
  731    !,
  732    latex(cmd(includegraphics(Path))).
  733include_file(Path, Type, _) -->
  734    { assertion(memberchk(Type, [prolog,wiki])),
  735      current_options(Options0),
  736      select_option(stand_alone(_), Options0, Options1, _),
  737      select_option(section_level(Level0), Options1, Options2, section),
  738      deepen_section_level(Level0, Level),
  739      Options = [stand_alone(false), section_level(Level)|Options2]
  740    },
  741    (   {Type == prolog}
  742    ->  latex_tokens_for_file(Path, Options)
  743    ;   latex_tokens_for_wiki_file(Path, Options)
  744    ).
 file(+File, +Options)// is det
Called from implicitely linked files. The HTML version creates a hyperlink. We just name the file.
  751file(File, _Options) -->
  752    { fragile },
  753    !,
  754    latex(cmd(texttt(File))).
  755file(File, _Options) -->
  756    latex(cmd(file(File))).
 predref(+PI)// is det
Called from name/arity or name//arity patterns in the documentation.
  763predref(Module:Name/Arity) -->
  764    !,
  765    latex(cmd(qpredref(Module, Name, Arity))).
  766predref(Module:Name//Arity) -->
  767    latex(cmd(qdcgref(Module, Name, Arity))).
  768predref(Name/Arity) -->
  769    latex(cmd(predref(Name, Arity))).
  770predref(Name//Arity) -->
  771    latex(cmd(dcgref(Name, Arity))).
 tags(+Tags:list(Tag)) is det
Emit tag list produced by the Wiki processor from the @keyword commands.
  778tags([\args(Params)|Rest]) -->
  779    !,
  780    args(Params),
  781    tags_list(Rest).
  782tags(List) -->
  783    tags_list(List).
  784
  785tags_list([]) -->
  786    [].
  787tags_list(List) -->
  788    [ nl(2) ],
  789    latex(cmd(begin(tags))),
  790    latex(List),
  791    latex(cmd(end(tags))),
  792    [ nl(2) ].
 tag(+Tag, +Values:list)// is det
Called from \tag(Name, Values) terms produced by doc_wiki.pl.
  798tag(Tag, [One]) -->
  799    !,
  800    { doc_tag_title(Tag, Title) },
  801    latex([ cmd(tag(Title))
  802          | One
  803          ]).
  804tag(Tag, More) -->
  805    { doc_tag_title(Tag, Title) },
  806    latex([ cmd(mtag(Title)),
  807            \tag_value_list(More)
  808          ]).
  809
  810tag_value_list([H|T]) -->
  811    latex(['- '|H]),
  812    (   { T \== [] }
  813    ->  [latex(' \\\\')],
  814        tag_value_list(T)
  815    ;   []
  816    ).
 args(+Params:list) is det
Called from \args(List) created by doc_wiki.pl. Params is a list of arg(Name, Descr).
  823args(Params) -->
  824    latex([ cmd(begin(arguments)),
  825            \arg_list(Params),
  826            cmd(end(arguments))
  827          ]).
  828
  829arg_list([]) -->
  830    [].
  831arg_list([H|T]) -->
  832    argument(H),
  833    arg_list(T).
  834
  835argument(arg(Name,Descr)) -->
  836    [ nl(1) ],
  837    latex(cmd(arg(Name))), [ latex(' & ') ],
  838    latex(Descr), [latex(' \\\\')].
 file_header(+File, +Options)// is det
Create the file header.
  844file_header(File, Options) -->
  845    { memberchk(file(Title, Comment), Options),
  846      !,
  847      file_synopsis(File, Synopsis)
  848    },
  849    file_title([Synopsis, ': ', Title], File, Options),
  850    { is_structured_comment(Comment, Prefixes),
  851      string_codes(Comment, Codes),
  852      indented_lines(Codes, Prefixes, Lines),
  853      section_comment_header(Lines, _Header, Lines1),
  854      wiki_lines_to_dom(Lines1, [], DOM0),
  855      tags_to_front(DOM0, DOM)
  856    },
  857    latex(DOM),
  858    latex(cmd(vspace('0.7cm'))).
  859file_header(File, Options) -->
  860    { file_synopsis(File, Synopsis)
  861    },
  862    file_title([Synopsis], File, Options).
  863
  864tags_to_front(DOM0, DOM) :-
  865    append(Content, [\tags(Tags)], DOM0),
  866    !,
  867    DOM = [\tags(Tags)|Content].
  868tags_to_front(DOM, DOM).
  869
  870file_synopsis(File, Synopsis) :-
  871    file_name_on_path(File, Term),
  872    unquote_filespec(Term, Unquoted),
  873    format(atom(Synopsis), '~w', [Unquoted]).
 file_title(+Title:list, +File, +Options)// is det
Emit the file-header and manipulation buttons.
  880file_title(Title, File, Options) -->
  881    { option(section_level(Level), Options, section),
  882      Section =.. [Level,Title],
  883      file_base_name(File, BaseExt),
  884      file_name_extension(Base, _, BaseExt),
  885      delete_unsafe_label_chars(Base, SafeBase),
  886      atom_concat('sec:', SafeBase, Label)
  887    },
  888    latex(cmd(Section)),
  889    latex(cmd(label(Label))).
 objects(+Objects:list, +Options)// is det
Emit the documentation body.
  896objects(Objects, Options) -->
  897    objects(Objects, [body], Options).
  898
  899objects([], Mode, _) -->
  900    pop_mode(body, Mode, _).
  901objects([Obj|T], Mode, Options) -->
  902    object(Obj, Mode, Mode1, Options),
  903    objects(T, Mode1, Options).
  904
  905object(doc(Obj,Pos,Comment), Mode0, Mode, Options) -->
  906    !,
  907    object(Obj, Pos, Comment, Mode0, Mode, Options).
  908object(Obj, Mode0, Mode, Options) -->
  909    { doc_comment(Obj, Pos, _Summary, Comment)
  910    },
  911    !,
  912    object(Obj, Pos, Comment, Mode0, Mode, Options).
  913
  914object(Obj, Pos, Comment, Mode0, Mode, Options) -->
  915    { is_pi(Obj),
  916      !,
  917      is_structured_comment(Comment, Prefixes),
  918      string_codes(Comment, Codes),
  919      indented_lines(Codes, Prefixes, Lines),
  920      strip_module(user:Obj, Module, _),
  921      process_modes(Lines, Module, Pos, Modes, Args, Lines1),
  922      (   private(Obj, Options)
  923      ->  Class = privdef           % private definition
  924      ;   multifile(Obj, Options)
  925      ->  Class = multidef
  926      ;   Class = pubdef            % public definition
  927      ),
  928      (   Obj = Module:_
  929      ->  POptions = [module(Module)|Options]
  930      ;   POptions = Options
  931      ),
  932      DOM = [\pred_dt(Modes, Class, POptions), dd(class=defbody, DOM1)],
  933      wiki_lines_to_dom(Lines1, Args, DOM0),
  934      strip_leading_par(DOM0, DOM1),
  935      assert_documented(Obj)
  936    },
  937    need_mode(description, Mode0, Mode),
  938    latex(DOM).
  939object([Obj|Same], Pos, Comment, Mode0, Mode, Options) -->
  940    !,
  941    object(Obj, Pos, Comment, Mode0, Mode, Options),
  942    { maplist(assert_documented, Same) }.
  943object(Obj, _Pos, _Comment, Mode, Mode, _Options) -->
  944    { debug(pldoc, 'Skipped ~p', [Obj]) },
  945    [].
  946
  947assert_documented(Obj) :-
  948    assert(documented(Obj)).
 need_mode(+Mode:atom, +Stack:list, -NewStack:list)// is det
While predicates are part of a description list, sections are not and we therefore need to insert <dl>...</dl> into the output. We do so by demanding an outer environment and push/pop the required elements.
  958need_mode(Mode, Stack, Stack) -->
  959    { Stack = [Mode|_] },
  960    !,
  961    [].
  962need_mode(Mode, Stack, Rest) -->
  963    { memberchk(Mode, Stack)
  964    },
  965    !,
  966    pop_mode(Mode, Stack, Rest).
  967need_mode(Mode, Stack, [Mode|Stack]) -->
  968    !,
  969    latex(cmd(begin(Mode))).
  970
  971pop_mode(Mode, Stack, Stack) -->
  972    { Stack = [Mode|_] },
  973    !,
  974    [].
  975pop_mode(Mode, [H|Rest0], Rest) -->
  976    latex(cmd(end(H))),
  977    pop_mode(Mode, Rest0, Rest).
 pred_dt(+Modes, +Class, Options)// is det
Emit the \predicate{}{}{} header.
Arguments:
Modes- List as returned by process_modes/5.
Class- One of privdef or pubdef.
To be done
- Determinism
  989pred_dt(Modes, Class, Options) -->
  990    [nl(2)],
  991    pred_dt(Modes, [], _Done, [class(Class)|Options]).
  992
  993pred_dt([], Done, Done, _) -->
  994    [].
  995pred_dt([H|T], Done0, Done, Options) -->
  996    pred_mode(H, Done0, Done1, Options),
  997    (   {T == []}
  998    ->  []
  999    ;   latex(cmd(nodescription)),
 1000        pred_dt(T, Done1, Done, Options)
 1001    ).
 1002
 1003pred_mode(mode(Head,Vars), Done0, Done, Options) -->
 1004    !,
 1005    { bind_vars(Head, Vars) },
 1006    pred_mode(Head, Done0, Done, Options).
 1007pred_mode(Head is Det, Done0, Done, Options) -->
 1008    !,
 1009    anchored_pred_head(Head, Done0, Done, [det(Det)|Options]).
 1010pred_mode(Head, Done0, Done, Options) -->
 1011    anchored_pred_head(Head, Done0, Done, Options).
 1012
 1013bind_vars(Term, Bindings) :-
 1014    bind_vars(Bindings),
 1015    anon_vars(Term).
 1016
 1017bind_vars([]).
 1018bind_vars([Name=Var|T]) :-
 1019    Var = '$VAR'(Name),
 1020    bind_vars(T).
 anon_vars(+Term) is det
Bind remaining variables in Term to '$VAR'('_'), so they are printed as '_'.
 1027anon_vars(Var) :-
 1028    var(Var),
 1029    !,
 1030    Var = '$VAR'('_').
 1031anon_vars(Term) :-
 1032    compound(Term),
 1033    !,
 1034    Term =.. [_|Args],
 1035    maplist(anon_vars, Args).
 1036anon_vars(_).
 1037
 1038
 1039anchored_pred_head(Head, Done0, Done, Options) -->
 1040    { pred_anchor_name(Head, PI, _Name) },
 1041    (   { memberchk(PI, Done0) }
 1042    ->  { Done = Done0 }
 1043    ;   { Done = [PI|Done0] }
 1044    ),
 1045    pred_head(Head, Options).
 pred_head(+Term, Options) is det
Emit a predicate head. The functor is typeset as a span using class pred and the arguments and var using class arglist.
To be done
- Support determinism in operators
 1055pred_head(//(Head), Options) -->
 1056    !,
 1057    { pred_attributes(Options, Atts),
 1058      Head =.. [Functor|Args],
 1059      length(Args, Arity)
 1060    },
 1061    latex(cmd(dcg(opt(Atts), Functor, Arity, \pred_args(Args, 1)))).
 1062pred_head(Head, _Options) -->                   % Infix operators
 1063    { Head =.. [Functor,Left,Right],
 1064      Functor \== (:),
 1065      is_op_type(Functor, infix), !
 1066    },
 1067    latex(cmd(infixop(Functor, \pred_arg(Left, 1), \pred_arg(Right, 2)))).
 1068pred_head(Head, _Options) -->                   % Prefix operators
 1069    { Head =.. [Functor,Arg],
 1070      is_op_type(Functor, prefix), !
 1071    },
 1072    latex(cmd(prefixop(Functor, \pred_arg(Arg, 1)))).
 1073pred_head(Head, _Options) -->                   % Postfix operators
 1074    { Head =.. [Functor,Arg],
 1075      is_op_type(Functor, postfix), !
 1076    },
 1077    latex(cmd(postfixop(Functor, \pred_arg(Arg, 1)))).
 1078pred_head(M:Head, Options) -->                 % Qualified predicates
 1079    !,
 1080    { pred_attributes(Options, Atts),
 1081      Head =.. [Functor|Args],
 1082      length(Args, Arity)
 1083    },
 1084    latex(cmd(qpredicate(opt(Atts),
 1085                         M,
 1086                         Functor, Arity, \pred_args(Args, 1)))).
 1087pred_head(Head, Options) -->                    % Plain terms
 1088    { pred_attributes(Options, Atts),
 1089      Head =.. [Functor|Args],
 1090      length(Args, Arity)
 1091    },
 1092    latex(cmd(predicate(opt(Atts),
 1093                        Functor, Arity, \pred_args(Args, 1)))).
 pred_attributes(+Options, -Attributes) is det
Create a comma-separated list of predicate attributes, such as determinism, etc.
 1100pred_attributes(Options, Attrs) :-
 1101    findall(A, pred_att(Options, A), As),
 1102    insert_comma(As, Attrs).
 1103
 1104pred_att(Options, Det) :-
 1105    option(det(Det), Options).
 1106pred_att(Options, private) :-
 1107    option(class(privdef), Options).
 1108pred_att(Options, multifile) :-
 1109    option(class(multidef), Options).
 1110
 1111insert_comma([H1,H2|T0], [H1, ','|T]) :-
 1112    !,
 1113    insert_comma([H2|T0], T).
 1114insert_comma(L, L).
 1115
 1116
 1117:- if(current_predicate(is_dict/1)). 1118dict_kv_pairs([]) --> [].
 1119dict_kv_pairs([H|T]) -->
 1120    dict_kv(H),
 1121    (   { T == [] }
 1122    ->  []
 1123    ;   latex(', '),
 1124        dict_kv_pairs(T)
 1125    ).
 1126
 1127dict_kv(Key-Value) -->
 1128    latex(cmd(key(Key))),
 1129    latex(':'),
 1130    term(Value).
 1131:- endif. 1132
 1133pred_args([], _) -->
 1134    [].
 1135pred_args([H|T], I) -->
 1136    pred_arg(H, I),
 1137    (   {T==[]}
 1138    ->  []
 1139    ;   latex(', '),
 1140        { I2 is I + 1 },
 1141        pred_args(T, I2)
 1142    ).
 1143
 1144pred_arg(Var, I) -->
 1145    { var(Var) },
 1146    !,
 1147    latex(['Arg', I]).
 1148pred_arg(...(Term), I) -->
 1149    !,
 1150    pred_arg(Term, I),
 1151    latex(cmd(ldots)).
 1152pred_arg(Term, I) -->
 1153    { Term =.. [Ind,Arg],
 1154      mode_indicator(Ind)
 1155    },
 1156    !,
 1157    latex([Ind, \pred_arg(Arg, I)]).
 1158pred_arg(Arg:Type, _) -->
 1159    !,
 1160    latex([\argname(Arg), :, \argtype(Type)]).
 1161pred_arg(Arg, _) -->
 1162    { atom(Arg) },
 1163    !,
 1164    argname(Arg).
 1165pred_arg(Arg, _) -->
 1166    argtype(Arg).                   % arbitrary term
 1167
 1168argname('$VAR'(Name)) -->
 1169    !,
 1170    latex(Name).
 1171argname(Name) -->
 1172    !,
 1173    latex(Name).
 1174
 1175argtype(Term) -->
 1176    { format(string(S), '~W',
 1177             [ Term,
 1178               [ quoted(true),
 1179                 numbervars(true)
 1180               ]
 1181             ]) },
 1182    latex(S).
 term(+Text, +Term, +Bindings)// is det
Process the \term element as produced by doc_wiki.pl.
To be done
- Properly merge with pred_head//1
 1190term(_, Term, Bindings) -->
 1191    { bind_vars(Bindings) },
 1192    term(Term).
 1193
 1194term('$VAR'(Name)) -->
 1195    !,
 1196    latex(cmd(arg(Name))).
 1197term(Compound) -->
 1198    { callable(Compound),
 1199      !,
 1200      Compound =.. [Functor|Args]
 1201    },
 1202    !,
 1203    term_with_args(Functor, Args).
 1204term(Rest) -->
 1205    latex(Rest).
 1206
 1207term_with_args(Functor, [Left, Right]) -->
 1208    { is_op_type(Functor, infix) },
 1209    !,
 1210    latex(cmd(infixterm(Functor, \term(Left), \term(Right)))).
 1211term_with_args(Functor, [Arg]) -->
 1212    { is_op_type(Functor, prefix) },
 1213    !,
 1214    latex(cmd(prefixterm(Functor, \term(Arg)))).
 1215term_with_args(Functor, [Arg]) -->
 1216    { is_op_type(Functor, postfix) },
 1217    !,
 1218    latex(cmd(postfixterm(Functor, \term(Arg)))).
 1219term_with_args(Functor, Args) -->
 1220    latex(cmd(term(Functor, \pred_args(Args, 1)))).
 termitem(+Text, +Term, +Bindings)// is det
Create a termitem or one of its variations.
 1227termitem(_Text, Term, Bindings) -->
 1228    { bind_vars(Bindings) },
 1229    termitem(Term).
 1230
 1231termitem('$VAR'(Name)) -->
 1232    !,
 1233    latex(cmd(termitem(var(Name), ''))).
 1234:- if(current_predicate(is_dict/1)). 1235termitem(Dict) -->
 1236    { is_dict(Dict),
 1237      !,
 1238      dict_pairs(Dict, Tag, Pairs)
 1239    },
 1240    latex(cmd(dictitem(Tag, \dict_kv_pairs(Pairs)))).
 1241:- endif. 1242termitem(Compound) -->
 1243    { callable(Compound),
 1244      !,
 1245      Compound =.. [Functor|Args]
 1246    },
 1247    !,
 1248    termitem_with_args(Functor, Args).
 1249termitem(Rest) -->
 1250    latex(cmd(termitem(Rest, ''))).
 1251
 1252termitem_with_args(Functor, [Left, Right]) -->
 1253    { is_op_type(Functor, infix) },
 1254    !,
 1255    latex(cmd(infixtermitem(Functor, \term(Left), \term(Right)))).
 1256termitem_with_args(Functor, [Arg]) -->
 1257    { is_op_type(Functor, prefix) },
 1258    !,
 1259    latex(cmd(prefixtermitem(Functor, \term(Arg)))).
 1260termitem_with_args(Functor, [Arg]) -->
 1261    { is_op_type(Functor, postfix) },
 1262    !,
 1263    latex(cmd(postfixtermitem(Functor, \term(Arg)))).
 1264termitem_with_args(Functor, Args) -->
 1265    latex(cmd(termitem(Functor, \pred_args(Args, 1)))).
 latex_table(Attrs, Content)// is det
Emit a table in LaTeX.
 1272latex_table(_Attrs, Content) -->
 1273    { max_columns(Content, 0, N),
 1274      make_frame(N, l, List),
 1275      atom_chars(Format, ['|'|List])
 1276    },
 1277%       latex(cmd(begin(table, opt(h)))),
 1278    latex(cmd(begin(quote))),
 1279    latex(cmd(begin(tabular, no_escape(Format)))),
 1280    latex(cmd(hline)),
 1281    rows(Content),
 1282    latex(cmd(hline)),
 1283    latex(cmd(end(tabular))),
 1284    latex(cmd(end(quote))).
 1285%       latex(cmd(end(table))).
 1286
 1287max_columns([], C, C).
 1288max_columns([tr(List)|T], C0, C) :-
 1289    length(List, C1),
 1290    C2 is max(C0, C1),
 1291    max_columns(T, C2, C).
 1292
 1293make_frame(0, _, []) :- !.
 1294make_frame(N, C, [C,'|'|T]) :-
 1295    N2 is N - 1,
 1296    make_frame(N2, C, T).
 1297
 1298rows([]) -->
 1299    [].
 1300rows([tr(Content)|T]) -->
 1301    row(Content),
 1302    rows(T).
 1303
 1304row([]) -->
 1305    [ latex(' \\\\'), nl(1) ].
 1306row([td(Content)|T]) -->
 1307    latex(Content),
 1308    (   {T == []}
 1309    ->  []
 1310    ;   [ latex(' & ') ]
 1311    ),
 1312    row(T).
 1313
 1314
 1315                 /*******************************
 1316                 *      SUMMARY PROCESSING      *
 1317                 *******************************/
 latex_summary(+Options)
If Options contains summary(+File), write a summary of all documented predicates to File.
 1324latex_summary(Options) :-
 1325    option(summary(File), Options),
 1326    !,
 1327    findall(Obj, summary_obj(Obj), Objs),
 1328    maplist(pi_sort_key, Objs, Keyed),
 1329    keysort(Keyed, KSorted),
 1330    pairs_values(KSorted, SortedObj),
 1331    phrase(summarylist(SortedObj, Options), Tokens),
 1332    open(File, write, Out),
 1333    call_cleanup(print_latex(Out, Tokens, Options),
 1334                 close(Out)).
 1335latex_summary(_) :-
 1336    retractall(documented(_)).
 1337
 1338summary_obj(Obj) :-
 1339    documented(Obj),
 1340    pi_head(Obj, Head),
 1341    \+ xref_hook(Head).
 1342
 1343pi_head(M:PI, M:Head) :-
 1344    !,
 1345    pi_head(PI, Head).
 1346pi_head(Name/Arity, Head) :-
 1347    functor(Head, Name, Arity).
 1348pi_head(Name//DCGArity, Head) :-
 1349    Arity is DCGArity+2,
 1350    functor(Head, Name, Arity).
 1351
 1352
 1353pi_sort_key(M:PI, PI-(M:PI)) :- !.
 1354pi_sort_key(PI, PI-PI).
 1355
 1356object_name_arity(_:Term, Type, Name, Arity) :-
 1357    nonvar(Term),
 1358    !,
 1359    object_name_arity(Term, Type, Name, Arity).
 1360object_name_arity(Name/Arity, pred, Name, Arity).
 1361object_name_arity(Name//Arity, dcg, Name, Arity).
 1362
 1363summarylist(Objs, Options) -->
 1364    latex(cmd(begin(summarylist, ll))),
 1365    summary(Objs, Options),
 1366    latex(cmd(end(summarylist))).
 1367
 1368summary([], _) -->
 1369    [].
 1370summary([H|T], Options) -->
 1371    summary_line(H, Options),
 1372    summary(T, Options).
 1373
 1374summary_line(Obj, _Options) -->
 1375    { doc_comment(Obj, _Pos, Summary, _Comment),
 1376      !,
 1377      atom_codes(Summary, Codes),
 1378      phrase(pldoc_wiki:line_tokens(Tokens), Codes), % TBD: proper export
 1379      object_name_arity(Obj, Type, Name, Arity)
 1380    },
 1381    (   {Type == dcg}
 1382    ->  latex(cmd(dcgsummary(Name, Arity, Tokens)))
 1383    ;   { strip_module(Obj, M, _),
 1384          current_op(Pri, Ass, M:Name)
 1385        }
 1386    ->  latex(cmd(oppredsummary(Name, Arity, Ass, Pri, Tokens)))
 1387    ;   latex(cmd(predicatesummary(Name, Arity, Tokens)))
 1388    ).
 1389summary_line(Obj, _Options) -->
 1390    { print_message(warning, pldoc(no_summary_for(Obj)))
 1391    }.
 1392
 1393                 /*******************************
 1394                 *          PRINT TOKENS        *
 1395                 *******************************/
 1396
 1397print_latex(Out, Tokens, Options) :-
 1398    latex_header(Out, Options),
 1399    print_latex_tokens(Tokens, Out),
 1400    latex_footer(Out, Options).
 print_latex_tokens(+Tokens, +Out)
Print primitive LaTeX tokens to Output
 1407print_latex_tokens([], _).
 1408print_latex_tokens([nl(N)|T0], Out) :-
 1409    !,
 1410    max_nl(T0, T, N, NL),
 1411    nl(Out, NL),
 1412    print_latex_tokens(T, Out).
 1413print_latex_tokens([nl_exact(N)|T0], Out) :-
 1414    !,
 1415    nl_exact(T0, T,N, NL),
 1416    nl(Out, NL),
 1417    print_latex_tokens(T, Out).
 1418print_latex_tokens([H|T], Out) :-
 1419    print_latex_token(H, Out),
 1420    print_latex_tokens(T, Out).
 1421
 1422print_latex_token(cmd(Cmd), Out) :-
 1423    !,
 1424    format(Out, '\\~w', [Cmd]).
 1425print_latex_token(curl(open), Out) :-
 1426    !,
 1427    format(Out, '{', []).
 1428print_latex_token(curl(close), Out) :-
 1429    !,
 1430    format(Out, '}', []).
 1431print_latex_token(indent(N), Out) :-
 1432    !,
 1433    format(Out, '~t~*|', [N]).
 1434print_latex_token(nl(N), Out) :-
 1435    !,
 1436    format(Out, '~N', []),
 1437    forall(between(2,N,_), nl(Out)).
 1438print_latex_token(verb(Verb), Out) :-
 1439    is_list(Verb), Verb \== [],
 1440    !,
 1441    atomic_list_concat(Verb, Atom),
 1442    print_latex_token(verb(Atom), Out).
 1443print_latex_token(verb(Verb), Out) :-
 1444    !,
 1445    (   member(C, [$,'|',@,=,'"',^,!]),
 1446        \+ sub_atom(Verb, _, _, _, C)
 1447    ->  atom_replace_char(Verb, '\n', ' ', Verb2),
 1448        format(Out, '\\verb~w~w~w', [C,Verb2,C])
 1449    ;   assertion(fail)
 1450    ).
 1451print_latex_token(code(Code), Out) :-
 1452    !,
 1453    format(Out, '~N\\begin{code}~n', []),
 1454    format(Out, '~w', [Code]),
 1455    format(Out, '~N\\end{code}', []).
 1456print_latex_token(latex(Code), Out) :-
 1457    !,
 1458    write(Out, Code).
 1459print_latex_token(w(Word), Out) :-
 1460    !,
 1461    print_latex(Out, Word).
 1462print_latex_token(no_escape(Text), Out) :-
 1463    !,
 1464    write(Out, Text).
 1465print_latex_token(Rest, Out) :-
 1466    (   atomic(Rest)
 1467    ->  print_latex(Out, Rest)
 1468    ;   %type_error(latex_token, Rest)
 1469        write(Out, Rest)
 1470    ).
 1471
 1472atom_replace_char(In, From, To, Out) :-
 1473    sub_atom(In, _, _, _, From),
 1474    !,
 1475    atom_chars(In, CharsIn),
 1476    replace(CharsIn, From, To, CharsOut),
 1477    atom_chars(Out, CharsOut).
 1478atom_replace_char(In, _, _, In).
 1479
 1480replace([], _, _, []).
 1481replace([H|T0], H, N, [N|T]) :-
 1482    !,
 1483    replace(T0, H, N, T).
 1484replace([H|T0], F, N, [H|T]) :-
 1485    replace(T0, F, N, T).
 print_latex(+Out, +Text:atomic) is det
Print Text, such that it comes out as normal LaTeX text.
 1492print_latex(Out, String) :-
 1493    atom_string(Atom, String),
 1494    atom_chars(Atom, Chars),
 1495    print_chars(Chars, Out).
 1496
 1497print_chars([], _).
 1498print_chars([H|T], Out) :-
 1499    print_char(H, Out),
 1500    print_chars(T, Out).
 max_nl(T0, T, M0, M)
Remove leading sequence of nl(N) and return the maximum of it.
 1507max_nl([nl(M1)|T0], T, M0, M) :-
 1508    !,
 1509    M2 is max(M1, M0),
 1510    max_nl(T0, T, M2, M).
 1511max_nl([nl_exact(M1)|T0], T, _, M) :-
 1512    !,
 1513    nl_exact(T0, T, M1, M).
 1514max_nl(T, T, M, M).
 1515
 1516nl_exact([nl(_)|T0], T, M0, M) :-
 1517    !,
 1518    max_nl(T0, T, M0, M).
 1519nl_exact([nl_exact(M1)|T0], T, M0, M) :-
 1520    !,
 1521    M2 is max(M1, M0),
 1522    max_nl(T0, T, M2, M).
 1523nl_exact(T, T, M, M).
 1524
 1525
 1526nl(Out, N) :-
 1527    forall(between(1, N, _), nl(Out)).
 1528
 1529
 1530print_char('<', Out) :- !, write(Out, '$<$').
 1531print_char('>', Out) :- !, write(Out, '$>$').
 1532print_char('{', Out) :- !, write(Out, '\\{').
 1533print_char('}', Out) :- !, write(Out, '\\}').
 1534print_char('$', Out) :- !, write(Out, '\\$').
 1535print_char('&', Out) :- !, write(Out, '\\&').
 1536print_char('#', Out) :- !, write(Out, '\\#').
 1537print_char('%', Out) :- !, write(Out, '\\%').
 1538print_char('~', Out) :- !, write(Out, '\\Stilde{}').
 1539print_char('\\',Out) :- !, write(Out, '\\bsl{}').
 1540print_char('^', Out) :- !, write(Out, '\\Shat{}').
 1541print_char('|', Out) :- !, write(Out, '\\Sbar{}').
 1542print_char(C,   Out) :- put_char(Out, C).
 identifier(+Atom) is semidet
True if Atom is (lower, alnum*).
 1549identifier(Atom) :-
 1550    atom_chars(Atom, [C0|Chars]),
 1551    char_type(C0, lower),
 1552    all_chartype(Chars, alnum).
 1553
 1554all_chartype([], _).
 1555all_chartype([H|T], Type) :-
 1556    char_type(H, Type),
 1557    all_chartype(T, Type).
 1558
 1559
 1560                 /*******************************
 1561                 *    LATEX SPECIAL SEQUENCES   *
 1562                 *******************************/
 urldef_name(?String, ?DefName)
True if \DefName is a urldef for String. UrlDefs are LaTeX sequences that can be used to represent strings with symbols in fragile environments. Whenever a word can be expressed with a urldef, we will do this to enhance the robustness of the generated LaTeX code.
 1572:- dynamic
 1573    urldef_name/2,
 1574    urlchar/1,                      % true if C appears in ine of them
 1575    urldefs_loaded/1.
 load_urldefs
 load_urldefs(+File)
Load \urldef definitions from File and populate urldef_name/2. See pldoc.sty for details.
 1583load_urldefs :-
 1584    urldefs_loaded(_),
 1585    !.
 1586load_urldefs :-
 1587    absolute_file_name(library('pldoc/pldoc.sty'), File,
 1588                       [ access(read) ]),
 1589    load_urldefs(File).
 1590
 1591load_urldefs(File) :-
 1592    urldefs_loaded(File),
 1593    !.
 1594load_urldefs(File) :-
 1595    open(File, read, In),
 1596    call_cleanup((   read_line_to_codes(In, L0),
 1597                     process_urldefs(L0, In)),
 1598                 close(In)),
 1599    assert(urldefs_loaded(File)).
 1600
 1601process_urldefs(end_of_file, _) :- !.
 1602process_urldefs(Line, In) :-
 1603    (   phrase(urldef(Name, String), Line)
 1604    ->  assert(urldef_name(String, Name)),
 1605        assert_chars(String)
 1606    ;   true
 1607    ),
 1608    read_line_to_codes(In, L2),
 1609    process_urldefs(L2, In).
 1610
 1611assert_chars(String) :-
 1612    atom_chars(String, Chars),
 1613    (   member(C, Chars),
 1614        \+ urlchar(C),
 1615        assert(urlchar(C)),
 1616        fail
 1617    ;   true
 1618    ).
 1619
 1620urldef(Name, String) -->
 1621    "\\urldef{\\", string(NameS), "}\\satom{", string(StringS), "}",
 1622    ws,
 1623    (   "%"
 1624    ->  string(_)
 1625    ;   []
 1626    ),
 1627    eol,
 1628    !,
 1629    { atom_codes(Name, NameS),
 1630      atom_codes(String, StringS)
 1631    }.
 1632
 1633ws --> [C], { C =< 32 }, !, ws.
 1634ws --> [].
 1635
 1636string([]) --> [].
 1637string([H|T]) --> [H], string(T).
 1638
 1639eol([],[]).
 1640
 1641
 1642                 /*******************************
 1643                 *         HEADER/FOOTER        *
 1644                 *******************************/
 1645
 1646latex_header(Out, Options) :-
 1647    (   option(stand_alone(true), Options, true)
 1648    ->  forall(header(Line), format(Out, '~w~n', [Line]))
 1649    ;   true
 1650    ),
 1651    forall(generated(Line), format(Out, '~w~n', [Line])).
 1652
 1653latex_footer(Out, Options) :-
 1654    (   option(stand_alone(true), Options, true)
 1655    ->  forall(footer(Line), format(Out, '~w~n', [Line]))
 1656    ;   true
 1657    ).
 1658
 1659header('\\documentclass[11pt]{article}').
 1660header('\\usepackage{times}').
 1661header('\\usepackage{pldoc}').
 1662header('\\sloppy').
 1663header('\\makeindex').
 1664header('').
 1665header('\\begin{document}').
 1666
 1667footer('').
 1668footer('\\printindex').
 1669footer('\\end{document}').
 1670
 1671generated('% This LaTeX document was generated using the LaTeX backend of PlDoc,').
 1672generated('% The SWI-Prolog documentation system').
 1673generated('').
 1674
 1675
 1676		 /*******************************
 1677		 *            MESSAGES		*
 1678		 *******************************/
 1679
 1680:- multifile
 1681    prolog:message//1. 1682
 1683prolog:message(pldoc(no_summary_for(Obj))) -->
 1684    [ 'No summary documentation for ~p'-[Obj] ]