View source with formatted 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/projects/xpce/
    6    Copyright (c)  2011-2016, 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(prolog_colour,
   37          [ prolog_colourise_stream/3,  % +Stream, +SourceID, :ColourItem
   38            prolog_colourise_term/4,    % +Stream, +SourceID, :ColourItem, +Opts
   39            prolog_colourise_query/3,   % +String, +SourceID, :ColourItem
   40            syntax_colour/2,            % +Class, -Attributes
   41            syntax_message//1           % +Class
   42          ]).   43:- use_module(library(prolog_xref)).   44:- use_module(library(predicate_options)).   45:- use_module(library(prolog_source)).   46:- use_module(library(lists)).   47:- use_module(library(operators)).   48:- use_module(library(debug)).   49:- use_module(library(error)).   50:- use_module(library(option)).   51:- use_module(library(record)).   52
   53:- meta_predicate
   54    prolog_colourise_stream(+, +, 3),
   55    prolog_colourise_query(+, +, 3),
   56    prolog_colourise_term(+, +, 3, +).   57
   58:- predicate_options(prolog_colourise_term/4, 4,
   59                     [ subterm_positions(-any)
   60                     ]).   61
   62/** <module> Prolog syntax colouring support.
   63
   64This module defines reusable code to colourise Prolog source.
   65
   66@tbd: The one-term version
   67*/
   68
   69
   70:- multifile
   71    style/2,                        % +ColourClass, -Attributes
   72    message//1,                     % +ColourClass
   73    term_colours/2,                 % +SourceTerm, -ColourSpec
   74    goal_colours/2,                 % +Goal, -ColourSpec
   75    goal_colours/3,                 % +Goal, +Class, -ColourSpec
   76    directive_colours/2,            % +Goal, -ColourSpec
   77    goal_classification/2,          % +Goal, -Class
   78    vararg_goal_classification/3.   % +Name, +Arity, -Class
   79
   80
   81:- record
   82    colour_state(source_id_list,
   83                 module,
   84                 stream,
   85                 closure,
   86                 singletons).   87
   88colour_state_source_id(State, SourceID) :-
   89    colour_state_source_id_list(State, SourceIDList),
   90    member(SourceID, SourceIDList).
   91
   92%!  prolog_colourise_stream(+Stream, +SourceID, :ColourItem) is det.
   93%
   94%   Determine colour fragments for the data   on Stream. SourceID is
   95%   the  canonical  identifier  of  the  input    as  known  to  the
   96%   cross-referencer, i.e., as created using xref_source(SourceID).
   97%
   98%   ColourItem is a closure  that  is   called  for  each identified
   99%   fragment with three additional arguments:
  100%
  101%     * The syntactical category
  102%     * Start position (character offset) of the fragment
  103%     * Length of the fragment (in characters).
  104
  105prolog_colourise_stream(Fd, SourceId, ColourItem) :-
  106    to_list(SourceId, SourceIdList),
  107    make_colour_state([ source_id_list(SourceIdList),
  108                        stream(Fd),
  109                        closure(ColourItem)
  110                      ],
  111                      TB),
  112    setup_call_cleanup(
  113        save_settings(TB, State),
  114        colourise_stream(Fd, TB),
  115        restore_settings(State)).
  116
  117to_list(List, List) :-
  118    is_list(List),
  119    !.
  120to_list(One, [One]).
  121
  122
  123colourise_stream(Fd, TB) :-
  124    (   peek_char(Fd, #)            % skip #! script line
  125    ->  skip(Fd, 10)
  126    ;   true
  127    ),
  128    repeat,
  129        colour_state_module(TB, SM),
  130        character_count(Fd, Start),
  131        catch(read_term(Fd, Term,
  132                        [ subterm_positions(TermPos),
  133                          singletons(Singletons),
  134                          module(SM),
  135                          comments(Comments)
  136                        ]),
  137              E,
  138              read_error(E, TB, Start, Fd)),
  139        fix_operators(Term, SM, TB),
  140        colour_state_singletons(TB, Singletons),
  141        (   colourise_term(Term, TB, TermPos, Comments)
  142        ->  true
  143        ;   arg(1, TermPos, From),
  144            print_message(warning,
  145                          format('Failed to colourise ~p at index ~d~n',
  146                                 [Term, From]))
  147        ),
  148        Term == end_of_file,
  149    !.
  150
  151save_settings(TB, state(Style, Flags, OSM)) :-
  152    (   source_module(TB, SM)
  153    ->  true
  154    ;   SM = prolog_colour_ops
  155    ),
  156    '$set_source_module'(OSM, SM),
  157    colour_state_module(TB, SM),
  158    push_operators([]),
  159    syntax_flags(Flags),
  160    '$style_check'(Style, Style).
  161
  162restore_settings(state(Style, Flags, OSM)) :-
  163    restore_syntax_flags(Flags),
  164    '$style_check'(_, Style),
  165    pop_operators,
  166    '$set_source_module'(OSM).
  167
  168syntax_flags(Pairs) :-
  169    findall(set_prolog_flag(Flag, Value),
  170            syntax_flag(Flag, Value),
  171            Pairs).
  172
  173syntax_flag(Flag, Value) :-
  174    syntax_flag(Flag),
  175    current_prolog_flag(Flag, Value).
  176
  177restore_syntax_flags([]).
  178restore_syntax_flags([set_prolog_flag(Flag, Value)|T]) :-
  179    set_prolog_flag(Flag, Value),
  180    restore_syntax_flags(T).
  181
  182%!  source_module(+State, -Module) is semidet.
  183%
  184%   True when Module is the module context   into  which the file is
  185%   loaded. This is the module of the file if File is a module file,
  186%   or the load context of  File  if   File  is  not included or the
  187%   module context of the file into which the file was included.
  188
  189source_module(TB, Module) :-
  190    colour_state_source_id_list(TB, []),
  191    !,
  192    colour_state_module(TB, Module).
  193source_module(TB, Module) :-
  194    colour_state_source_id(TB, SourceId),
  195    xref_option(SourceId, module(Module)),
  196    !.
  197source_module(TB, Module) :-
  198    (   colour_state_source_id(TB, File),
  199        atom(File)
  200    ;   colour_state_stream(TB, Fd),
  201        is_stream(Fd),
  202        stream_property(Fd, file_name(File))
  203    ),
  204    module_context(File, [], Module).
  205
  206module_context(File, _, Module) :-
  207    source_file_property(File, module(Module)),
  208    !.
  209module_context(File, Seen, Module) :-
  210    source_file_property(File, included_in(File2, _Line)),
  211    \+ memberchk(File, Seen),
  212    !,
  213    module_context(File2, [File|Seen], Module).
  214module_context(File, _, Module) :-
  215    source_file_property(File, load_context(Module, _, _)).
  216
  217
  218%!  read_error(+Error, +TB, +Start, +Stream) is failure.
  219%
  220%   If this is a syntax error, create a syntax-error fragment.
  221
  222read_error(Error, TB, Start, EndSpec) :-
  223    (   syntax_error(Error, Id, CharNo)
  224    ->  message_to_string(error(syntax_error(Id), _), Msg),
  225        (   integer(EndSpec)
  226        ->  End = EndSpec
  227        ;   character_count(EndSpec, End)
  228        ),
  229        show_syntax_error(TB, CharNo:Msg, Start-End),
  230        fail
  231    ;   throw(Error)
  232    ).
  233
  234syntax_error(error(syntax_error(Id), stream(_S, _Line, _LinePos, CharNo)),
  235             Id, CharNo).
  236syntax_error(error(syntax_error(Id), file(_S, _Line, _LinePos, CharNo)),
  237             Id, CharNo).
  238syntax_error(error(syntax_error(Id), string(_Text, CharNo)),
  239             Id, CharNo).
  240
  241%!  colour_item(+Class, +TB, +Pos) is det.
  242
  243colour_item(Class, TB, Pos) :-
  244    arg(1, Pos, Start),
  245    arg(2, Pos, End),
  246    Len is End - Start,
  247    colour_state_closure(TB, Closure),
  248    call(Closure, Class, Start, Len).
  249
  250
  251%!  safe_push_op(+Prec, +Type, :Name, +State)
  252%
  253%   Define operators into the default source module and register
  254%   them to be undone by pop_operators/0.
  255
  256safe_push_op(P, T, N0, State) :-
  257    colour_state_module(State, CM),
  258    strip_module(CM:N0, M, N),
  259    (   is_list(N)
  260    ->  acyclic_term(N),
  261        forall(member(Name, N),
  262               safe_push_op(P, T, M:Name, State))
  263    ;   push_op(P, T, M:N)
  264    ),
  265    debug(colour, ':- ~w.', [op(P,T,M:N)]).
  266
  267%!  fix_operators(+Term, +Module, +State) is det.
  268%
  269%   Fix flags that affect the  syntax,   such  as operators and some
  270%   style checking options. Src is the  canonical source as required
  271%   by the cross-referencer.
  272
  273fix_operators((:- Directive), M, Src) :-
  274    ground(Directive),
  275    catch(process_directive(Directive, M, Src), _, true),
  276    !.
  277fix_operators(_, _, _).
  278
  279process_directive(style_check(X), _, _) :-
  280    !,
  281    style_check(X).
  282process_directive(set_prolog_flag(Flag, Value), M, _) :-
  283    syntax_flag(Flag),
  284    !,
  285    set_prolog_flag(M:Flag, Value).
  286process_directive(M:op(P,T,N), _, Src) :-
  287    !,
  288    process_directive(op(P,T,N), M, Src).
  289process_directive(op(P,T,N), M, Src) :-
  290    !,
  291    safe_push_op(P, T, M:N, Src).
  292process_directive(module(_Name, Export), M, Src) :-
  293    !,
  294    forall(member(op(P,A,N), Export),
  295           safe_push_op(P,A,M:N, Src)).
  296process_directive(use_module(Spec), _, Src) :-
  297    !,
  298    catch(process_use_module(Spec, Src), _, true).
  299process_directive(Directive, _, Src) :-
  300    prolog_source:expand((:-Directive), Src, _).
  301
  302syntax_flag(character_escapes).
  303syntax_flag(var_prefix).
  304syntax_flag(allow_variable_name_as_functor).
  305syntax_flag(allow_dot_in_atom).
  306
  307%!  process_use_module(+Imports, +Src)
  308%
  309%   Get the exported operators from the referenced files.
  310
  311process_use_module([], _) :- !.
  312process_use_module([H|T], Src) :-
  313    !,
  314    process_use_module(H, Src),
  315    process_use_module(T, Src).
  316process_use_module(File, Src) :-
  317    (   xref_public_list(File, Src,
  318                         [ exports(Exports),
  319                           silent(true),
  320                           path(Path)
  321                         ])
  322    ->  forall(member(op(P,T,N), Exports),
  323               safe_push_op(P,T,N,Src)),
  324        colour_state_module(Src, SM),
  325        (   member(Syntax/4, Exports),
  326            load_quasi_quotation_syntax(SM:Path, Syntax),
  327            fail
  328        ;   true
  329        )
  330    ;   true
  331    ).
  332
  333
  334%!  prolog_colourise_query(+Query:string, +SourceId, :ColourItem)
  335%
  336%   Colourise a query, to be executed in the context of SourceId.
  337%
  338%   @arg    SourceId Execute Query in the context of
  339%           the cross-referenced environment SourceID.
  340
  341prolog_colourise_query(QueryString, SourceID, ColourItem) :-
  342    query_colour_state(SourceID, ColourItem, TB),
  343    setup_call_cleanup(
  344        save_settings(TB, State),
  345        colourise_query(QueryString, TB),
  346        restore_settings(State)).
  347
  348query_colour_state(module(Module), ColourItem, TB) :-
  349    !,
  350    make_colour_state([ source_id_list([]),
  351                        module(Module),
  352                        closure(ColourItem)
  353                      ],
  354                      TB).
  355query_colour_state(SourceID, ColourItem, TB) :-
  356    to_list(SourceID, SourceIDList),
  357    make_colour_state([ source_id_list(SourceIDList),
  358                        closure(ColourItem)
  359                      ],
  360                      TB).
  361
  362
  363colourise_query(QueryString, TB) :-
  364    colour_state_module(TB, SM),
  365    string_length(QueryString, End),
  366    (   catch(term_string(Query, QueryString,
  367                          [ subterm_positions(TermPos),
  368                            singletons(Singletons),
  369                            module(SM),
  370                            comments(Comments)
  371                          ]),
  372              E,
  373              read_error(E, TB, 0, End))
  374    ->  colour_state_singletons(TB, Singletons),
  375        colourise_comments(Comments, TB),
  376        (   Query == end_of_file
  377        ->  true
  378        ;   colourise_body(Query, TB, TermPos)
  379        )
  380    ;   true                        % only a syntax error
  381    ).
  382
  383%!  prolog_colourise_term(+Stream, +SourceID, :ColourItem, +Options)
  384%
  385%   Colourise    the    next     term      on     Stream.     Unlike
  386%   prolog_colourise_stream/3, this predicate assumes  it is reading
  387%   a single term rather than the   entire stream. This implies that
  388%   it cannot adjust syntax according to directives that preceed it.
  389%
  390%   Options:
  391%
  392%     * subterm_positions(-TermPos)
  393%     Return complete term-layout.  If an error is read, this is a
  394%     term error_position(StartClause, EndClause, ErrorPos)
  395
  396prolog_colourise_term(Stream, SourceId, ColourItem, Options) :-
  397    to_list(SourceId, SourceIdList),
  398    make_colour_state([ source_id_list(SourceIdList),
  399                        stream(Stream),
  400                        closure(ColourItem)
  401                      ],
  402                      TB),
  403    option(subterm_positions(TermPos), Options, _),
  404    findall(Op, xref_op(SourceId, Op), Ops),
  405    findall(Opt, xref_flag_option(SourceId, Opt), Opts),
  406    character_count(Stream, Start),
  407    (   source_module(TB, Module)
  408    ->  true
  409    ;   Module = prolog_colour_ops
  410    ),
  411    read_source_term_at_location(
  412        Stream, Term,
  413        [ module(Module),
  414          operators(Ops),
  415          error(Error),
  416          subterm_positions(TermPos),
  417          singletons(Singletons),
  418          comments(Comments)
  419        | Opts
  420        ]),
  421    (   var(Error)
  422    ->  colour_state_singletons(TB, Singletons),
  423        colour_item(range, TB, TermPos),            % Call to allow clearing
  424        colourise_term(Term, TB, TermPos, Comments)
  425    ;   character_count(Stream, End),
  426        TermPos = error_position(Start, End, Pos),
  427        colour_item(range, TB, TermPos),
  428        show_syntax_error(TB, Error, Start-End),
  429        Error = Pos:_Message
  430    ).
  431
  432xref_flag_option(TB, var_prefix(Bool)) :-
  433    xref_prolog_flag(TB, var_prefix, Bool, _Line).
  434
  435show_syntax_error(TB, Pos:Message, Range) :-
  436    integer(Pos),
  437    !,
  438    End is Pos + 1,
  439    colour_item(syntax_error(Message, Range), TB, Pos-End).
  440show_syntax_error(TB, _:Message, Range) :-
  441    colour_item(syntax_error(Message, Range), TB, Range).
  442
  443
  444singleton(Var, TB) :-
  445    colour_state_singletons(TB, Singletons),
  446    member_var(Var, Singletons).
  447
  448member_var(V, [_=V2|_]) :-
  449    V == V2,
  450    !.
  451member_var(V, [_|T]) :-
  452    member_var(V, T).
  453
  454%!  colourise_term(+Term, +TB, +Termpos, +Comments)
  455%
  456%   Colourise the next Term.
  457%
  458%   @bug    The colour spec is closed with =fullstop=, but the
  459%           position information does not include the full stop
  460%           location, so all we can do is assume it is behind the
  461%           term.
  462
  463colourise_term(Term, TB, TermPos, Comments) :-
  464    colourise_comments(Comments, TB),
  465    (   Term == end_of_file
  466    ->  true
  467    ;   colourise_term(Term, TB, TermPos),
  468        colourise_fullstop(TB, TermPos)
  469    ).
  470
  471colourise_fullstop(TB, TermPos) :-
  472    arg(2, TermPos, EndTerm),
  473    Start is EndTerm,
  474    End is Start+1,
  475    colour_item(fullstop, TB, Start-End).
  476
  477colourise_comments(-, _).
  478colourise_comments([], _).
  479colourise_comments([H|T], TB) :-
  480    colourise_comment(H, TB),
  481    colourise_comments(T, TB).
  482
  483colourise_comment((-)-_, _) :- !.
  484colourise_comment(Pos-Comment, TB) :-
  485    comment_style(Comment, Style),
  486    stream_position_data(char_count, Pos, Start),
  487    string_length(Comment, Len),
  488    End is Start + Len + 1,
  489    colour_item(comment(Style), TB, Start-End).
  490
  491comment_style(Comment, structured) :-           % Starts %%, %! or /**
  492    structured_comment_start(Start),
  493    sub_string(Comment, 0, Len, _, Start),
  494    Next is Len+1,
  495    string_code(Next, Comment, NextCode),
  496    code_type(NextCode, space),
  497    !.
  498comment_style(Comment, line) :-                 % Starts %
  499    sub_string(Comment, 0, _, _, '%'),
  500    !.
  501comment_style(_, block).                        % Starts /*
  502
  503%!  structured_comment_start(-Start)
  504%
  505%   Copied from library(pldoc/doc_process). Unfortunate,   but we do
  506%   not want to force loading pldoc.
  507
  508structured_comment_start('%%').
  509structured_comment_start('%!').
  510structured_comment_start('/**').
  511
  512%!  colourise_term(+Term, +TB, +Pos)
  513%
  514%   Colorise a file toplevel term.
  515
  516colourise_term(Var, TB, Start-End) :-
  517    var(Var),
  518    !,
  519    colour_item(instantiation_error, TB, Start-End).
  520colourise_term(_, _, Pos) :-
  521    var(Pos),
  522    !.
  523colourise_term(Term, TB, parentheses_term_position(PO,PC,Pos)) :-
  524    !,
  525    colour_item(parentheses, TB, PO-PC),
  526    colourise_term(Term, TB, Pos).
  527colourise_term(Term, TB, Pos) :-
  528    term_colours(Term, FuncSpec-ArgSpecs),
  529    !,
  530    Pos = term_position(F,T,FF,FT,ArgPos),
  531    colour_item(term, TB, F-T),     % TBD: Allow specifying by term_colours/2?
  532    specified_item(FuncSpec, Term, TB, FF-FT),
  533    specified_items(ArgSpecs, Term, TB, ArgPos).
  534colourise_term((Head :- Body), TB,
  535               term_position(F,T,FF,FT,[HP,BP])) :-
  536    !,
  537    colour_item(clause,         TB, F-T),
  538    colour_item(neck(clause),   TB, FF-FT),
  539    colourise_clause_head(Head, TB, HP),
  540    colourise_body(Body, Head,  TB, BP).
  541colourise_term(((Head,RHC) --> Body), TB,
  542               term_position(F,T,FF,FT,
  543                             [ term_position(_,_,_,_,[HP,RHCP]),
  544                               BP
  545                             ])) :-
  546    !,
  547    colour_item(grammar_rule,       TB, F-T),
  548    colour_item(dcg_right_hand_ctx, TB, RHCP),
  549    colourise_term_arg(RHC, TB, RHCP),
  550    colour_item(neck(grammar_rule), TB, FF-FT),
  551    colourise_extended_head(Head, 2, TB, HP),
  552    colourise_dcg(Body, Head,       TB, BP).
  553colourise_term((Head --> Body), TB,                     % TBD: expansion!
  554               term_position(F,T,FF,FT,[HP,BP])) :-
  555    !,
  556    colour_item(grammar_rule,       TB, F-T),
  557    colour_item(neck(grammar_rule), TB, FF-FT),
  558    colourise_extended_head(Head, 2, TB, HP),
  559    colourise_dcg(Body, Head,       TB, BP).
  560colourise_term(:->(Head, Body), TB,
  561               term_position(F,T,FF,FT,[HP,BP])) :-
  562    !,
  563    colour_item(method,             TB, F-T),
  564    colour_item(neck(method(send)), TB, FF-FT),
  565    colour_method_head(send(Head),  TB, HP),
  566    colourise_method_body(Body,     TB, BP).
  567colourise_term(:<-(Head, Body), TB,
  568               term_position(F,T,FF,FT,[HP,BP])) :-
  569    !,
  570    colour_item(method,            TB, F-T),
  571    colour_item(neck(method(get)), TB, FF-FT),
  572    colour_method_head(get(Head),  TB, HP),
  573    colourise_method_body(Body,    TB, BP).
  574colourise_term((:- Directive), TB, Pos) :-
  575    !,
  576    colour_item(directive, TB, Pos),
  577    Pos = term_position(_F,_T,FF,FT,[ArgPos]),
  578    colour_item(neck(directive), TB, FF-FT),
  579    colourise_directive(Directive, TB, ArgPos).
  580colourise_term((?- Directive), TB, Pos) :-
  581    !,
  582    colourise_term((:- Directive), TB, Pos).
  583colourise_term(end_of_file, _, _) :- !.
  584colourise_term(Fact, TB, Pos) :-
  585    !,
  586    colour_item(clause, TB, Pos),
  587    colourise_clause_head(Fact, TB, Pos).
  588
  589%!  colourise_extended_head(+Head, +ExtraArgs, +TB, +Pos) is det.
  590%
  591%   Colourise a clause-head that  is   extended  by  term_expansion,
  592%   getting ExtraArgs more  arguments  (e.g.,   DCGs  add  two  more
  593%   arguments.
  594
  595colourise_extended_head(Head, N, TB, Pos) :-
  596    extend(Head, N, TheHead),
  597    colourise_clause_head(TheHead, TB, Pos).
  598
  599extend(M:Head, N, M:ExtHead) :-
  600    nonvar(Head),
  601    !,
  602    extend(Head, N, ExtHead).
  603extend(Head, N, ExtHead) :-
  604    compound(Head),
  605    !,
  606    compound_name_arguments(Head, Name, Args),
  607    length(Extra, N),
  608    append(Args, Extra, NArgs),
  609    compound_name_arguments(ExtHead, Name, NArgs).
  610extend(Head, N, ExtHead) :-
  611    atom(Head),
  612    !,
  613    length(Extra, N),
  614    compound_name_arguments(ExtHead, Head, Extra).
  615extend(Head, _, Head).
  616
  617
  618colourise_clause_head(_, _, Pos) :-
  619    var(Pos),
  620    !.
  621colourise_clause_head(Head, TB, parentheses_term_position(PO,PC,Pos)) :-
  622    colour_item(parentheses, TB, PO-PC),
  623    colourise_clause_head(Head, TB, Pos).
  624colourise_clause_head(M:Head, TB, QHeadPos) :-
  625    QHeadPos = term_position(_,_,QF,QT,[MPos,HeadPos]),
  626    head_colours(M:Head, meta-[_, ClassSpec-ArgSpecs]),
  627    !,
  628    colour_item(module(M), TB, MPos),
  629    colour_item(functor, TB, QF-QT),
  630    functor_position(HeadPos, FPos, ArgPos),
  631    (   ClassSpec == classify
  632    ->  classify_head(TB, Head, Class)
  633    ;   Class = ClassSpec
  634    ),
  635    colour_item(head_term(Class, Head), TB, QHeadPos),
  636    colour_item(head(Class, Head), TB, FPos),
  637    specified_items(ArgSpecs, Head, TB, ArgPos).
  638colourise_clause_head(Head, TB, Pos) :-
  639    head_colours(Head, ClassSpec-ArgSpecs),
  640    !,
  641    functor_position(Pos, FPos, ArgPos),
  642    (   ClassSpec == classify
  643    ->  classify_head(TB, Head, Class)
  644    ;   Class = ClassSpec
  645    ),
  646    colour_item(head_term(Class, Head), TB, Pos),
  647    colour_item(head(Class, Head), TB, FPos),
  648    specified_items(ArgSpecs, Head, TB, ArgPos).
  649colourise_clause_head(:=(Eval, Ret), TB,
  650                      term_position(_,_,AF,AT,
  651                                    [ term_position(_,_,SF,ST,
  652                                                    [ SelfPos,
  653                                                      FuncPos
  654                                                    ]),
  655                                      RetPos
  656                                    ])) :-
  657    Eval =.. [.,M,Func],
  658    FuncPos = term_position(_,_,FF,FT,_),
  659    !,
  660    colourise_term_arg(M, TB, SelfPos),
  661    colour_item(func_dot, TB, SF-ST),               % .
  662    colour_item(dict_function(Func), TB, FF-FT),
  663    colourise_term_args(Func, TB, FuncPos),
  664    colour_item(dict_return_op, TB, AF-AT),         % :=
  665    colourise_term_arg(Ret, TB, RetPos).
  666colourise_clause_head(Head, TB, Pos) :-
  667    functor_position(Pos, FPos, _),
  668    classify_head(TB, Head, Class),
  669    colour_item(head_term(Class, Head), TB, Pos),
  670    colour_item(head(Class, Head), TB, FPos),
  671    colourise_term_args(Head, TB, Pos).
  672
  673%!  colourise_extern_head(+Head, +Module, +TB, +Pos)
  674%
  675%   Colourise the head specified as Module:Head. Normally used for
  676%   adding clauses to multifile predicates in other modules.
  677
  678colourise_extern_head(Head, M, TB, Pos) :-
  679    functor_position(Pos, FPos, _),
  680    colour_item(head(extern(M), Head), TB, FPos),
  681    colourise_term_args(Head, TB, Pos).
  682
  683colour_method_head(SGHead, TB, Pos) :-
  684    arg(1, SGHead, Head),
  685    functor_name(SGHead, SG),
  686    functor_position(Pos, FPos, _),
  687    colour_item(method(SG), TB, FPos),
  688    colourise_term_args(Head, TB, Pos).
  689
  690%!  functor_position(+Term, -FunctorPos, -ArgPosList)
  691%
  692%   Get the position of a functor   and  its argument. Unfortunately
  693%   this goes wrong for lists, who have two `functor-positions'.
  694
  695functor_position(term_position(_,_,FF,FT,ArgPos), FF-FT, ArgPos) :- !.
  696functor_position(list_position(F,_T,Elms,none), F-FT, Elms) :-
  697    !,
  698    FT is F + 1.
  699functor_position(dict_position(_,_,FF,FT,KVPos), FF-FT, KVPos) :- !.
  700functor_position(brace_term_position(F,T,Arg), F-T, [Arg]) :- !.
  701functor_position(Pos, Pos, []).
  702
  703
  704%!  colourise_directive(+Body, +TB, +Pos)
  705%
  706%   Colourise the body of a directive.
  707
  708colourise_directive(_,_,Pos) :-
  709    var(Pos),
  710    !.
  711colourise_directive(Dir, TB, parentheses_term_position(PO,PC,Pos)) :-
  712    !,
  713    colour_item(parentheses, TB, PO-PC),
  714    colourise_directive(Dir, TB, Pos).
  715colourise_directive((A,B), TB, term_position(_,_,_,_,[PA,PB])) :-
  716    !,
  717    colourise_directive(A, TB, PA),
  718    colourise_directive(B, TB, PB).
  719colourise_directive(Body, TB, Pos) :-
  720    nonvar(Body),
  721    directive_colours(Body, ClassSpec-ArgSpecs),   % specified
  722    !,
  723    functor_position(Pos, FPos, ArgPos),
  724    (   ClassSpec == classify
  725    ->  goal_classification(TB, Body, [], Class)
  726    ;   Class = ClassSpec
  727    ),
  728    colour_item(goal(Class, Body), TB, FPos),
  729    specified_items(ArgSpecs, Body, TB, ArgPos).
  730colourise_directive(Body, TB, Pos) :-
  731    colourise_body(Body, TB, Pos).
  732
  733
  734%       colourise_body(+Body, +TB, +Pos)
  735%
  736%       Breaks down to colourise_goal/3.
  737
  738colourise_body(Body, TB, Pos) :-
  739    colourise_body(Body, [], TB, Pos).
  740
  741colourise_body(Body, Origin, TB, Pos) :-
  742    colour_item(body, TB, Pos),
  743    colourise_goals(Body, Origin, TB, Pos).
  744
  745%!  colourise_method_body(+MethodBody, +TB, +Pos)
  746%
  747%   Colourise the optional "comment":: as pce(comment) and proceed
  748%   with the body.
  749%
  750%   @tbd    Get this handled by a hook.
  751
  752colourise_method_body(_, _, Pos) :-
  753    var(Pos),
  754    !.
  755colourise_method_body(Body, TB, parentheses_term_position(PO,PC,Pos)) :-
  756    !,
  757    colour_item(parentheses, TB, PO-PC),
  758    colourise_method_body(Body, TB, Pos).
  759colourise_method_body(::(_Comment,Body), TB,
  760                      term_position(_F,_T,_FF,_FT,[CP,BP])) :-
  761    !,
  762    colour_item(comment(string), TB, CP),
  763    colourise_body(Body, TB, BP).
  764colourise_method_body(Body, TB, Pos) :-         % deal with pri(::) < 1000
  765    Body =.. [F,A,B],
  766    control_op(F),
  767    !,
  768    Pos = term_position(_F,_T,FF,FT,
  769                        [ AP,
  770                          BP
  771                        ]),
  772    colour_item(control, TB, FF-FT),
  773    colourise_method_body(A, TB, AP),
  774    colourise_body(B, TB, BP).
  775colourise_method_body(Body, TB, Pos) :-
  776    colourise_body(Body, TB, Pos).
  777
  778control_op(',').
  779control_op((;)).
  780control_op((->)).
  781control_op((*->)).
  782
  783%!  colourise_goals(+Body, +Origin, +TB, +Pos)
  784%
  785%   Colourise the goals in a body.
  786
  787colourise_goals(_, _, _, Pos) :-
  788    var(Pos),
  789    !.
  790colourise_goals(Body, Origin, TB, parentheses_term_position(PO,PC,Pos)) :-
  791    !,
  792    colour_item(parentheses, TB, PO-PC),
  793    colourise_goals(Body, Origin, TB, Pos).
  794colourise_goals(Body, Origin, TB, term_position(_,_,FF,FT,ArgPos)) :-
  795    body_compiled(Body),
  796    !,
  797    colour_item(control, TB, FF-FT),
  798    colourise_subgoals(ArgPos, 1, Body, Origin, TB).
  799colourise_goals(Goal, Origin, TB, Pos) :-
  800    colourise_goal(Goal, Origin, TB, Pos).
  801
  802colourise_subgoals([], _, _, _, _).
  803colourise_subgoals([Pos|T], N, Body, Origin, TB) :-
  804    arg(N, Body, Arg),
  805    colourise_goals(Arg, Origin, TB, Pos),
  806    NN is N + 1,
  807    colourise_subgoals(T, NN, Body, Origin, TB).
  808
  809%!  colourise_dcg(+Body, +Head, +TB, +Pos)
  810%
  811%   Breaks down to colourise_dcg_goal/3.
  812
  813colourise_dcg(Body, Head, TB, Pos) :-
  814    colour_item(dcg, TB, Pos),
  815    (   dcg_extend(Head, Origin)
  816    ->  true
  817    ;   Origin = Head
  818    ),
  819    colourise_dcg_goals(Body, Origin, TB, Pos).
  820
  821colourise_dcg_goals(Var, _, TB, Pos) :-
  822    var(Var),
  823    !,
  824    colour_item(goal(meta,Var), TB, Pos).
  825colourise_dcg_goals(_, _, _, Pos) :-
  826    var(Pos),
  827    !.
  828colourise_dcg_goals(Body, Origin, TB, parentheses_term_position(PO,PC,Pos)) :-
  829    !,
  830    colour_item(parentheses, TB, PO-PC),
  831    colourise_dcg_goals(Body, Origin, TB, Pos).
  832colourise_dcg_goals({Body}, Origin, TB, brace_term_position(F,T,Arg)) :-
  833    !,
  834    colour_item(dcg(plain), TB, F-T),
  835    colourise_goals(Body, Origin, TB, Arg).
  836colourise_dcg_goals([], _, TB, Pos) :-
  837    !,
  838    colour_item(dcg(terminal), TB, Pos).
  839colourise_dcg_goals(List, _, TB, list_position(F,T,Elms,Tail)) :-
  840    List = [_|_],
  841    !,
  842    colour_item(dcg(terminal), TB, F-T),
  843    colourise_list_args(Elms, Tail, List, TB, classify).
  844colourise_dcg_goals(_, _, TB, string_position(F,T)) :-
  845    integer(F),
  846    !,
  847    colour_item(dcg(string), TB, F-T).
  848colourise_dcg_goals(Body, Origin, TB, term_position(_,_,FF,FT,ArgPos)) :-
  849    dcg_body_compiled(Body),       % control structures
  850    !,
  851    colour_item(control, TB, FF-FT),
  852    colourise_dcg_subgoals(ArgPos, 1, Body, Origin, TB).
  853colourise_dcg_goals(Goal, Origin, TB, Pos) :-
  854    colourise_dcg_goal(Goal, Origin, TB, Pos).
  855
  856colourise_dcg_subgoals([], _, _, _, _).
  857colourise_dcg_subgoals([Pos|T], N, Body, Origin, TB) :-
  858    arg(N, Body, Arg),
  859    colourise_dcg_goals(Arg, Origin, TB, Pos),
  860    NN is N + 1,
  861    colourise_dcg_subgoals(T, NN, Body, Origin, TB).
  862
  863dcg_extend(Term, _) :-
  864    var(Term), !, fail.
  865dcg_extend(M:Term, M:Goal) :-
  866    dcg_extend(Term, Goal).
  867dcg_extend(Term, Goal) :-
  868    compound(Term),
  869    !,
  870    compound_name_arguments(Term, Name, Args),
  871    append(Args, [_,_], NArgs),
  872    compound_name_arguments(Goal, Name, NArgs).
  873dcg_extend(Term, Goal) :-
  874    atom(Term),
  875    !,
  876    compound_name_arguments(Goal, Term, [_,_]).
  877
  878dcg_body_compiled(G) :-
  879    body_compiled(G),
  880    !.
  881dcg_body_compiled((_|_)).
  882
  883%       colourise_dcg_goal(+Goal, +Origin, +TB, +Pos).
  884
  885colourise_dcg_goal(!, Origin, TB, TermPos) :-
  886    !,
  887    colourise_goal(!, Origin, TB, TermPos).
  888colourise_dcg_goal(Goal, Origin, TB, TermPos) :-
  889    dcg_extend(Goal, TheGoal),
  890    !,
  891    colourise_goal(TheGoal, Origin, TB, TermPos).
  892colourise_dcg_goal(Goal, _, TB, Pos) :-
  893    colourise_term_args(Goal, TB, Pos).
  894
  895
  896%!  colourise_goal(+Goal, +Origin, +TB, +Pos)
  897%
  898%   Colourise access to a single goal.
  899%
  900%   @tbd Quasi Quotations are coloured as a general term argument.
  901%   Possibly we should do something with the goal information it
  902%   refers to, in particular if this goal is not defined.
  903
  904                                        % Deal with list as goal (consult)
  905colourise_goal(_,_,_,Pos) :-
  906    var(Pos),
  907    !.
  908colourise_goal(Goal, Origin, TB, parentheses_term_position(PO,PC,Pos)) :-
  909    !,
  910    colour_item(parentheses, TB, PO-PC),
  911    colourise_goal(Goal, Origin, TB, Pos).
  912colourise_goal(Goal, _, TB, Pos) :-
  913    Pos = list_position(F,T,Elms,_),
  914    Goal = [_|_],
  915    !,
  916    FT is F + 1,
  917    AT is T - 1,
  918    colour_item(goal_term(built_in, Goal), TB, Pos),
  919    colour_item(goal(built_in, Goal), TB, F-FT),
  920    colour_item(goal(built_in, Goal), TB, AT-T),
  921    colourise_file_list(Goal, TB, Elms, any).
  922colourise_goal(Goal, Origin, TB, Pos) :-
  923    Pos = list_position(F,T,Elms,Tail),
  924    callable(Goal),
  925    Goal =.. [_,GH,GT|_],
  926    !,
  927    goal_classification(TB, Goal, Origin, Class),
  928    FT is F + 1,
  929    AT is T - 1,
  930    colour_item(goal_term(Class, Goal), TB, Pos),
  931    colour_item(goal(Class, Goal), TB, F-FT),
  932    colour_item(goal(Class, Goal), TB, AT-T),
  933    colourise_list_args(Elms, Tail, [GH|GT], TB, classify).
  934colourise_goal(Goal, _Origin, TB, Pos) :-
  935    Pos = quasi_quotation_position(_F,_T,_QQType,_QQTypePos,_CPos),
  936    !,
  937    colourise_term_arg(Goal, TB, Pos).
  938colourise_goal(Goal, Origin, TB, Pos) :-
  939    nonvar(Goal),
  940    (   goal_classification(TB, Goal, Origin, ClassInferred),
  941        goal_colours(Goal, ClassInferred, ClassSpec-ArgSpecs)
  942    ->  true
  943    ;   goal_colours(Goal, ClassSpec-ArgSpecs)
  944    ),
  945    !,                                          % specified
  946    functor_position(Pos, FPos, ArgPos),
  947    (   ClassSpec == classify
  948    ->  goal_classification(TB, Goal, Origin, Class)
  949    ;   Class = ClassSpec
  950    ),
  951    colour_item(goal_term(Class, Goal), TB, Pos),
  952    colour_item(goal(Class, Goal), TB, FPos),
  953    colour_dict_braces(TB, Pos),
  954    specified_items(ArgSpecs, Goal, TB, ArgPos).
  955colourise_goal(Module:Goal, _Origin, TB, QGoalPos) :-
  956    QGoalPos = term_position(_,_,QF,QT,[PM,PG]),
  957    !,
  958    colour_item(module(Module), TB, PM),
  959    colour_item(functor, TB, QF-QT),
  960    (   PG = term_position(_,_,FF,FT,_)
  961    ->  FP = FF-FT
  962    ;   FP = PG
  963    ),
  964    colour_item(goal_term(extern(Module), Goal), TB, QGoalPos),
  965    colour_item(goal(extern(Module), Goal), TB, FP),
  966    colourise_goal_args(Goal, Module, TB, PG).
  967colourise_goal(Op, _Origin, TB, Pos) :-
  968    nonvar(Op),
  969    Op = op(_,_,_),
  970    !,
  971    colourise_op_declaration(Op, TB, Pos).
  972colourise_goal(Goal, Origin, TB, Pos) :-
  973    goal_classification(TB, Goal, Origin, Class),
  974    (   Pos = term_position(_,_,FF,FT,_ArgPos)
  975    ->  FPos = FF-FT
  976    ;   FPos = Pos
  977    ),
  978    colour_item(goal_term(Class, Goal), TB, Pos),
  979    colour_item(goal(Class, Goal), TB, FPos),
  980    colourise_goal_args(Goal, TB, Pos).
  981
  982% make sure to emit a fragment for the braces of tag{k:v, ...} or
  983% {...} that is mapped to something else.
  984
  985colour_dict_braces(TB, dict_position(_F,T,_TF,TT,_KVPos)) :-
  986    !,
  987    BStart is TT+1,
  988    colour_item(dict_content, TB, BStart-T).
  989colour_dict_braces(TB, brace_term_position(F,T,_Arg)) :-
  990    !,
  991    colour_item(brace_term, TB, F-T).
  992colour_dict_braces(_, _).
  993
  994%!  colourise_goal_args(+Goal, +TB, +Pos)
  995%
  996%   Colourise the arguments to a goal. This predicate deals with
  997%   meta- and database-access predicates.
  998
  999colourise_goal_args(Goal, TB, Pos) :-
 1000    colourization_module(TB, Module),
 1001    colourise_goal_args(Goal, Module, TB, Pos).
 1002
 1003colourization_module(TB, Module) :-
 1004    (   colour_state_source_id(TB, SourceId),
 1005        xref_module(SourceId, Module)
 1006    ->  true
 1007    ;   Module = user
 1008    ).
 1009
 1010colourise_goal_args(Goal, M, TB, term_position(_,_,_,_,ArgPos)) :-
 1011    !,
 1012    (   meta_args(Goal, TB, MetaArgs)
 1013    ->  colourise_meta_args(1, Goal, M, MetaArgs, TB, ArgPos)
 1014    ;   colourise_goal_args(1, Goal, M, TB, ArgPos)
 1015    ).
 1016colourise_goal_args(Goal, M, TB, brace_term_position(_,_,ArgPos)) :-
 1017    !,
 1018    (   meta_args(Goal, TB, MetaArgs)
 1019    ->  colourise_meta_args(1, Goal, M, MetaArgs, TB, [ArgPos])
 1020    ;   colourise_goal_args(1, Goal, M, TB, [ArgPos])
 1021    ).
 1022colourise_goal_args(_, _, _, _).                % no arguments
 1023
 1024colourise_goal_args(_, _, _, _, []) :- !.
 1025colourise_goal_args(N, Goal, Module, TB, [P0|PT]) :-
 1026    colourise_option_arg(Goal, Module, N, TB, P0),
 1027    !,
 1028    NN is N + 1,
 1029    colourise_goal_args(NN, Goal, Module, TB, PT).
 1030colourise_goal_args(N, Goal, Module, TB, [P0|PT]) :-
 1031    arg(N, Goal, Arg),
 1032    colourise_term_arg(Arg, TB, P0),
 1033    NN is N + 1,
 1034    colourise_goal_args(NN, Goal, Module, TB, PT).
 1035
 1036
 1037colourise_meta_args(_, _, _, _, _, []) :- !.
 1038colourise_meta_args(N, Goal, Module, MetaArgs, TB, [P0|PT]) :-
 1039    colourise_option_arg(Goal, Module, N, TB, P0),
 1040    !,
 1041    NN is N + 1,
 1042    colourise_meta_args(NN, Goal, Module, MetaArgs, TB, PT).
 1043colourise_meta_args(N, Goal, Module, MetaArgs, TB, [P0|PT]) :-
 1044    arg(N, Goal, Arg),
 1045    arg(N, MetaArgs, MetaSpec),
 1046    colourise_meta_arg(MetaSpec, Arg, TB, P0),
 1047    NN is N + 1,
 1048    colourise_meta_args(NN, Goal, Module, MetaArgs, TB, PT).
 1049
 1050colourise_meta_arg(MetaSpec, Arg, TB, Pos) :-
 1051    expand_meta(MetaSpec, Arg, Expanded),
 1052    !,
 1053    colourise_goal(Expanded, [], TB, Pos). % TBD: recursion
 1054colourise_meta_arg(MetaSpec, Arg, TB, Pos) :-
 1055    MetaSpec == //,
 1056    !,
 1057    colourise_dcg_goals(Arg, //, TB, Pos).
 1058colourise_meta_arg(_, Arg, TB, Pos) :-
 1059    colourise_term_arg(Arg, TB, Pos).
 1060
 1061%!  meta_args(+Goal, +TB, -ArgSpec) is semidet.
 1062%
 1063%   Return a copy of Goal, where   each  meta-argument is an integer
 1064%   representing the number of extra arguments   or  the atom // for
 1065%   indicating a DCG  body.  The   non-meta  arguments  are  unbound
 1066%   variables.
 1067%
 1068%   E.g. meta_args(maplist(foo,x,y), X) --> X = maplist(2,_,_)
 1069%
 1070%   NOTE: this could be cached if performance becomes an issue.
 1071
 1072meta_args(Goal, TB, VarGoal) :-
 1073    colour_state_source_id(TB, SourceId),
 1074    xref_meta(SourceId, Goal, _),
 1075    !,
 1076    compound_name_arity(Goal, Name, Arity),
 1077    compound_name_arity(VarGoal, Name, Arity),
 1078    xref_meta(SourceId, VarGoal, MetaArgs),
 1079    instantiate_meta(MetaArgs).
 1080
 1081instantiate_meta([]).
 1082instantiate_meta([H|T]) :-
 1083    (   var(H)
 1084    ->  H = 0
 1085    ;   H = V+N
 1086    ->  V = N
 1087    ;   H = //(V)
 1088    ->  V = (//)
 1089    ),
 1090    instantiate_meta(T).
 1091
 1092%!  expand_meta(+MetaSpec, +Goal, -Expanded) is semidet.
 1093%
 1094%   Add extra arguments to the goal if the meta-specifier is an
 1095%   integer (see above).
 1096
 1097expand_meta(MetaSpec, Goal, Goal) :-
 1098    MetaSpec == 0.
 1099expand_meta(MetaSpec, M:Goal, M:Expanded) :-
 1100    atom(M),
 1101    !,
 1102    expand_meta(MetaSpec, Goal, Expanded).
 1103expand_meta(MetaSpec, Goal, Expanded) :-
 1104    integer(MetaSpec),
 1105    callable(Goal),
 1106    !,
 1107    length(Extra, MetaSpec),
 1108    Goal =.. List0,
 1109    append(List0, Extra, List),
 1110    Expanded =.. List.
 1111
 1112%!  colourise_setof(+Term, +TB, +Pos)
 1113%
 1114%   Colourise the 2nd argument of setof/bagof
 1115
 1116colourise_setof(Var^G, TB, term_position(_,_,FF,FT,[VP,GP])) :-
 1117    !,
 1118    colourise_term_arg(Var, TB, VP),
 1119    colour_item(ext_quant, TB, FF-FT),
 1120    colourise_setof(G, TB, GP).
 1121colourise_setof(Term, TB, Pos) :-
 1122    colourise_goal(Term, [], TB, Pos).
 1123
 1124%       colourise_db(+Arg, +TB, +Pos)
 1125%
 1126%       Colourise database modification calls (assert/1, retract/1 and
 1127%       friends.
 1128
 1129colourise_db((Head:-_Body), TB, term_position(_,_,_,_,[HP,_])) :-
 1130    !,
 1131    colourise_db(Head, TB, HP).
 1132colourise_db(Module:Head, TB, term_position(_,_,QF,QT,[MP,HP])) :-
 1133    !,
 1134    colour_item(module(Module), TB, MP),
 1135    colour_item(functor, TB, QF-QT),
 1136    (   atom(Module),
 1137        colour_state_source_id(TB, SourceId),
 1138        xref_module(SourceId, Module)
 1139    ->  colourise_db(Head, TB, HP)
 1140    ;   colourise_db(Head, TB, HP)
 1141    ).
 1142colourise_db(Head, TB, Pos) :-
 1143    colourise_goal(Head, '<db-change>', TB, Pos).
 1144
 1145
 1146%!  colourise_option_args(+Goal, +Module, +Arg:integer,
 1147%!                        +TB, +ArgPos) is semidet.
 1148%
 1149%   Colourise  predicate  options  for  the    Arg-th   argument  of
 1150%   Module:Goal
 1151
 1152colourise_option_arg(Goal, Module, Arg, TB, ArgPos) :-
 1153    goal_name_arity(Goal, Name, Arity),
 1154    current_option_arg(Module:Name/Arity, Arg),
 1155    current_predicate_options(Module:Name/Arity, Arg, OptionDecl),
 1156    debug(emacs, 'Colouring option-arg ~w of ~p',
 1157          [Arg, Module:Name/Arity]),
 1158    arg(Arg, Goal, Options),
 1159    colourise_option(Options, Module, Goal, Arg, OptionDecl, TB, ArgPos).
 1160
 1161colourise_option(Options0, Module, Goal, Arg, OptionDecl, TB, Pos0) :-
 1162    strip_option_module_qualifier(Goal, Module, Arg, TB,
 1163                                  Options0, Pos0, Options, Pos),
 1164    (   Pos = list_position(F, T, ElmPos, TailPos)
 1165    ->  colour_item(list, TB, F-T),
 1166        colourise_option_list(Options, OptionDecl, TB, ElmPos, TailPos)
 1167    ;   (   var(Options)
 1168        ;   Options == []
 1169        )
 1170    ->  colourise_term_arg(Options, TB, Pos)
 1171    ;   colour_item(type_error(list), TB, Pos)
 1172    ).
 1173
 1174strip_option_module_qualifier(Goal, Module, Arg, TB,
 1175                              M:Options, term_position(_,_,_,_,[MP,Pos]),
 1176                              Options, Pos) :-
 1177    predicate_property(Module:Goal, meta_predicate(Head)),
 1178    arg(Arg, Head, :),
 1179    !,
 1180    colour_item(module(M), TB, MP).
 1181strip_option_module_qualifier(_, _, _, _,
 1182                              Options, Pos, Options, Pos).
 1183
 1184
 1185colourise_option_list(_, _, _, [], none) :- !.
 1186colourise_option_list(Tail, _, TB, [], TailPos) :-
 1187    !,
 1188    colourise_term_arg(Tail, TB, TailPos).
 1189colourise_option_list([H|T], OptionDecl, TB, [HPos|TPos], TailPos) :-
 1190    colourise_option(H, OptionDecl, TB, HPos),
 1191    colourise_option_list(T, OptionDecl, TB, TPos, TailPos).
 1192
 1193colourise_option(Opt, _, TB, Pos) :-
 1194    var(Opt),
 1195    !,
 1196    colourise_term_arg(Opt, TB, Pos).
 1197colourise_option(Opt, OptionDecl, TB, term_position(_,_,FF,FT,ValPosList)) :-
 1198    !,
 1199    generalise_term(Opt, GenOpt),
 1200    (   memberchk(GenOpt, OptionDecl)
 1201    ->  colour_item(option_name, TB, FF-FT),
 1202        Opt =.. [Name|Values],
 1203        GenOpt =.. [Name|Types],
 1204        colour_option_values(Values, Types, TB, ValPosList)
 1205    ;   colour_item(no_option_name, TB, FF-FT),
 1206        colourise_term_args(ValPosList, 1, Opt, TB)
 1207    ).
 1208colourise_option(_, _, TB, Pos) :-
 1209    colour_item(type_error(option), TB, Pos).
 1210
 1211colour_option_values([], [], _, _).
 1212colour_option_values([V0|TV], [T0|TT], TB, [P0|TP]) :-
 1213    (   (   var(V0)
 1214        ;   is_of_type(T0, V0)
 1215        ;   T0 = list(_),
 1216            member(E, V0),
 1217            var(E)
 1218        ;   functor(V0, '.', 2),
 1219            V0 \= [_|_]
 1220        )
 1221    ->  colourise_term_arg(V0, TB, P0)
 1222    ;   callable(V0),
 1223        (   T0 = callable
 1224        ->  N = 0
 1225        ;   T0 = (callable+N)
 1226        )
 1227    ->  colourise_meta_arg(N, V0, TB, P0)
 1228    ;   colour_item(type_error(T0), TB, P0)
 1229    ),
 1230    colour_option_values(TV, TT, TB, TP).
 1231
 1232
 1233%!  colourise_files(+Arg, +TB, +Pos, +Why)
 1234%
 1235%   Colourise the argument list of one of the file-loading predicates.
 1236%
 1237%   @param Why is one of =any= or =imported=
 1238
 1239colourise_files(List, TB, list_position(F,T,Elms,_), Why) :-
 1240    !,
 1241    colour_item(list, TB, F-T),
 1242    colourise_file_list(List, TB, Elms, Why).
 1243colourise_files(M:Spec, TB, term_position(_,_,_,_,[MP,SP]), Why) :-
 1244    !,
 1245    colour_item(module(M), TB, MP),
 1246    colourise_files(Spec, TB, SP, Why).
 1247colourise_files(Var, TB, P, _) :-
 1248    var(Var),
 1249    !,
 1250    colour_item(var, TB, P).
 1251colourise_files(Spec0, TB, Pos, Why) :-
 1252    strip_module(Spec0, _, Spec),
 1253    (   colour_state_source_id(TB, Source),
 1254        prolog_canonical_source(Source, SourceId),
 1255        catch(xref_source_file(Spec, Path, SourceId, [silent(true)]),
 1256              _, fail)
 1257    ->  (   Why = imported,
 1258            \+ resolves_anything(TB, Path),
 1259            exports_something(TB, Path)
 1260        ->  colour_item(file_no_depend(Path), TB, Pos)
 1261        ;   colour_item(file(Path), TB, Pos)
 1262        )
 1263    ;   colour_item(nofile, TB, Pos)
 1264    ).
 1265
 1266colourise_file_list([], _, _, _).
 1267colourise_file_list([H|T], TB, [PH|PT], Why) :-
 1268    colourise_files(H, TB, PH, Why),
 1269    colourise_file_list(T, TB, PT, Why).
 1270
 1271resolves_anything(TB, Path) :-
 1272    colour_state_source_id(TB, SourceId),
 1273    xref_defined(SourceId, Head, imported(Path)),
 1274    xref_called(SourceId, Head, _),
 1275    !.
 1276
 1277exports_something(TB, Path) :-
 1278    colour_state_source_id(TB, SourceId),
 1279    xref_defined(SourceId, _, imported(Path)),
 1280    !.
 1281
 1282%!  colourise_directory(+Arg, +TB, +Pos)
 1283%
 1284%   Colourise argument that should be an existing directory.
 1285
 1286colourise_directory(Spec, TB, Pos) :-
 1287    (   colour_state_source_id(TB, SourceId),
 1288        catch(xref_source_file(Spec, Path, SourceId,
 1289                               [ file_type(directory),
 1290                                 silent(true)
 1291                               ]),
 1292              _, fail)
 1293    ->  colour_item(directory(Path), TB, Pos)
 1294    ;   colour_item(nofile, TB, Pos)
 1295    ).
 1296
 1297%!  colourise_langoptions(+Term, +TB, +Pos) is det.
 1298%
 1299%   Colourise the 3th argument of module/3
 1300
 1301colourise_langoptions([], _, _) :- !.
 1302colourise_langoptions([H|T], TB, list_position(PF,PT,[HP|TP],_)) :-
 1303    !,
 1304    colour_item(list, TB, PF-PT),
 1305    colourise_langoptions(H, TB, HP),
 1306    colourise_langoptions(T, TB, TP).
 1307colourise_langoptions(Spec, TB, Pos) :-
 1308    colourise_files(library(dialect/Spec), TB, Pos, imported).
 1309
 1310%!  colourise_class(ClassName, TB, Pos)
 1311%
 1312%   Colourise an XPCE class.
 1313
 1314colourise_class(ClassName, TB, Pos) :-
 1315    colour_state_source_id(TB, SourceId),
 1316    classify_class(SourceId, ClassName, Classification),
 1317    colour_item(class(Classification, ClassName), TB, Pos).
 1318
 1319%!  classify_class(+SourceId, +ClassName, -Classification)
 1320%
 1321%   Classify an XPCE class. As long as   this code is in this module
 1322%   rather than using hooks, we do not   want to load xpce unless it
 1323%   is already loaded.
 1324
 1325classify_class(SourceId, Name, Class) :-
 1326    xref_defined_class(SourceId, Name, Class),
 1327    !.
 1328classify_class(_SourceId, Name, Class) :-
 1329    current_predicate(pce:send_class/3),
 1330    (   current_predicate(classify_class/2)
 1331    ->  true
 1332    ;   use_module(library(pce_meta), [classify_class/2])
 1333    ),
 1334    member(G, [classify_class(Name, Class)]),
 1335    call(G).
 1336
 1337%!  colourise_term_args(+Term, +TB, +Pos)
 1338%
 1339%   colourise head/body principal terms.
 1340
 1341colourise_term_args(Term, TB,
 1342                    term_position(_,_,_,_,ArgPos)) :-
 1343    !,
 1344    colourise_term_args(ArgPos, 1, Term, TB).
 1345colourise_term_args(_, _, _).
 1346
 1347colourise_term_args([], _, _, _).
 1348colourise_term_args([Pos|T], N, Term, TB) :-
 1349    arg(N, Term, Arg),
 1350    colourise_term_arg(Arg, TB, Pos),
 1351    NN is N + 1,
 1352    colourise_term_args(T, NN, Term, TB).
 1353
 1354colourise_term_arg(_, _, Pos) :-
 1355    var(Pos),
 1356    !.
 1357colourise_term_arg(Arg, TB, parentheses_term_position(PO,PC,Pos)) :-
 1358    !,
 1359    colour_item(parentheses, TB, PO-PC),
 1360    colourise_term_arg(Arg, TB, Pos).
 1361colourise_term_arg(Var, TB, Pos) :-                     % variable
 1362    var(Var), Pos = _-_,
 1363    !,
 1364    (   singleton(Var, TB)
 1365    ->  colour_item(singleton, TB, Pos)
 1366    ;   colour_item(var, TB, Pos)
 1367    ).
 1368colourise_term_arg(List, TB, list_position(F, T, Elms, Tail)) :-
 1369    !,
 1370    colour_item(list, TB, F-T),
 1371    colourise_list_args(Elms, Tail, List, TB, classify).    % list
 1372colourise_term_arg(String, TB, string_position(F, T)) :-       % string
 1373    !,
 1374    (   string(String)
 1375    ->  colour_item(string, TB, F-T)
 1376    ;   String = [H|_]
 1377    ->  (   integer(H)
 1378        ->  colour_item(codes, TB, F-T)
 1379        ;   colour_item(chars, TB, F-T)
 1380        )
 1381    ;   String == []
 1382    ->  colour_item(codes, TB, F-T)
 1383    ).
 1384colourise_term_arg(_, TB,
 1385                   quasi_quotation_position(F,T,QQType,QQTypePos,CPos)) :-
 1386    !,
 1387    colourise_qq_type(QQType, TB, QQTypePos),
 1388    functor_name(QQType, Type),
 1389    colour_item(qq_content(Type), TB, CPos),
 1390    arg(1, CPos, SE),
 1391    SS is SE-2,
 1392    FE is F+2,
 1393    TS is T-2,
 1394    colour_item(qq(open),  TB, F-FE),
 1395    colour_item(qq(sep),   TB, SS-SE),
 1396    colour_item(qq(close), TB, TS-T).
 1397colourise_term_arg({Term}, TB, brace_term_position(F,T,Arg)) :-
 1398    !,
 1399    colour_item(brace_term, TB, F-T),
 1400    colourise_term_arg(Term, TB, Arg).
 1401colourise_term_arg(Map, TB, dict_position(F,T,TF,TT,KVPos)) :-
 1402    !,
 1403    is_dict(Map, Tag),
 1404    colour_item(dict, TB, F-T),
 1405    TagPos = TF-TT,
 1406    (   var(Tag)
 1407    ->  (   singleton(Tag, TB)
 1408        ->  colour_item(singleton, TB, TagPos)
 1409        ;   colour_item(var, TB, TagPos)
 1410        )
 1411    ;   colour_item(dict_tag, TB, TagPos)
 1412    ),
 1413    BStart is TT+1,
 1414    colour_item(dict_content, TB, BStart-T),
 1415    colourise_dict_kv(Map, TB, KVPos).
 1416colourise_term_arg([](List,Term), TB,                   % [] as operator
 1417                   term_position(_,_,0,0,[ListPos,ArgPos])) :-
 1418    !,
 1419    colourise_term_arg(List, TB, ListPos),
 1420    colourise_term_arg(Term, TB, ArgPos).
 1421colourise_term_arg(Compound, TB, Pos) :-                % compound
 1422    compound(Compound),
 1423    !,
 1424    (   Pos = term_position(_F,_T,FF,FT,_ArgPos)
 1425    ->  colour_item(functor, TB, FF-FT)             % TBD: Infix/Postfix?
 1426    ;   true                                        % TBD: When is this
 1427    ),
 1428    colourise_term_args(Compound, TB, Pos).
 1429colourise_term_arg(EmptyList, TB, Pos) :-
 1430    EmptyList == [],
 1431    !,
 1432    colour_item(empty_list, TB, Pos).
 1433colourise_term_arg(Atom, TB, Pos) :-
 1434    atom(Atom),
 1435    !,
 1436    colour_item(atom, TB, Pos).
 1437colourise_term_arg(Integer, TB, Pos) :-
 1438    integer(Integer),
 1439    !,
 1440    colour_item(int, TB, Pos).
 1441colourise_term_arg(Float, TB, Pos) :-
 1442    float(Float),
 1443    !,
 1444    colour_item(float, TB, Pos).
 1445colourise_term_arg(_Arg, _TB, _Pos) :-
 1446    true.
 1447
 1448colourise_list_args([HP|TP], Tail, [H|T], TB, How) :-
 1449    specified_item(How, H, TB, HP),
 1450    colourise_list_args(TP, Tail, T, TB, How).
 1451colourise_list_args([], none, _, _, _) :- !.
 1452colourise_list_args([], TP, T, TB, How) :-
 1453    specified_item(How, T, TB, TP).
 1454
 1455%!  colourise_qq_type(+QQType, +TB, +QQTypePos)
 1456%
 1457%   Colouring the type part of a quasi quoted term
 1458
 1459colourise_qq_type(QQType, TB, QQTypePos) :-
 1460    functor_position(QQTypePos, FPos, _),
 1461    colour_item(qq_type, TB, FPos),
 1462    colourise_term_args(QQType, TB, QQTypePos).
 1463
 1464qq_position(quasi_quotation_position(_,_,_,_,_)).
 1465
 1466%!  colourise_dict_kv(+Dict, +TB, +KVPosList)
 1467%
 1468%   Colourise the name-value pairs in the dict
 1469
 1470colourise_dict_kv(_, _, []) :- !.
 1471colourise_dict_kv(Dict, TB, [key_value_position(_F,_T,SF,ST,K,KP,VP)|KV]) :-
 1472    colour_item(dict_key, TB, KP),
 1473    colour_item(dict_sep, TB, SF-ST),
 1474    get_dict(K, Dict, V),
 1475    colourise_term_arg(V, TB, VP),
 1476    colourise_dict_kv(Dict, TB, KV).
 1477
 1478
 1479%!  colourise_exports(+List, +TB, +Pos)
 1480%
 1481%   Colourise the module export-list (or any other list holding
 1482%   terms of the form Name/Arity referring to predicates).
 1483
 1484colourise_exports([], _, _) :- !.
 1485colourise_exports(List, TB, list_position(F,T,ElmPos,Tail)) :-
 1486    !,
 1487    colour_item(list, TB, F-T),
 1488    (   Tail == none
 1489    ->  true
 1490    ;   colour_item(type_error(list), TB, Tail)
 1491    ),
 1492    colourise_exports2(List, TB, ElmPos).
 1493colourise_exports(_, TB, Pos) :-
 1494    colour_item(type_error(list), TB, Pos).
 1495
 1496colourise_exports2([G0|GT], TB, [P0|PT]) :-
 1497    !,
 1498    colourise_declaration(G0, TB, P0),
 1499    colourise_exports2(GT, TB, PT).
 1500colourise_exports2(_, _, _).
 1501
 1502
 1503%!  colourise_imports(+List, +File, +TB, +Pos)
 1504%
 1505%   Colourise import list from use_module/2, importing from File.
 1506
 1507colourise_imports(List, File, TB, Pos) :-
 1508    (   colour_state_source_id(TB, SourceId),
 1509        ground(File),
 1510        catch(xref_public_list(File, SourceId,
 1511                               [ path(Path),
 1512                                 public(Public),
 1513                                 silent(true)
 1514                               ] ), _, fail)
 1515    ->  true
 1516    ;   Public = [],
 1517        Path = (-)
 1518    ),
 1519    colourise_imports(List, Path, Public, TB, Pos).
 1520
 1521colourise_imports([], _, _, TB, Pos) :-
 1522    !,
 1523    colour_item(empty_list, TB, Pos).
 1524colourise_imports(List, File, Public, TB, list_position(F,T,ElmPos,Tail)) :-
 1525    !,
 1526    colour_item(list, TB, F-T),
 1527    (   Tail == none
 1528    ->  true
 1529    ;   colour_item(type_error(list), TB, Tail)
 1530    ),
 1531    colourise_imports2(List, File, Public, TB, ElmPos).
 1532colourise_imports(except(Except), File, Public, TB,
 1533                  term_position(_,_,FF,FT,[LP])) :-
 1534    !,
 1535    colour_item(keyword(except), TB, FF-FT),
 1536    colourise_imports(Except, File, Public, TB, LP).
 1537colourise_imports(_, _, _, TB, Pos) :-
 1538    colour_item(type_error(list), TB, Pos).
 1539
 1540colourise_imports2([G0|GT], File, Public, TB, [P0|PT]) :-
 1541    !,
 1542    colourise_import(G0, File, TB, P0),
 1543    colourise_imports2(GT, File, Public, TB, PT).
 1544colourise_imports2(_, _, _, _, _).
 1545
 1546
 1547colourise_import(PI as Name, File, TB, term_position(_,_,FF,FT,[PP,NP])) :-
 1548    pi_to_term(PI, Goal),
 1549    !,
 1550    colour_item(goal(imported(File), Goal), TB, PP),
 1551    rename_goal(Goal, Name, NewGoal),
 1552    goal_classification(TB, NewGoal, [], Class),
 1553    colour_item(goal(Class, NewGoal), TB, NP),
 1554    colour_item(keyword(as), TB, FF-FT).
 1555colourise_import(PI, File, TB, Pos) :-
 1556    pi_to_term(PI, Goal),
 1557    colour_state_source_id(TB, SourceID),
 1558    (   \+ xref_defined(SourceID, Goal, imported(File))
 1559    ->  colour_item(undefined_import, TB, Pos)
 1560    ;   \+ xref_called(SourceID, Goal, _)
 1561    ->  colour_item(unused_import, TB, Pos)
 1562    ),
 1563    !.
 1564colourise_import(PI, _, TB, Pos) :-
 1565    colourise_declaration(PI, TB, Pos).
 1566
 1567
 1568%!  colourise_declarations(+Term, +TB, +Pos)
 1569%
 1570%   Colourise the Predicate indicator lists of dynamic, multifile, etc
 1571%   declarations.
 1572
 1573colourise_declarations(List, TB, list_position(F,T,Elms,none)) :-
 1574    !,
 1575    colour_item(list, TB, F-T),
 1576    colourise_list_declarations(List, TB, Elms).
 1577colourise_declarations((Head,Tail), TB,
 1578                       term_position(_,_,_,_,[PH,PT])) :-
 1579    !,
 1580    colourise_declaration(Head, TB, PH),
 1581    colourise_declarations(Tail, TB, PT).
 1582colourise_declarations(Last, TB, Pos) :-
 1583    colourise_declaration(Last, TB, Pos).
 1584
 1585colourise_list_declarations([], _, []).
 1586colourise_list_declarations([H|T], TB, [HP|TP]) :-
 1587    colourise_declaration(H, TB, HP),
 1588    colourise_list_declarations(T, TB, TP).
 1589
 1590%!  colourise_declaration(+Decl, +TB, +Pos) is det.
 1591%
 1592%   Colourise declaration sequences as used  by module/2, dynamic/1,
 1593%   etc.
 1594
 1595colourise_declaration(PI, TB, term_position(F,T,FF,FT,[NamePos,ArityPos])) :-
 1596    pi_to_term(PI, Goal),
 1597    !,
 1598    goal_classification(TB, Goal, [], Class),
 1599    colour_item(predicate_indicator(Class, Goal), TB, F-T),
 1600    colour_item(goal(Class, Goal), TB, NamePos),
 1601    colour_item(predicate_indicator, TB, FF-FT),
 1602    colour_item(arity, TB, ArityPos).
 1603colourise_declaration(Module:PI, TB,
 1604                      term_position(_,_,QF,QT,[PM,PG])) :-
 1605    atom(Module), pi_to_term(PI, Goal),
 1606    !,
 1607    colour_item(module(M), TB, PM),
 1608    colour_item(functor, TB, QF-QT),
 1609    colour_item(predicate_indicator(extern(M), Goal), TB, PG),
 1610    PG = term_position(_,_,FF,FT,[NamePos,ArityPos]),
 1611    colour_item(goal(extern(M), Goal), TB, NamePos),
 1612    colour_item(predicate_indicator, TB, FF-FT),
 1613    colour_item(arity, TB, ArityPos).
 1614colourise_declaration(op(N,T,P), TB, Pos) :-
 1615    colour_item(exported_operator, TB, Pos),
 1616    colourise_op_declaration(op(N,T,P), TB, Pos).
 1617colourise_declaration(_, TB, Pos) :-
 1618    colour_item(type_error(export_declaration), TB, Pos).
 1619
 1620pi_to_term(Name/Arity, Term) :-
 1621    atom(Name), integer(Arity), Arity >= 0,
 1622    !,
 1623    functor(Term, Name, Arity).
 1624pi_to_term(Name//Arity0, Term) :-
 1625    atom(Name), integer(Arity0), Arity0 >= 0,
 1626    !,
 1627    Arity is Arity0 + 2,
 1628    functor(Term, Name, Arity).
 1629
 1630colourise_meta_declarations((Head,Tail), Extra, TB,
 1631                            term_position(_,_,_,_,[PH,PT])) :-
 1632    !,
 1633    colourise_meta_declaration(Head, Extra, TB, PH),
 1634    colourise_meta_declarations(Tail, Extra, TB, PT).
 1635colourise_meta_declarations(Last, Extra, TB, Pos) :-
 1636    colourise_meta_declaration(Last, Extra, TB, Pos).
 1637
 1638colourise_meta_declaration(M:Head, Extra, TB,
 1639                           term_position(_,_,QF,QT,
 1640                                         [ MP,
 1641                                           term_position(_,_,FF,FT,ArgPos)
 1642                                         ])) :-
 1643    !,
 1644    colour_item(module(M), TB, MP),
 1645    colour_item(functor, TB, QF-QT),
 1646    colour_item(goal(extern(M),Head), TB, FF-FT),
 1647    Head =.. [_|Args],
 1648    colourise_meta_decls(Args, Extra, TB, ArgPos).
 1649colourise_meta_declaration(Head, Extra, TB, term_position(_,_,FF,FT,ArgPos)) :-
 1650    !,
 1651    goal_classification(TB, Head, [], Class),
 1652    colour_item(goal(Class, Head), TB, FF-FT),
 1653    Head =.. [_|Args],
 1654    colourise_meta_decls(Args, Extra, TB, ArgPos).
 1655colourise_meta_declaration([H|T], Extra, TB, list_position(LF,LT,[HP],TP)) :-
 1656    !,
 1657    colour_item(list, TB, LF-LT),
 1658    colourise_meta_decls([H,T], Extra, TB, [HP,TP]).
 1659colourise_meta_declaration(_, _, TB, Pos) :-
 1660    !,
 1661    colour_item(type_error(compound), TB, Pos).
 1662
 1663colourise_meta_decls([], _, _, []).
 1664colourise_meta_decls([Arg|ArgT], Extra, TB, [PosH|PosT]) :-
 1665    colourise_meta_decl(Arg, Extra, TB, PosH),
 1666    colourise_meta_decls(ArgT, Extra, TB, PosT).
 1667
 1668colourise_meta_decl(Arg, Extra, TB, Pos) :-
 1669    nonvar(Arg),
 1670    (   valid_meta_decl(Arg)
 1671    ->  true
 1672    ;   memberchk(Arg, Extra)
 1673    ),
 1674    colour_item(meta(Arg), TB, Pos).
 1675colourise_meta_decl(_, _, TB, Pos) :-
 1676    colour_item(error, TB, Pos).
 1677
 1678valid_meta_decl(:).
 1679valid_meta_decl(*).
 1680valid_meta_decl(//).
 1681valid_meta_decl(^).
 1682valid_meta_decl(?).
 1683valid_meta_decl(+).
 1684valid_meta_decl(-).
 1685valid_meta_decl(I) :- integer(I), between(0,9,I).
 1686
 1687%!  colourise_op_declaration(Op, TB, Pos) is det.
 1688
 1689colourise_op_declaration(op(P,T,N), TB, term_position(_,_,FF,FT,[PP,TP,NP])) :-
 1690    colour_item(goal(built_in, op(N,T,P)), TB, FF-FT),
 1691    colour_op_priority(P, TB, PP),
 1692    colour_op_type(T, TB, TP),
 1693    colour_op_name(N, TB, NP).
 1694
 1695colour_op_name(_, _, Pos) :-
 1696    var(Pos),
 1697    !.
 1698colour_op_name(Name, TB, parentheses_term_position(PO,PC,Pos)) :-
 1699    !,
 1700    colour_item(parentheses, TB, PO-PC),
 1701    colour_op_name(Name, TB, Pos).
 1702colour_op_name(Name, TB, Pos) :-
 1703    var(Name),
 1704    !,
 1705    colour_item(var, TB, Pos).
 1706colour_op_name(Name, TB, Pos) :-
 1707    (atom(Name) ; Name == []),
 1708    !,
 1709    colour_item(identifier, TB, Pos).
 1710colour_op_name(Module:Name, TB, term_position(_F,_T,QF,QT,[MP,NP])) :-
 1711    !,
 1712    colour_item(module(Module), TB, MP),
 1713    colour_item(functor, TB, QF-QT),
 1714    colour_op_name(Name, TB, NP).
 1715colour_op_name(List, TB, list_position(F,T,Elems,none)) :-
 1716    !,
 1717    colour_item(list, TB, F-T),
 1718    colour_op_names(List, TB, Elems).
 1719colour_op_name(_, TB, Pos) :-
 1720    colour_item(error, TB, Pos).
 1721
 1722colour_op_names([], _, []).
 1723colour_op_names([H|T], TB, [HP|TP]) :-
 1724    colour_op_name(H, TB, HP),
 1725    colour_op_names(T, TB, TP).
 1726
 1727colour_op_type(Type, TB, Pos) :-
 1728    var(Type),
 1729    !,
 1730    colour_item(var, TB, Pos).
 1731colour_op_type(Type, TB, Pos) :-
 1732    op_type(Type),
 1733    !,
 1734    colour_item(op_type(Type), TB, Pos).
 1735colour_op_type(_, TB, Pos) :-
 1736    colour_item(error, TB, Pos).
 1737
 1738colour_op_priority(Priority, TB, Pos) :-
 1739    var(Priority), colour_item(var, TB, Pos).
 1740colour_op_priority(Priority, TB, Pos) :-
 1741    integer(Priority),
 1742    between(0, 1200, Priority),
 1743    !,
 1744    colour_item(int, TB, Pos).
 1745colour_op_priority(_, TB, Pos) :-
 1746    colour_item(error, TB, Pos).
 1747
 1748op_type(fx).
 1749op_type(fy).
 1750op_type(xf).
 1751op_type(yf).
 1752op_type(xfy).
 1753op_type(xfx).
 1754op_type(yfx).
 1755
 1756
 1757%!  colourise_prolog_flag_name(+Name, +TB, +Pos)
 1758%
 1759%   Colourise the name of a Prolog flag
 1760
 1761colourise_prolog_flag_name(_, _, Pos) :-
 1762    var(Pos),
 1763    !.
 1764colourise_prolog_flag_name(Name, TB, parentheses_term_position(PO,PC,Pos)) :-
 1765    !,
 1766    colour_item(parentheses, TB, PO-PC),
 1767    colourise_prolog_flag_name(Name, TB, Pos).
 1768colourise_prolog_flag_name(Name, TB, Pos) :-
 1769    atom(Name),
 1770    !,
 1771    (   current_prolog_flag(Name, _)
 1772    ->  colour_item(flag_name(Name), TB, Pos)
 1773    ;   colour_item(no_flag_name(Name), TB, Pos)
 1774    ).
 1775colourise_prolog_flag_name(Name, TB, Pos) :-
 1776    colourise_term(Name, TB, Pos).
 1777
 1778
 1779                 /*******************************
 1780                 *        CONFIGURATION         *
 1781                 *******************************/
 1782
 1783%       body_compiled(+Term)
 1784%
 1785%       Succeeds if term is a construct handled by the compiler.
 1786
 1787body_compiled((_,_)).
 1788body_compiled((_->_)).
 1789body_compiled((_*->_)).
 1790body_compiled((_;_)).
 1791body_compiled(\+_).
 1792
 1793%!  goal_classification(+TB, +Goal, +Origin, -Class)
 1794%
 1795%   Classify Goal appearing in TB and called from a clause with head
 1796%   Origin.  For directives, Origin is [].
 1797
 1798goal_classification(_, Goal, _, meta) :-
 1799    var(Goal),
 1800    !.
 1801goal_classification(_, Goal, _, not_callable) :-
 1802    \+ callable(Goal),
 1803    !.
 1804goal_classification(_, Goal, Origin, recursion) :-
 1805    callable(Origin),
 1806    generalise_term(Goal, Origin),
 1807    !.
 1808goal_classification(TB, Goal, _, How) :-
 1809    colour_state_source_id(TB, SourceId),
 1810    xref_defined(SourceId, Goal, How),
 1811    How \= public(_),
 1812    !.
 1813goal_classification(_TB, Goal, _, Class) :-
 1814    goal_classification(Goal, Class),
 1815    !.
 1816goal_classification(TB, Goal, _, How) :-
 1817    colour_state_module(TB, Module),
 1818    atom(Module),
 1819    Module \== prolog_colour_ops,
 1820    predicate_property(Module:Goal, imported_from(From)),
 1821    !,
 1822    How = imported(From).
 1823goal_classification(_TB, _Goal, _, undefined).
 1824
 1825%!  goal_classification(+Goal, -Class)
 1826%
 1827%   Multifile hookable classification for non-local goals.
 1828
 1829goal_classification(Goal, built_in) :-
 1830    built_in_predicate(Goal),
 1831    !.
 1832goal_classification(Goal, autoload(From)) :-    % SWI-Prolog
 1833    predicate_property(Goal, autoload(From)).
 1834goal_classification(Goal, global) :-            % SWI-Prolog
 1835    current_predicate(_, user:Goal),
 1836    !.
 1837goal_classification(Goal, Class) :-
 1838    compound(Goal),
 1839    compound_name_arity(Goal, Name, Arity),
 1840    vararg_goal_classification(Name, Arity, Class).
 1841
 1842%!  vararg_goal_classification(+Name, +Arity, -Class) is semidet.
 1843%
 1844%   Multifile hookable classification for _vararg_ predicates.
 1845
 1846vararg_goal_classification(call, Arity, built_in) :-
 1847    Arity >= 1.
 1848vararg_goal_classification(send_super, Arity, expanded) :- % XPCE (TBD)
 1849    Arity >= 2.
 1850vararg_goal_classification(get_super, Arity, expanded) :-  % XPCE (TBD)
 1851    Arity >= 3.
 1852
 1853
 1854classify_head(TB, Goal, exported) :-
 1855    colour_state_source_id(TB, SourceId),
 1856    xref_exported(SourceId, Goal),
 1857    !.
 1858classify_head(_TB, Goal, hook) :-
 1859    xref_hook(Goal),
 1860    !.
 1861classify_head(TB, Goal, hook) :-
 1862    colour_state_source_id(TB, SourceId),
 1863    xref_module(SourceId, M),
 1864    xref_hook(M:Goal),
 1865    !.
 1866classify_head(TB, Goal, Class) :-
 1867    built_in_predicate(Goal),
 1868    (   system_module(TB)
 1869    ->  (   predicate_property(system:Goal, iso)
 1870        ->  Class = def_iso
 1871        ;   goal_name(Goal, Name),
 1872            \+ sub_atom(Name, 0, _, _, $)
 1873        ->  Class = def_swi
 1874        )
 1875    ;   (   predicate_property(system:Goal, iso)
 1876        ->  Class = iso
 1877        ;   Class = built_in
 1878        )
 1879    ).
 1880classify_head(TB, Goal, unreferenced) :-
 1881    colour_state_source_id(TB, SourceId),
 1882    \+ (xref_called(SourceId, Goal, By), By \= Goal),
 1883    !.
 1884classify_head(TB, Goal, How) :-
 1885    colour_state_source_id(TB, SourceId),
 1886    (   xref_defined(SourceId, Goal, imported(From))
 1887    ->  How = imported(From)
 1888    ;   xref_defined(SourceId, Goal, How)
 1889    ),
 1890    !.
 1891classify_head(_TB, _Goal, undefined).
 1892
 1893built_in_predicate(Goal) :-
 1894    predicate_property(system:Goal, built_in),
 1895    !.
 1896built_in_predicate(module(_, _)).       % reserved expanded constructs
 1897built_in_predicate(module(_, _, _)).
 1898built_in_predicate(if(_)).
 1899built_in_predicate(elif(_)).
 1900built_in_predicate(else).
 1901built_in_predicate(endif).
 1902
 1903goal_name(_:G, Name) :- nonvar(G), !, goal_name(G, Name).
 1904goal_name(G, Name) :- callable(G), functor_name(G, Name).
 1905
 1906system_module(TB) :-
 1907    colour_state_source_id(TB, SourceId),
 1908    xref_module(SourceId, M),
 1909    module_property(M, class(system)).
 1910
 1911generalise_term(Specific, General) :-
 1912    (   compound(Specific)
 1913    ->  compound_name_arity(Specific, Name, Arity),
 1914        compound_name_arity(General0, Name, Arity),
 1915        General = General0
 1916    ;   General = Specific
 1917    ).
 1918
 1919rename_goal(Goal0, Name, Goal) :-
 1920    (   compound(Goal0)
 1921    ->  compound_name_arity(Goal0, _, Arity),
 1922        compound_name_arity(Goal, Name, Arity)
 1923    ;   Goal = Name
 1924    ).
 1925
 1926functor_name(Term, Name) :-
 1927    (   compound(Term)
 1928    ->  compound_name_arity(Term, Name, _)
 1929    ;   atom(Term)
 1930    ->  Name = Term
 1931    ).
 1932
 1933goal_name_arity(Goal, Name, Arity) :-
 1934    (   compound(Goal)
 1935    ->  compound_name_arity(Goal, Name, Arity)
 1936    ;   atom(Goal)
 1937    ->  Name = Goal, Arity = 0
 1938    ).
 1939
 1940
 1941%       Specify colours for individual goals.
 1942
 1943goal_colours(module(_,_),            built_in-[identifier,exports]).
 1944goal_colours(module(_,_,_),          built_in-[identifier,exports,langoptions]).
 1945goal_colours(use_module(_),          built_in-[imported_file]).
 1946goal_colours(use_module(File,_),     built_in-[file,imports(File)]).
 1947goal_colours(reexport(_),            built_in-[file]).
 1948goal_colours(reexport(File,_),       built_in-[file,imports(File)]).
 1949goal_colours(dynamic(_),             built_in-[predicates]).
 1950goal_colours(thread_local(_),        built_in-[predicates]).
 1951goal_colours(module_transparent(_),  built_in-[predicates]).
 1952goal_colours(discontiguous(_),       built_in-[predicates]).
 1953goal_colours(multifile(_),           built_in-[predicates]).
 1954goal_colours(volatile(_),            built_in-[predicates]).
 1955goal_colours(public(_),              built_in-[predicates]).
 1956goal_colours(meta_predicate(_),      built_in-[meta_declarations]).
 1957goal_colours(consult(_),             built_in-[file]).
 1958goal_colours(include(_),             built_in-[file]).
 1959goal_colours(ensure_loaded(_),       built_in-[file]).
 1960goal_colours(load_files(_),          built_in-[file]).
 1961goal_colours(load_files(_,_),        built_in-[file,options]).
 1962goal_colours(setof(_,_,_),           built_in-[classify,setof,classify]).
 1963goal_colours(bagof(_,_,_),           built_in-[classify,setof,classify]).
 1964goal_colours(predicate_options(_,_,_), built_in-[predicate,classify,classify]).
 1965% Database access
 1966goal_colours(assert(_),              built_in-[db]).
 1967goal_colours(asserta(_),             built_in-[db]).
 1968goal_colours(assertz(_),             built_in-[db]).
 1969goal_colours(assert(_,_),            built_in-[db,classify]).
 1970goal_colours(asserta(_,_),           built_in-[db,classify]).
 1971goal_colours(assertz(_,_),           built_in-[db,classify]).
 1972goal_colours(retract(_),             built_in-[db]).
 1973goal_colours(retractall(_),          built_in-[db]).
 1974goal_colours(clause(_,_),            built_in-[db,classify]).
 1975goal_colours(clause(_,_,_),          built_in-[db,classify,classify]).
 1976% misc
 1977goal_colours(set_prolog_flag(_,_),   built_in-[prolog_flag_name,classify]).
 1978goal_colours(current_prolog_flag(_,_), built_in-[prolog_flag_name,classify]).
 1979% XPCE stuff
 1980goal_colours(pce_autoload(_,_),      classify-[classify,file]).
 1981goal_colours(pce_image_directory(_), classify-[directory]).
 1982goal_colours(new(_, _),              built_in-[classify,pce_new]).
 1983goal_colours(send_list(_,_,_),       built_in-pce_arg_list).
 1984goal_colours(send(_,_),              built_in-[pce_arg,pce_selector]).
 1985goal_colours(get(_,_,_),             built_in-[pce_arg,pce_selector,pce_arg]).
 1986goal_colours(send_super(_,_),        built_in-[pce_arg,pce_selector]).
 1987goal_colours(get_super(_,_),         built_in-[pce_arg,pce_selector,pce_arg]).
 1988goal_colours(get_chain(_,_,_),       built_in-[pce_arg,pce_selector,pce_arg]).
 1989goal_colours(Pce,                    built_in-pce_arg) :-
 1990    compound(Pce),
 1991    functor_name(Pce, Functor),
 1992    pce_functor(Functor).
 1993
 1994pce_functor(send).
 1995pce_functor(get).
 1996pce_functor(send_super).
 1997pce_functor(get_super).
 1998
 1999
 2000                 /*******************************
 2001                 *        SPECIFIC HEADS        *
 2002                 *******************************/
 2003
 2004head_colours(file_search_path(_,_), hook-[identifier,classify]).
 2005head_colours(library_directory(_),  hook-[file]).
 2006head_colours(resource(_,_,_),       hook-[identifier,classify,file]).
 2007
 2008head_colours(Var, _) :-
 2009    var(Var),
 2010    !,
 2011    fail.
 2012head_colours(M:H, Colours) :-
 2013    M == user,
 2014    head_colours(H, HC),
 2015    HC = hook - _,
 2016    !,
 2017    Colours = meta-[module(user), HC ].
 2018head_colours(M:H, Colours) :-
 2019    atom(M), callable(H),
 2020    xref_hook(M:H),
 2021    !,
 2022    Colours = meta-[module(M), hook-classify ].
 2023head_colours(M:_, meta-[module(M),extern(M)]).
 2024
 2025
 2026                 /*******************************
 2027                 *             STYLES           *
 2028                 *******************************/
 2029
 2030%!  def_style(+Pattern, -Style)
 2031%
 2032%   Define the style used for the   given  pattern. Definitions here
 2033%   can     be     overruled     by       defining     rules     for
 2034%   emacs_prolog_colours:style/2
 2035
 2036def_style(goal(built_in,_),        [colour(blue)]).
 2037def_style(goal(imported(_),_),     [colour(blue)]).
 2038def_style(goal(autoload(_),_),     [colour(navy_blue)]).
 2039def_style(goal(global,_),          [colour(navy_blue)]).
 2040def_style(goal(undefined,_),       [colour(red)]).
 2041def_style(goal(thread_local(_),_), [colour(magenta), underline(true)]).
 2042def_style(goal(dynamic(_),_),      [colour(magenta)]).
 2043def_style(goal(multifile(_),_),    [colour(navy_blue)]).
 2044def_style(goal(expanded,_),        [colour(blue), underline(true)]).
 2045def_style(goal(extern(_),_),       [colour(blue), underline(true)]).
 2046def_style(goal(recursion,_),       [underline(true)]).
 2047def_style(goal(meta,_),            [colour(red4)]).
 2048def_style(goal(foreign(_),_),      [colour(darkturquoise)]).
 2049def_style(goal(local(_),_),        []).
 2050def_style(goal(constraint(_),_),   [colour(darkcyan)]).
 2051def_style(goal(not_callable,_),    [background(orange)]).
 2052
 2053def_style(option_name,             [colour('#3434ba')]).
 2054def_style(no_option_name,          [colour(red)]).
 2055
 2056def_style(head(exported,_),        [colour(blue), bold(true)]).
 2057def_style(head(public(_),_),       [colour('#016300'), bold(true)]).
 2058def_style(head(extern(_),_),       [colour(blue), bold(true)]).
 2059def_style(head(dynamic,_),         [colour(magenta), bold(true)]).
 2060def_style(head(multifile,_),       [colour(navy_blue), bold(true)]).
 2061def_style(head(unreferenced,_),    [colour(red), bold(true)]).
 2062def_style(head(hook,_),            [colour(blue), underline(true)]).
 2063def_style(head(meta,_),            []).
 2064def_style(head(constraint(_),_),   [colour(darkcyan), bold(true)]).
 2065def_style(head(imported(_),_),     [colour(darkgoldenrod4), bold(true)]).
 2066def_style(head(built_in,_),        [background(orange), bold(true)]).
 2067def_style(head(iso,_),             [background(orange), bold(true)]).
 2068def_style(head(def_iso,_),         [colour(blue), bold(true)]).
 2069def_style(head(def_swi,_),         [colour(blue), bold(true)]).
 2070def_style(head(_,_),               [bold(true)]).
 2071
 2072def_style(module(_),               [colour(dark_slate_blue)]).
 2073def_style(comment(_),              [colour(dark_green)]).
 2074
 2075def_style(directive,               [background(grey90)]).
 2076def_style(method(_),               [bold(true)]).
 2077
 2078def_style(var,                     [colour(red4)]).
 2079def_style(singleton,               [bold(true), colour(red4)]).
 2080def_style(unbound,                 [colour(red), bold(true)]).
 2081def_style(quoted_atom,             [colour(navy_blue)]).
 2082def_style(string,                  [colour(navy_blue)]).
 2083def_style(codes,                   [colour(navy_blue)]).
 2084def_style(chars,                   [colour(navy_blue)]).
 2085def_style(nofile,                  [colour(red)]).
 2086def_style(file(_),                 [colour(blue), underline(true)]).
 2087def_style(file_no_depend(_),       [colour(blue), underline(true), background(pink)]).
 2088def_style(directory(_),            [colour(blue)]).
 2089def_style(class(built_in,_),       [colour(blue), underline(true)]).
 2090def_style(class(library(_),_),     [colour(navy_blue), underline(true)]).
 2091def_style(class(local(_,_,_),_),   [underline(true)]).
 2092def_style(class(user(_),_),        [underline(true)]).
 2093def_style(class(user,_),           [underline(true)]).
 2094def_style(class(undefined,_),      [colour(red), underline(true)]).
 2095def_style(prolog_data,             [colour(blue), underline(true)]).
 2096def_style(flag_name(_),            [colour(blue)]).
 2097def_style(no_flag_name(_),         [colour(red)]).
 2098def_style(unused_import,           [colour(blue), background(pink)]).
 2099def_style(undefined_import,        [colour(red)]).
 2100
 2101def_style(constraint(_),           [colour(darkcyan)]).
 2102
 2103def_style(keyword(_),              [colour(blue)]).
 2104def_style(identifier,              [bold(true)]).
 2105def_style(delimiter,               [bold(true)]).
 2106def_style(expanded,                [colour(blue), underline(true)]).
 2107def_style(hook(_),                 [colour(blue), underline(true)]).
 2108def_style(op_type(_),              [colour(blue)]).
 2109
 2110def_style(qq_type,                 [bold(true)]).
 2111def_style(qq(_),                   [colour(blue), bold(true)]).
 2112def_style(qq_content(_),           [colour(red4)]).
 2113
 2114def_style(dict_tag,                [bold(true)]).
 2115def_style(dict_key,                [bold(true)]).
 2116def_style(dict_function(_),        [colour(navy_blue)]).
 2117def_style(dict_return_op,          [colour(blue)]).
 2118
 2119def_style(hook,                    [colour(blue), underline(true)]).
 2120def_style(dcg_right_hand_ctx,      [background('#d4ffe3')]).
 2121
 2122def_style(error,                   [background(orange)]).
 2123def_style(type_error(_),           [background(orange)]).
 2124def_style(syntax_error(_,_),       [background(orange)]).
 2125def_style(instantiation_error,     [background(orange)]).
 2126
 2127%!  syntax_colour(?Class, ?Attributes) is nondet.
 2128%
 2129%   True when a range  classified  Class   must  be  coloured  using
 2130%   Attributes.  Attributes is a list of:
 2131%
 2132%     * colour(ColourName)
 2133%     * background(ColourName)
 2134%     * bold(Boolean)
 2135%     * underline(Boolean)
 2136%
 2137%   Attributes may be the empty list. This   is used for cases where
 2138%   -for example- a  menu  is  associated   with  the  fragment.  If
 2139%   syntax_colour/2 fails, no fragment is created for the region.
 2140
 2141syntax_colour(Class, Attributes) :-
 2142    (   style(Class, Attributes)            % user hook
 2143    ;   def_style(Class, Attributes)        % system default
 2144    ).
 2145
 2146
 2147%!  term_colours(+Term, -FunctorColour, -ArgColours)
 2148%
 2149%   Define colourisation for specific terms.
 2150
 2151term_colours((?- Directive), Colours) :-
 2152    term_colours((:- Directive), Colours).
 2153term_colours((prolog:Head --> _),
 2154             neck(grammar_rule) - [ expanded - [ module(prolog),
 2155                                                 hook(message) - [ identifier
 2156                                                                 ]
 2157                                               ],
 2158                                    dcg_body(prolog:Head)
 2159                                  ]) :-
 2160    prolog_message_hook(Head).
 2161
 2162prolog_message_hook(message(_)).
 2163prolog_message_hook(error_message(_)).
 2164prolog_message_hook(message_context(_)).
 2165prolog_message_hook(message_location(_)).
 2166
 2167%       XPCE rules
 2168
 2169term_colours(variable(_, _, _, _),
 2170             expanded - [ identifier,
 2171                          classify,
 2172                          classify,
 2173                          comment(string)
 2174                        ]).
 2175term_colours(variable(_, _, _),
 2176             expanded - [ identifier,
 2177                          classify,
 2178                          atom
 2179                        ]).
 2180term_colours(handle(_, _, _),
 2181             expanded - [ classify,
 2182                          classify,
 2183                          classify
 2184                        ]).
 2185term_colours(handle(_, _, _, _),
 2186             expanded - [ classify,
 2187                          classify,
 2188                          classify,
 2189                          classify
 2190                        ]).
 2191term_colours(class_variable(_,_,_,_),
 2192             expanded - [ identifier,
 2193                          pce(type),
 2194                          pce(default),
 2195                          comment(string)
 2196                        ]).
 2197term_colours(class_variable(_,_,_),
 2198             expanded - [ identifier,
 2199                          pce(type),
 2200                          pce(default)
 2201                        ]).
 2202term_colours(delegate_to(_),
 2203             expanded - [ classify
 2204                        ]).
 2205term_colours((:- encoding(_)),
 2206             expanded - [ expanded - [ classify
 2207                                     ]
 2208                        ]).
 2209term_colours((:- pce_begin_class(_, _, _)),
 2210             expanded - [ expanded - [ identifier,
 2211                                       pce_new,
 2212                                       comment(string)
 2213                                     ]
 2214                        ]).
 2215term_colours((:- pce_begin_class(_, _)),
 2216             expanded - [ expanded - [ identifier,
 2217                                       pce_new
 2218                                     ]
 2219                        ]).
 2220term_colours((:- pce_extend_class(_)),
 2221             expanded - [ expanded - [ identifier
 2222                                     ]
 2223                        ]).
 2224term_colours((:- pce_end_class),
 2225             expanded - [ expanded
 2226                        ]).
 2227term_colours((:- pce_end_class(_)),
 2228             expanded - [ expanded - [ identifier
 2229                                     ]
 2230                        ]).
 2231term_colours((:- use_class_template(_)),
 2232             expanded - [ expanded - [ pce_new
 2233                                     ]
 2234                        ]).
 2235term_colours((:- emacs_begin_mode(_,_,_,_,_)),
 2236             expanded - [ expanded - [ identifier,
 2237                                       classify,
 2238                                       classify,
 2239                                       classify,
 2240                                       classify
 2241                                     ]
 2242                        ]).
 2243term_colours((:- emacs_extend_mode(_,_)),
 2244             expanded - [ expanded - [ identifier,
 2245                                       classify
 2246                                     ]
 2247                        ]).
 2248term_colours((:- pce_group(_)),
 2249             expanded - [ expanded - [ identifier
 2250                                     ]
 2251                        ]).
 2252term_colours((:- pce_global(_, new(_))),
 2253             expanded - [ expanded - [ identifier,
 2254                                       pce_arg
 2255                                     ]
 2256                        ]).
 2257term_colours((:- emacs_end_mode),
 2258             expanded - [ expanded
 2259                        ]).
 2260term_colours(pce_ifhostproperty(_,_),
 2261             expanded - [ classify,
 2262                          classify
 2263                        ]).
 2264term_colours((_,_),
 2265             error - [ classify,
 2266                       classify
 2267                     ]).
 2268
 2269%!  specified_item(+Specified, +Term, +TB, +TermPosition) is det.
 2270%
 2271%   Colourise an item that is explicitly   classified  by the user using
 2272%   term_colours/2 or goal_colours/2.
 2273
 2274specified_item(_Class, _Term, _TB, Pos) :-
 2275    var(Pos),
 2276    !.
 2277specified_item(Class, Term, TB, parentheses_term_position(PO,PC,Pos)) :-
 2278    !,
 2279    colour_item(parentheses, TB, PO-PC),
 2280    specified_item(Class, Term, TB, Pos).
 2281specified_item(_, Var, TB, Pos) :-
 2282    (   var(Var)
 2283    ;   qq_position(Pos)
 2284    ),
 2285    !,
 2286    colourise_term_arg(Var, TB, Pos).
 2287                                        % generic classification
 2288specified_item(classify, Term, TB, Pos) :-
 2289    !,
 2290    colourise_term_arg(Term, TB, Pos).
 2291                                        % classify as head
 2292specified_item(head, Term, TB, Pos) :-
 2293    !,
 2294    colourise_clause_head(Term, TB, Pos).
 2295                                        % expanded head (DCG=2, ...)
 2296specified_item(head(+N), Term, TB, Pos) :-
 2297    !,
 2298    colourise_extended_head(Term, N, TB, Pos).
 2299                                        % M:Head
 2300specified_item(extern(M), Term, TB, Pos) :-
 2301    !,
 2302    colourise_extern_head(Term, M, TB, Pos).
 2303                                        % classify as body
 2304specified_item(body, Term, TB, Pos) :-
 2305    !,
 2306    colourise_body(Term, TB, Pos).
 2307specified_item(body(Goal), _Term0, TB, Pos) :-
 2308    !,
 2309    colourise_body(Goal, TB, Pos).
 2310specified_item(dcg_body(Head), Term, TB, Pos) :-
 2311    !,
 2312    colourise_dcg(Term, Head, TB, Pos).
 2313specified_item(setof, Term, TB, Pos) :-
 2314    !,
 2315    colourise_setof(Term, TB, Pos).
 2316specified_item(meta(MetaSpec), Term, TB, Pos) :-
 2317    !,
 2318    colourise_meta_arg(MetaSpec, Term, TB, Pos).
 2319                                        % DCG goal in body
 2320specified_item(dcg, Term, TB, Pos) :-
 2321    !,
 2322    colourise_dcg(Term, [], TB, Pos).
 2323                                        % assert/retract arguments
 2324specified_item(db, Term, TB, Pos) :-
 2325    !,
 2326    colourise_db(Term, TB, Pos).
 2327                                        % files
 2328specified_item(file, Term, TB, Pos) :-
 2329    !,
 2330    colourise_files(Term, TB, Pos, any).
 2331specified_item(imported_file, Term, TB, Pos) :-
 2332    !,
 2333    colourise_files(Term, TB, Pos, imported).
 2334specified_item(langoptions, Term, TB, Pos) :-
 2335    !,
 2336    colourise_langoptions(Term, TB, Pos).
 2337
 2338                                        % directory
 2339specified_item(directory, Term, TB, Pos) :-
 2340    !,
 2341    colourise_directory(Term, TB, Pos).
 2342                                        % [Name/Arity, ...]
 2343specified_item(exports, Term, TB, Pos) :-
 2344    !,
 2345    colourise_exports(Term, TB, Pos).
 2346                                        % [Name/Arity, ...]
 2347specified_item(imports(File), Term, TB, Pos) :-
 2348    !,
 2349    colourise_imports(Term, File, TB, Pos).
 2350                                        % Name/Arity, ...
 2351specified_item(predicates, Term, TB, Pos) :-
 2352    !,
 2353    colourise_declarations(Term, TB, Pos).
 2354                                        % Name/Arity
 2355specified_item(predicate, Term, TB, Pos) :-
 2356    !,
 2357    colourise_declaration(Term, TB, Pos).
 2358                                        % head(Arg, ...)
 2359specified_item(meta_declarations, Term, TB, Pos) :-
 2360    !,
 2361    colourise_meta_declarations(Term, [], TB, Pos).
 2362specified_item(meta_declarations(Extra), Term, TB, Pos) :-
 2363    !,
 2364    colourise_meta_declarations(Term, Extra, TB, Pos).
 2365                                        % set_prolog_flag(Name, _)
 2366specified_item(prolog_flag_name, Term, TB, Pos) :-
 2367    !,
 2368    colourise_prolog_flag_name(Term, TB, Pos).
 2369                                        % XPCE new argument
 2370specified_item(pce_new, Term, TB, Pos) :-
 2371    !,
 2372    (   atom(Term)
 2373    ->  colourise_class(Term, TB, Pos)
 2374    ;   compound(Term)
 2375    ->  functor_name(Term, Class),
 2376        Pos = term_position(_,_,FF, FT, ArgPos),
 2377        colourise_class(Class, TB, FF-FT),
 2378        specified_items(pce_arg, Term, TB, ArgPos)
 2379    ;   colourise_term_arg(Term, TB, Pos)
 2380    ).
 2381                                        % Generic XPCE arguments
 2382specified_item(pce_arg, new(X), TB,
 2383               term_position(_,_,_,_,[ArgPos])) :-
 2384    !,
 2385    specified_item(pce_new, X, TB, ArgPos).
 2386specified_item(pce_arg, new(X, T), TB,
 2387               term_position(_,_,_,_,[P1, P2])) :-
 2388    !,
 2389    colourise_term_arg(X, TB, P1),
 2390    specified_item(pce_new, T, TB, P2).
 2391specified_item(pce_arg, @(Ref), TB, Pos) :-
 2392    !,
 2393    colourise_term_arg(@(Ref), TB, Pos).
 2394specified_item(pce_arg, prolog(Term), TB,
 2395               term_position(_,_,FF,FT,[ArgPos])) :-
 2396    !,
 2397    colour_item(prolog_data, TB, FF-FT),
 2398    colourise_term_arg(Term, TB, ArgPos).
 2399specified_item(pce_arg, Term, TB, Pos) :-
 2400    compound(Term),
 2401    Term \= [_|_],
 2402    !,
 2403    specified_item(pce_new, Term, TB, Pos).
 2404specified_item(pce_arg, Term, TB, Pos) :-
 2405    !,
 2406    colourise_term_arg(Term, TB, Pos).
 2407                                        % List of XPCE arguments
 2408specified_item(pce_arg_list, List, TB, list_position(F,T,Elms,Tail)) :-
 2409    !,
 2410    colour_item(list, TB, F-T),
 2411    colourise_list_args(Elms, Tail, List, TB, pce_arg).
 2412specified_item(pce_arg_list, Term, TB, Pos) :-
 2413    !,
 2414    specified_item(pce_arg, Term, TB, Pos).
 2415                                        % XPCE selector
 2416specified_item(pce_selector, Term, TB,
 2417               term_position(_,_,_,_,ArgPos)) :-
 2418    !,
 2419    specified_items(pce_arg, Term, TB, ArgPos).
 2420specified_item(pce_selector, Term, TB, Pos) :-
 2421    colourise_term_arg(Term, TB, Pos).
 2422                                        % Nested specification
 2423specified_item(FuncSpec-ArgSpecs, Term, TB,
 2424               term_position(_,_,FF,FT,ArgPos)) :-
 2425    !,
 2426    specified_item(FuncSpec, Term, TB, FF-FT),
 2427    specified_items(ArgSpecs, Term, TB, ArgPos).
 2428                                        % Nested for {...}
 2429specified_item(FuncSpec-[ArgSpec], {Term}, TB,
 2430               brace_term_position(F,T,ArgPos)) :-
 2431    !,
 2432    specified_item(FuncSpec, {Term}, TB, F-T),
 2433    specified_item(ArgSpec, Term, TB, ArgPos).
 2434                                        % Specified
 2435specified_item(FuncSpec-ElmSpec, List, TB,
 2436               list_position(F,T,ElmPos,TailPos)) :-
 2437    !,
 2438    colour_item(FuncSpec, TB, F-T),
 2439    specified_list(ElmSpec, List, TB, ElmPos, TailPos).
 2440specified_item(Class, _, TB, Pos) :-
 2441    colour_item(Class, TB, Pos).
 2442
 2443%!  specified_items(+Spec, +Term, +TB, +PosList)
 2444
 2445specified_items(Specs, Term, TB, PosList) :-
 2446    is_dict(Term),
 2447    !,
 2448    specified_dict_kv(PosList, Term, TB, Specs).
 2449specified_items(Specs, Term, TB, PosList) :-
 2450    is_list(Specs),
 2451    !,
 2452    specified_arglist(Specs, 1, Term, TB, PosList).
 2453specified_items(Spec, Term, TB, PosList) :-
 2454    specified_argspec(PosList, Spec, 1, Term, TB).
 2455
 2456
 2457specified_arglist([], _, _, _, _).
 2458specified_arglist(_, _, _, _, []) :- !.         % Excess specification args
 2459specified_arglist([S0|ST], N, T, TB, [P0|PT]) :-
 2460    (   S0 == options,
 2461        colourization_module(TB, Module),
 2462        colourise_option_arg(T, Module, N, TB, P0)
 2463    ->  true
 2464    ;   arg(N, T, Term),
 2465        specified_item(S0, Term, TB, P0)
 2466    ),
 2467    NN is N + 1,
 2468    specified_arglist(ST, NN, T, TB, PT).
 2469
 2470specified_argspec([], _, _, _, _).
 2471specified_argspec([P0|PT], Spec, N, T, TB) :-
 2472    arg(N, T, Term),
 2473    specified_item(Spec, Term, TB, P0),
 2474    NN is N + 1,
 2475    specified_argspec(PT, Spec, NN, T, TB).
 2476
 2477
 2478%       specified_list(+Spec, +List, +TB, +PosList, TailPos)
 2479
 2480specified_list([], [], _, [], _).
 2481specified_list([HS|TS], [H|T], TB, [HP|TP], TailPos) :-
 2482    !,
 2483    specified_item(HS, H, TB, HP),
 2484    specified_list(TS, T, TB, TP, TailPos).
 2485specified_list(Spec, [H|T], TB, [HP|TP], TailPos) :-
 2486    specified_item(Spec, H, TB, HP),
 2487    specified_list(Spec, T, TB, TP, TailPos).
 2488specified_list(_, _, _, [], none) :- !.
 2489specified_list(Spec, Tail, TB, [], TailPos) :-
 2490    specified_item(Spec, Tail, TB, TailPos).
 2491
 2492%!  specified_dict_kv(+PosList, +Term, +TB, +Specs)
 2493%
 2494%   @arg Specs is a list of dict_kv(+Key, +KeySpec, +ArgSpec)
 2495
 2496specified_dict_kv([], _, _, _).
 2497specified_dict_kv([key_value_position(_F,_T,SF,ST,K,KP,VP)|Pos],
 2498                  Dict, TB, Specs) :-
 2499    specified_dict_kv1(K, Specs, KeySpec, ValueSpec),
 2500    colour_item(KeySpec, TB, KP),
 2501    colour_item(dict_sep, TB, SF-ST),
 2502    get_dict(K, Dict, V),
 2503    specified_item(ValueSpec, V, TB, VP),
 2504    specified_dict_kv(Pos, Dict, TB, Specs).
 2505
 2506specified_dict_kv1(Key, Specs, KeySpec, ValueSpec) :-
 2507    Specs = [_|_],
 2508    memberchk(dict_kv(Key, KeySpec, ValueSpec), Specs),
 2509    !.
 2510specified_dict_kv1(Key, dict_kv(Key2, KeySpec, ValueSpec), KeySpec, ValueSpec) :-
 2511    \+ Key \= Key2,
 2512    !.              % do not bind Key2
 2513specified_dict_kv1(_, _, dict_key, classify).
 2514
 2515
 2516                 /*******************************
 2517                 *         DESCRIPTIONS         *
 2518                 *******************************/
 2519
 2520syntax_message(Class) -->
 2521    message(Class),
 2522    !.
 2523syntax_message(qq(_)) -->
 2524    [ 'Quasi quote delimiter' ].
 2525syntax_message(qq_type) -->
 2526    [ 'Quasi quote type term' ].
 2527syntax_message(qq_content(Type)) -->
 2528    [ 'Quasi quote content (~w syntax)'-[Type] ].
 2529syntax_message(goal(Class, Goal)) -->
 2530    !,
 2531    goal_message(Class, Goal).
 2532syntax_message(class(Type, Class)) -->
 2533    !,
 2534    xpce_class_message(Type, Class).
 2535syntax_message(dict_return_op) -->
 2536    !,
 2537    [ ':= separates function from return value' ].
 2538syntax_message(dict_function) -->
 2539    !,
 2540    [ 'Function on a dict' ].
 2541syntax_message(ext_quant) -->
 2542    !,
 2543    [ 'Existential quantification operator' ].
 2544syntax_message(hook(message)) -->
 2545    [ 'Rule for print_message/2' ].
 2546syntax_message(module(Module)) -->
 2547    (   { current_module(Module) }
 2548    ->  (   { module_property(Module, file(File)) }
 2549        ->  [ 'Module ~w defined in ~w'-[Module,File] ]
 2550        ;   [ 'Module ~w'-[Module] ]
 2551        )
 2552    ;   [ 'Module ~w (not loaded)'-[Module] ]
 2553    ).
 2554
 2555goal_message(meta, _) -->
 2556    [ 'Meta call' ].
 2557goal_message(recursion, _) -->
 2558    [ 'Recursive call' ].
 2559goal_message(not_callable, _) -->
 2560    [ 'Goal is not callable (type error)' ].
 2561goal_message(undefined, _) -->
 2562    [ 'Call to undefined predicate' ].
 2563goal_message(expanded, _) -->
 2564    [ 'Expanded goal' ].
 2565goal_message(global, _) -->
 2566    [ 'Auto-imported from module user' ].
 2567goal_message(Class, Goal) -->
 2568    { predicate_name(Goal, PI) },
 2569    [ 'Call to ~w predicate ~q'-[Class,PI] ].
 2570
 2571xpce_class_message(Type, Class) -->
 2572    [ 'XPCE ~w class ~q'-[Type, Class] ]