This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/swi/library/prolog_colour.pl
Vítor Santos Costa 3164ed2d61 doc support
2015-01-04 23:58:23 +00:00

1510 lines
46 KiB
Prolog

/* Part of SWI-Prolog
Author: Jan Wielemaker
E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org/projects/xpce/
Copyright (C): 1985-2011, University of Amsterdam
VU University Amsterdam
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
As a special exception, if you link this library with other files,
compiled with a Free Software compiler, to produce an executable, this
library does not by itself cause the resulting executable to be covered
by the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
:- module(prolog_colour,
[ prolog_colourise_stream/3, % +Stream, +SourceID, :ColourItem
prolog_colourise_term/4, % +Stream, +SourceID, :ColourItem, +Options
syntax_colour/2, % +Class, -Attributes
syntax_message//1 % +Class
]).
:- use_module(library(prolog_xref)).
:- use_module(library(predicate_options)).
:- use_module(library(prolog_source)).
:- use_module(library(lists)).
:- use_module(library(operators)).
:- use_module(library(debug)).
:- use_module(library(edit)).
:- use_module(library(error)).
:- use_module(library(option)).
:- use_module(library(record)).
:- if(exists_source(library(pce_meta))).
:- use_module(library(pce_meta)).
:- endif.
:- meta_predicate
prolog_colourise_stream(+, +, 3),
prolog_colourise_term(+, +, 3, +).
:- predicate_options(prolog_colourise_term/4, 4,
[ subterm_positions(-any)
]).
/** <module> Prolog syntax colouring support.
@ingroup swi
This module defines reusable code to colourise Prolog source.
@tbd: The one-term version
*/
:- multifile
style/2, % +ColourClass, -Attributes
message//1, % +ColourClass
term_colours/2, % +SourceTerm, -ColourSpec
goal_colours/2, % +Goal, -ColourSpec
directive_colours/2, % +Goal, -ColourSpec
goal_classification/2. % +Goal, -Class
:- record
colour_state(source_id,
closure,
singletons).
%% prolog_colourise_stream(+Stream, +SourceID, :ColourItem) is det.
%
% Determine colour fragments for the data on Stream. SourceID is
% the canonical identifier of the input as known to the
% cross-referencer, i.e., as created using xref_source(SourceID).
%
% ColourItem is a closure that is called for each identified
% fragment with three additional arguments:
%
% * The syntactical category
% * Start position (character offset) of the fragment
% * Length of the fragment (in characters).
prolog_colourise_stream(Fd, SourceId, ColourItem) :-
make_colour_state([ source_id(SourceId),
closure(ColourItem)
],
TB),
setup_call_cleanup(
save_settings(State),
colourise_stream(Fd, TB),
restore_settings(State)).
colourise_stream(Fd, TB) :-
( peek_char(Fd, #) % skip #! script line
-> skip(Fd, 10)
; true
),
repeat,
'$set_source_module'(SM, SM),
character_count(Fd, Start),
catch(read_term(Fd, Term,
[ subterm_positions(TermPos),
singletons(Singletons),
module(SM),
comments(Comments)
]),
E,
read_error(E, TB, Fd, Start)),
fix_operators(Term, TB),
colour_state_singletons(TB, Singletons),
( colourise_term(Term, TB, TermPos, Comments)
-> true
; arg(1, TermPos, From),
print_message(warning,
format('Failed to colourise ~p at index ~d~n',
[Term, From]))
),
Term == end_of_file, !.
save_settings(state(Style, Esc)) :-
push_operators([]),
current_prolog_flag(character_escapes, Esc),
'$style_check'(Style, Style).
restore_settings(state(Style, Esc)) :-
set_prolog_flag(character_escapes, Esc),
'$style_check'(_, Style),
pop_operators.
%% read_error(+Error, +TB, +Stream, +Start) is failure.
%
% If this is a syntax error, create a syntax-error fragment.
read_error(Error, TB, Stream, Start) :-
( Error = error(syntax_error(Id), stream(_S, _Line, _LinePos, CharNo))
-> message_to_string(error(syntax_error(Id), _), Msg),
character_count(Stream, End),
show_syntax_error(TB, CharNo:Msg, Start-End),
fail
; throw(Error)
).
%% colour_item(+Class, +TB, +Pos) is det.
colour_item(Class, TB, Pos) :-
arg(1, Pos, Start),
arg(2, Pos, End),
Len is End - Start,
colour_state_closure(TB, Closure),
call(Closure, Class, Start, Len).
%% safe_push_op(+Prec, +Type, :Name)
%
% Define operators into the default source module and register
% them to be undone by pop_operators/0.
safe_push_op(P, T, N0) :-
( N0 = _:_
-> N = N0
; '$set_source_module'(M, M),
N = M:N0
),
push_op(P, T, N),
debug(colour, ':- ~w.', [op(P,T,N)]).
%% fix_operators(+Term, +Src) is det.
%
% Fix flags that affect the syntax, such as operators and some
% style checking options. Src is the canonical source as required
% by the cross-referencer.
fix_operators((:- Directive), Src) :-
catch(process_directive(Directive, Src), _, true), !.
fix_operators(_, _).
process_directive(style_check(X), _) :- !,
style_check(X).
process_directive(op(P,T,N), _) :- !,
safe_push_op(P, T, N).
process_directive(module(_Name, Export), _) :- !,
forall(member(op(P,A,N), Export),
safe_push_op(P,A,N)).
process_directive(use_module(Spec), Src) :- !,
catch(process_use_module(Spec, Src), _, true).
process_directive(Directive, Src) :-
prolog_source:expand((:-Directive), Src, _).
%% process_use_module(+Imports, +Src)
%
% Get the exported operators from the referenced files.
process_use_module([], _) :- !.
process_use_module([H|T], Src) :- !,
process_use_module(H, Src),
process_use_module(T, Src).
process_use_module(File, Src) :-
( xref_public_list(File, _Path, Public, Src)
-> forall(member(op(P,T,N), Public),
safe_push_op(P,T,N))
; true
).
%% prolog_colourise_term(+Stream, +SourceID, :ColourItem, +Options)
%
% Colourise the next term on Stream. Unlike
% prolog_colourise_stream/3, this predicate assumes it is reading
% a single term rather than the entire stream. This implies that
% it cannot adjust syntax according to directives that preceed it.
%
% Options:
%
% * subterm_positions(-TermPos)
% Return complete term-layout. If an error is read, this is a
% term error_position(StartClause, EndClause, ErrorPos)
prolog_colourise_term(Stream, SourceId, ColourItem, Options) :-
make_colour_state([ source_id(SourceId),
closure(ColourItem)
],
TB),
option(subterm_positions(TermPos), Options, _),
findall(Op, xref_op(SourceId, Op), Ops),
character_count(Stream, Start),
read_source_term_at_location(
Stream, Term,
[ module(prolog_colour),
operators(Ops),
error(Error),
subterm_positions(TermPos),
singletons(Singletons),
comments(Comments)
]),
( var(Error)
-> colour_state_singletons(TB, Singletons),
colour_item(range, TB, TermPos), % Call to allow clearing
colourise_term(Term, TB, TermPos, Comments)
; character_count(Stream, End),
TermPos = error_position(Start, End, Pos),
colour_item(range, TB, TermPos),
show_syntax_error(TB, Error, Start-End),
Error = Pos:_Message
).
show_syntax_error(TB, Pos:Message, Range) :-
End is Pos + 1,
colour_item(syntax_error(Message, Range), TB, Pos-End).
singleton(Var, TB) :-
colour_state_singletons(TB, Singletons),
member_var(Var, Singletons).
member_var(V, [_=V2|_]) :-
V == V2, !.
member_var(V, [_|T]) :-
member_var(V, T).
%% colourise_term(+Term, +TB, +Termpos, +Comments)
colourise_term(Term, TB, TermPos, Comments) :-
colourise_comments(Comments, TB),
colourise_term(Term, TB, TermPos).
colourise_comments(-, _).
colourise_comments([], _).
colourise_comments([H|T], TB) :-
colourise_comment(H, TB),
colourise_comments(T, TB).
colourise_comment(Pos-Comment, TB) :-
stream_position_data(char_count, Pos, Start),
string_length(Comment, Len),
End is Start + Len + 1,
colour_item(comment, TB, Start-End).
colourise_term(Term, TB, Pos) :-
term_colours(Term, FuncSpec-ArgSpecs), !,
Pos = term_position(_,_,FF,FT,ArgPos),
specified_item(FuncSpec, Term, TB, FF-FT),
specified_items(ArgSpecs, Term, TB, ArgPos).
colourise_term((Head :- Body), TB,
term_position(F,T,FF,FT,[HP,BP])) :- !,
colour_item(clause, TB, F-T),
colour_item(neck(clause), TB, FF-FT),
colourise_clause_head(Head, TB, HP),
colourise_body(Body, Head, TB, BP).
colourise_term((Head --> Body), TB, % TBD: expansion!
term_position(F,T,FF,FT,[HP,BP])) :- !,
colour_item(grammar_rule, TB, F-T),
colour_item(neck(grammar_rule), TB, FF-FT),
colourise_extended_head(Head, 2, TB, HP),
colourise_dcg(Body, Head, TB, BP).
colourise_term(:->(Head, Body), TB,
term_position(F,T,FF,FT,[HP,BP])) :- !,
colour_item(method, TB, F-T),
colour_item(neck(method(send)), TB, FF-FT),
colour_method_head(send(Head), TB, HP),
colourise_method_body(Body, TB, BP).
colourise_term(:<-(Head, Body), TB,
term_position(F,T,FF,FT,[HP,BP])) :- !,
colour_item(method, TB, F-T),
colour_item(neck(method(get)), TB, FF-FT),
colour_method_head(get(Head), TB, HP),
colourise_method_body(Body, TB, BP).
colourise_term((:- Directive), TB, Pos) :- !,
colour_item(directive, TB, Pos),
arg(5, Pos, [ArgPos]),
colourise_directive(Directive, TB, ArgPos).
colourise_term((?- Directive), TB, Pos) :- !,
colourise_term((:- Directive), TB, Pos).
colourise_term(end_of_file, _, _) :- !.
colourise_term(Fact, TB, Pos) :- !,
colour_item(clause, TB, Pos),
colourise_clause_head(Fact, TB, Pos).
%% colourise_extended_head(+Head, +ExtraArgs, +TB, +Pos) is det.
%
% Colourise a clause-head that is extended by term_expansion,
% getting ExtraArgs more arguments (e.g., DCGs add two more
% arguments.
colourise_extended_head(Head, N, TB, Pos) :-
extend(Head, N, TheHead),
colourise_clause_head(TheHead, TB, Pos).
extend(M:Head, N, M:ExtHead) :-
nonvar(Head), !,
extend(Head, N, ExtHead).
extend(Head, N, ExtHead) :-
callable(Head), !,
Head =.. List,
length(Extra, N),
append(List, Extra, List1),
ExtHead =.. List1.
extend(Head, _, Head).
colourise_clause_head(Head, TB, Pos) :-
head_colours(Head, ClassSpec-ArgSpecs), !,
functor_position(Pos, FPos, ArgPos),
( ClassSpec == classify
-> classify_head(TB, Head, Class)
; Class = ClassSpec
),
colour_item(head(Class), TB, FPos),
specified_items(ArgSpecs, Head, TB, ArgPos).
colourise_clause_head(Head, TB, Pos) :-
functor_position(Pos, FPos, _),
classify_head(TB, Head, Class),
colour_item(head(Class), TB, FPos),
colourise_term_args(Head, TB, Pos).
% colourise_extern_head(+Head, +Module, +TB, +Pos)
%
% Colourise the head specified as Module:Head. Normally used for
% adding clauses to multifile predicates in other modules.
colourise_extern_head(Head, M, TB, Pos) :-
functor_position(Pos, FPos, _),
colour_item(head(extern(M)), TB, FPos),
colourise_term_args(Head, TB, Pos).
colour_method_head(SGHead, TB, Pos) :-
arg(1, SGHead, Head),
functor(SGHead, SG, _),
functor_position(Pos, FPos, _),
colour_item(method(SG), TB, FPos),
colourise_term_args(Head, TB, Pos).
% functor_position(+Term, -FunctorPos, -ArgPosList)
%
% Get the position of a functor and its argument. Unfortunately
% this goes wrong for lists, who have two `functor-positions'.
functor_position(term_position(_,_,FF,FT,ArgPos), FF-FT, ArgPos) :- !.
functor_position(list_position(F,_T,Elms,none), F-FT, Elms) :- !,
FT is F + 1.
functor_position(Pos, Pos, []).
%% colourise_directive(+Body, +TB, +Pos)
%
% Colourise the body of a directive.
colourise_directive((A,B), TB, term_position(_,_,_,_,[PA,PB])) :- !,
colourise_directive(A, TB, PA),
colourise_directive(B, TB, PB).
colourise_directive(Body, TB, Pos) :-
nonvar(Body),
directive_colours(Body, ClassSpec-ArgSpecs), !, % specified
functor_position(Pos, FPos, ArgPos),
( ClassSpec == classify
-> goal_classification(TB, Body, [], Class)
; Class = ClassSpec
),
colour_item(goal(Class, Body), TB, FPos),
specified_items(ArgSpecs, Body, TB, ArgPos).
colourise_directive(Body, TB, Pos) :-
colourise_body(Body, TB, Pos).
% colourise_body(+Body, +TB, +Pos)
%
% Breaks down to colourise_goal/3.
colourise_body(Body, TB, Pos) :-
colourise_body(Body, [], TB, Pos).
colourise_body(Body, Origin, TB, Pos) :-
colour_item(body, TB, Pos),
colourise_goals(Body, Origin, TB, Pos).
%% colourise_method_body(+MethodBody, +TB, +Pos)
%
% Colourise the optional "comment":: as pce(comment) and proceed
% with the body.
%
% @tbd Get this handled by a hook.
colourise_method_body(::(_Comment,Body), TB,
term_position(_F,_T,_FF,_FT,[CP,BP])) :- !,
colour_item(comment, TB, CP),
colourise_body(Body, TB, BP).
colourise_method_body(Body, TB, Pos) :- % deal with pri(::) < 1000
Body =.. [F,A,B],
control_op(F), !,
Pos = term_position(_F,_T,_FF,_FT,
[ AP,
BP
]),
colourise_method_body(A, TB, AP),
colourise_body(B, TB, BP).
colourise_method_body(Body, TB, Pos) :-
colourise_body(Body, TB, Pos).
control_op(',').
control_op((;)).
control_op((->)).
control_op((*->)).
colourise_goals(Body, Origin, TB, term_position(_,_,_,_,ArgPos)) :-
body_compiled(Body), !,
colourise_subgoals(ArgPos, 1, Body, Origin, TB).
colourise_goals(Goal, Origin, TB, Pos) :-
colourise_goal(Goal, Origin, TB, Pos).
colourise_subgoals([], _, _, _, _).
colourise_subgoals([Pos|T], N, Body, Origin, TB) :-
arg(N, Body, Arg),
colourise_goals(Arg, Origin, TB, Pos),
NN is N + 1,
colourise_subgoals(T, NN, Body, Origin, TB).
% colourise_dcg(+Body, +Head, +TB, +Pos)
%
% Breaks down to colourise_dcg_goal/3.
colourise_dcg(Body, Head, TB, Pos) :-
colour_item(dcg, TB, Pos),
dcg_extend(Head, Origin),
colourise_dcg_goals(Body, Origin, TB, Pos).
colourise_dcg_goals(Var, _, TB, Pos) :-
var(Var), !,
colour_item(goal(meta,Var), TB, Pos).
colourise_dcg_goals({Body}, Origin, TB, brace_term_position(F,T,Arg)) :- !,
colour_item(dcg(plain), TB, F-T),
colourise_goals(Body, Origin, TB, Arg).
colourise_dcg_goals([], _, TB, Pos) :- !,
colour_item(dcg(list), TB, Pos).
colourise_dcg_goals(List, _, TB, Pos) :-
List = [_|_], !,
colour_item(dcg(list), TB, Pos),
colourise_term_args(List, TB, Pos).
colourise_dcg_goals(Body, Origin, TB, term_position(_,_,_,_,ArgPos)) :-
body_compiled(Body), !,
colourise_dcg_subgoals(ArgPos, 1, Body, Origin, TB).
colourise_dcg_goals(Goal, Origin, TB, Pos) :-
colourise_dcg_goal(Goal, Origin, TB, Pos),
colourise_term_args(Goal, TB, Pos).
colourise_dcg_subgoals([], _, _, _, _).
colourise_dcg_subgoals([Pos|T], N, Body, Origin, TB) :-
arg(N, Body, Arg),
colourise_dcg_goals(Arg, Origin, TB, Pos),
NN is N + 1,
colourise_dcg_subgoals(T, NN, Body, Origin, TB).
dcg_extend(Term, _) :-
var(Term), !, fail.
dcg_extend(M:Term, M:Goal) :-
dcg_extend(Term, Goal).
dcg_extend(Term, Goal) :-
callable(Term),
Term =.. List,
append(List, [_,_], List2),
Goal =.. List2.
% colourise_dcg_goal(+Goal, +Origin, +TB, +Pos).
colourise_dcg_goal(!, Origin, TB, TermPos) :- !,
colourise_goal(!, Origin, TB, TermPos).
colourise_dcg_goal(Goal, Origin, TB, TermPos) :-
dcg_extend(Goal, TheGoal), !,
colourise_goal(TheGoal, Origin, TB, TermPos).
colourise_dcg_goal(Goal, _, TB, Pos) :-
colourise_term_args(Goal, TB, Pos).
% colourise_goal(+Goal, +Origin, +TB, +Pos)
%
% Colourise access to a single goal.
% Deal with list as goal (consult)
colourise_goal(Goal, _, TB, list_position(F,T,Elms,_)) :- !,
FT is F + 1,
AT is T - 1,
colour_item(goal(built_in, Goal), TB, F-FT),
colour_item(goal(built_in, Goal), TB, AT-T),
colourise_file_list(Goal, TB, Elms).
colourise_goal(Goal, Origin, TB, Pos) :-
nonvar(Goal),
goal_colours(Goal, ClassSpec-ArgSpecs), !, % specified
functor_position(Pos, FPos, ArgPos),
( ClassSpec == classify
-> goal_classification(TB, Goal, Origin, Class)
; Class = ClassSpec
),
colour_item(goal(Class, Goal), TB, FPos),
specified_items(ArgSpecs, Goal, TB, ArgPos).
colourise_goal(Module:Goal, _Origin, TB, term_position(_,_,_,_,[PM,PG])) :- !,
colour_item(module(Module), TB, PM),
( PG = term_position(_,_,FF,FT,_)
-> FP = FF-FT
; FP = PG
),
colour_item(goal(extern(Module), Goal), TB, FP),
colourise_goal_args(Goal, TB, PG).
colourise_goal(Goal, Origin, TB, Pos) :-
goal_classification(TB, Goal, Origin, Class),
( Pos = term_position(_,_,FF,FT,_ArgPos)
-> FPos = FF-FT
; FPos = Pos
),
colour_item(goal(Class, Goal), TB, FPos),
colourise_goal_args(Goal, TB, Pos).
%% colourise_goal_args(+Goal, +TB, +Pos)
%
% Colourise the arguments to a goal. This predicate deals with
% meta- and database-access predicates.
colourise_goal_args(Goal, TB, term_position(_,_,_,_,ArgPos)) :-
colourise_options(Goal, TB, ArgPos),
meta_args(Goal, MetaArgs), !,
colourise_meta_args(1, Goal, MetaArgs, TB, ArgPos).
colourise_goal_args(Goal, TB, Pos) :-
Pos = term_position(_,_,_,_,ArgPos), !,
colourise_options(Goal, TB, ArgPos),
colourise_term_args(Goal, TB, Pos).
colourise_goal_args(_, _, _). % no arguments
colourise_meta_args(_, _, _, _, []) :- !.
colourise_meta_args(N, Goal, MetaArgs, TB, [P0|PT]) :-
arg(N, Goal, Arg),
arg(N, MetaArgs, MetaSpec),
colourise_meta_arg(MetaSpec, Arg, TB, P0),
NN is N + 1,
colourise_meta_args(NN, Goal, MetaArgs, TB, PT).
colourise_meta_arg(MetaSpec, Arg, TB, Pos) :-
expand_meta(MetaSpec, Arg, Expanded), !,
colourise_goal(Expanded, [], TB, Pos). % TBD: recursion
colourise_meta_arg(_, Arg, TB, Pos) :-
colourise_term_arg(Arg, TB, Pos).
% meta_args(+Goal, -ArgSpec)
%
% Return a copy of Goal, where each meta-argument is an integer
% representing the number of extra arguments. The non-meta
% arguments are unbound variables.
%
% E.g. meta_args(maplist(foo,x,y), X) --> X = maplist(2,_,_)
%
% NOTE: this could be cached if performance becomes an issue.
meta_args(Goal, VarGoal) :-
xref_meta(Goal, _),
functor(Goal, Name, Arity),
functor(VarGoal, Name, Arity),
xref_meta(VarGoal, MetaArgs),
instantiate_meta(MetaArgs).
instantiate_meta([]).
instantiate_meta([H|T]) :-
( var(H)
-> H = 0
; H = V+N
-> V = N
),
instantiate_meta(T).
% expand_meta(+MetaSpec, +Goal, -Expanded)
%
% Add extra arguments to the goal if the meta-specifier is an
% integer (see above).
expand_meta(MetaSpec, Goal, Goal) :-
MetaSpec == 0.
expand_meta(MetaSpec, M:Goal, M:Expanded) :-
atom(M), !,
expand_meta(MetaSpec, Goal, Expanded).
expand_meta(MetaSpec, Goal, Expanded) :-
integer(MetaSpec),
callable(Goal), !,
length(Extra, MetaSpec),
Goal =.. List0,
append(List0, Extra, List),
Expanded =.. List.
%% colourise_setof(+Term, +TB, +Pos)
%
% Colourise the 2nd argument of setof/bagof
colourise_setof(Var^G, TB, term_position(_,_,FF,FT,[VP,GP])) :- !,
colourise_term_arg(Var, TB, VP),
colour_item(built_in, TB, FF-FT),
colourise_setof(G, TB, GP).
colourise_setof(Term, TB, Pos) :-
colourise_goal(Term, [], TB, Pos).
% colourise_db(+Arg, +TB, +Pos)
%
% Colourise database modification calls (assert/1, retract/1 and
% friends.
colourise_db((Head:-_Body), TB, term_position(_,_,_,_,[HP,_])) :- !,
colourise_db(Head, TB, HP).
colourise_db(Module:Head, TB, term_position(_,_,_,_,[MP,HP])) :- !,
colour_item(module(Module), TB, MP),
( atom(Module),
colour_state_source_id(TB, SourceId),
xref_module(SourceId, Module)
-> colourise_db(Head, TB, HP)
; true % TBD: Modifying in other module
).
colourise_db(Head, TB, Pos) :-
colourise_goal(Head, '<db-change>', TB, Pos).
%% colourise_options(+Goal, +TB, +ArgPos)
%
% Colourise predicate options
colourise_options(Goal, TB, ArgPos) :-
( compound(Goal),
functor(Goal, Name, Arity),
( colour_state_source_id(TB, SourceId),
xref_module(SourceId, Module)
-> true
; Module = user
),
current_predicate_options(Module:Name/Arity, Arg, OptionDecl),
debug(emacs, 'Colouring option-arg ~w of ~p',
[Arg, Module:Name/Arity]),
arg(Arg, Goal, Options0),
nth1(Arg, ArgPos, Pos0),
strip_option_module_qualifier(Goal, Module, Arg, TB,
Options0, Pos0, Options, Pos),
( Pos = list_position(_, _, ElmPos, TailPos)
-> colourise_option_list(Options, OptionDecl, TB, ElmPos, TailPos)
; ( var(Options)
; Options == []
)
-> colourise_term_arg(Options, TB, Pos)
; colour_item(type_error(list), TB, Pos)
),
fail
; true
).
strip_option_module_qualifier(Goal, Module, Arg, TB,
M:Options, term_position(_,_,_,_,[MP,Pos]),
Options, Pos) :-
predicate_property(Module:Goal, meta_predicate(Head)),
arg(Arg, Head, :), !,
colour_item(module(M), TB, MP).
strip_option_module_qualifier(_, _, _, _,
Options, Pos, Options, Pos).
colourise_option_list(_, _, _, [], none).
colourise_option_list(Tail, _, TB, [], TailPos) :-
colourise_term_arg(Tail, TB, TailPos).
colourise_option_list([H|T], OptionDecl, TB, [HPos|TPos], TailPos) :-
colourise_option(H, OptionDecl, TB, HPos),
colourise_option_list(T, OptionDecl, TB, TPos, TailPos).
colourise_option(Opt, _, TB, Pos) :-
var(Opt), !,
colourise_term_arg(Opt, TB, Pos).
colourise_option(Opt, OptionDecl, TB, term_position(_,_,FF,FT,ValPosList)) :- !,
functor(Opt, Name, Arity),
functor(GenOpt, Name, Arity),
( memberchk(GenOpt, OptionDecl)
-> colour_item(option_name, TB, FF-FT),
Opt =.. [Name|Values],
GenOpt =.. [Name|Types],
colour_option_values(Values, Types, TB, ValPosList)
; colour_item(no_option_name, TB, FF-FT)
).
colourise_option(_, _, TB, Pos) :-
colour_item(type_error(option), TB, Pos).
colour_option_values([], [], _, _).
colour_option_values([V0|TV], [T0|TT], TB, [P0|TP]) :-
( ( var(V0)
; is_of_type(T0, V0)
)
-> colourise_term_arg(V0, TB, P0)
; callable(V0),
( T0 = callable
-> N = 0
; T0 = (callable+N)
)
-> colourise_meta_arg(N, V0, TB, P0)
; colour_item(type_error(T0), TB, P0)
),
colour_option_values(TV, TT, TB, TP).
%% colourise_files(+Arg, +TB, +Pos)
%
% Colourise the argument list of one of the file-loading predicates.
colourise_files(List, TB, list_position(_,_,Elms,_)) :- !,
colourise_file_list(List, TB, Elms).
colourise_files(M:Spec, TB, term_position(_,_,_,_,[MP,SP])) :- !,
colour_item(module(M), TB, MP),
colourise_files(Spec, TB, SP).
colourise_files(Var, TB, P) :-
var(Var), !,
colour_item(var, TB, P).
colourise_files(Spec0, TB, Pos) :-
strip_module(Spec0, _, Spec),
( colour_state_source_id(TB, Source),
prolog_canonical_source(Source, SourceId),
catch(xref_source_file(Spec, Path, SourceId), _, fail)
-> colour_item(file(Path), TB, Pos)
; colour_item(nofile, TB, Pos)
).
colourise_file_list([], _, _).
colourise_file_list([H|T], TB, [PH|PT]) :-
colourise_files(H, TB, PH),
colourise_file_list(T, TB, PT).
%% colourise_directory(+Arg, +TB, +Pos)
%
% Colourise argument that should be an existing directory.
colourise_directory(Spec, TB, Pos) :-
( colour_state_source_id(TB, SourceId),
catch(xref_source_file(Spec, Path, SourceId,
[file_type(directory)]),
_, fail)
-> colour_item(directory(Path), TB, Pos)
; colour_item(nofile, TB, Pos)
).
%% colourise_class(ClassName, TB, Pos)
%
% Colourise an XPCE class.
colourise_class(ClassName, TB, Pos) :-
colour_state_source_id(TB, SourceId),
classify_class(SourceId, ClassName, Classification),
colour_item(class(Classification, ClassName), TB, Pos).
%% classify_class(+SourceId, +ClassName, -Classification).
classify_class(SourceId, Name, Class) :-
xref_defined_class(SourceId, Name, Class), !.
:- if(current_predicate(classify_class/2)).
classify_class(_, Name, Class) :-
classify_class(Name, Class).
:- endif.
%% colourise_term_args(+Term, +TB, +Pos)
%
% colourise head/body principal terms.
colourise_term_args(Term, TB,
term_position(_,_,_,_,ArgPos)) :- !,
colourise_term_args(ArgPos, 1, Term, TB).
colourise_term_args(_, _, _).
colourise_term_args([], _, _, _).
colourise_term_args([Pos|T], N, Term, TB) :-
arg(N, Term, Arg),
colourise_term_arg(Arg, TB, Pos),
NN is N + 1,
colourise_term_args(T, NN, Term, TB).
colourise_term_arg(Var, TB, Pos) :- % variable
var(Var), !,
( singleton(Var, TB)
-> colour_item(singleton, TB, Pos)
; colour_item(var, TB, Pos)
).
colourise_term_arg(List, TB, list_position(_, _, Elms, Tail)) :- !,
colourise_list_args(Elms, Tail, List, TB, classify). % list
colourise_term_arg(Compound, TB, Pos) :- % compound
compound(Compound), !,
colourise_term_args(Compound, TB, Pos).
colourise_term_arg(_, TB, string_position(F, T)) :- !, % string
colour_item(string, TB, F-T).
colourise_term_arg(Atom, TB, Pos) :- % single quoted atom
atom(Atom), !,
colour_item(atom, TB, Pos).
colourise_term_arg(_Arg, _TB, _Pos) :-
true.
colourise_list_args([HP|TP], Tail, [H|T], TB, How) :-
specified_item(How, H, TB, HP),
colourise_list_args(TP, Tail, T, TB, How).
colourise_list_args([], none, _, _, _) :- !.
colourise_list_args([], TP, T, TB, How) :-
specified_item(How, T, TB, TP).
% colourise_exports(+List, +TB, +Pos)
%
% Colourise the module export-list (or any other list holding
% terms of the form Name/Arity referring to predicates).
colourise_exports([], _, _) :- !.
colourise_exports(List, TB, list_position(_,_,ElmPos,Tail)) :- !,
( Tail == none
-> true
; colour_item(type_error(list), TB, Tail)
),
colourise_exports2(List, TB, ElmPos).
colourise_exports(_, TB, Pos) :-
colour_item(type_error(list), TB, Pos).
colourise_exports2([G0|GT], TB, [P0|PT]) :- !,
colourise_declaration(G0, TB, P0),
colourise_exports2(GT, TB, PT).
colourise_exports2(_, _, _).
% colourise_imports(+List, +File, +TB, +Pos)
%
% Colourise import list from use_module/2, importing from File.
colourise_imports(List, File, TB, Pos) :-
( colour_state_source_id(TB, SourceId),
catch(xref_public_list(File, Path, Public, SourceId), _, fail)
-> true
; Public = []
),
colourise_imports(List, Path, Public, TB, Pos).
colourise_imports([], _, _, _, _).
colourise_imports(List, File, Public, TB, list_position(_,_,ElmPos,Tail)) :- !,
( Tail == none
-> true
; colour_item(type_error(list), TB, Tail)
),
colourise_imports2(List, File, Public, TB, ElmPos).
colourise_imports(except(Except), File, Public, TB,
term_position(_,_,FF,FT,[LP])) :- !,
colour_item(keyword(except), TB, FF-FT),
colourise_imports(Except, File, Public, TB, LP).
colourise_imports(_, _, _, TB, Pos) :-
colour_item(type_error(list), TB, Pos).
colourise_imports2([G0|GT], File, Public, TB, [P0|PT]) :- !,
colourise_import(G0, File, TB, P0),
colourise_imports2(GT, File, Public, TB, PT).
colourise_imports2(_, _, _, _, _).
colourise_import(PI as Name, File, TB, term_position(_,_,FF,FT,[PP,NP])) :-
pi_to_term(PI, Goal), !,
colour_item(goal(imported(File), Goal), TB, PP),
functor(Goal, _, Arity),
functor(NewGoal, Name, Arity),
goal_classification(TB, NewGoal, [], Class),
colour_item(goal(Class, NewGoal), TB, NP),
colour_item(keyword(as), TB, FF-FT).
colourise_import(PI, _, TB, Pos) :-
colourise_declaration(PI, TB, Pos).
%% colourise_declarations(+Term, +TB, +Pos)
%
% Colourise the Predicate indicator lists of dynamic, multifile, etc
% declarations.
colourise_declarations((Head,Tail), TB,
term_position(_,_,_,_,[PH,PT])) :- !,
colourise_declaration(Head, TB, PH),
colourise_declarations(Tail, TB, PT).
colourise_declarations(Last, TB, Pos) :-
colourise_declaration(Last, TB, Pos).
colourise_declaration(PI, TB, Pos) :-
pi_to_term(PI, Goal), !,
goal_classification(TB, Goal, [], Class),
colour_item(goal(Class, Goal), TB, Pos).
colourise_declaration(Module:PI, TB,
term_position(_,_,_,_,[PM,PG])) :-
atom(Module), pi_to_term(PI, Goal), !,
colour_item(module(M), TB, PM),
colour_item(goal(extern(M), Goal), TB, PG).
colourise_declaration(op(_,_,_), TB, Pos) :-
colour_item(exported_operator, TB, Pos).
colourise_declaration(_, TB, Pos) :-
colour_item(type_error(export_declaration), TB, Pos).
pi_to_term(Name/Arity, Term) :-
atom(Name), integer(Arity), !,
functor(Term, Name, Arity).
pi_to_term(Name//Arity0, Term) :-
atom(Name), integer(Arity0), !,
Arity is Arity0 + 2,
functor(Term, Name, Arity).
%% colourise_prolog_flag_name(+Name, +TB, +Pos)
%
% Colourise the name of a Prolog flag
colourise_prolog_flag_name(Name, TB, Pos) :-
atom(Name), !,
( current_prolog_flag(Name, _)
-> colour_item(flag_name(Name), TB, Pos)
; colour_item(no_flag_name(Name), TB, Pos)
).
colourise_prolog_flag_name(Name, TB, Pos) :-
colourise_term(Name, TB, Pos).
/*******************************
* CONFIGURATION *
*******************************/
% body_compiled(+Term)
%
% Succeeds if term is a construct handled by the compiler.
body_compiled((_,_)).
body_compiled((_->_)).
body_compiled((_*->_)).
body_compiled((_;_)).
body_compiled(\+_).
% goal_classification(+TB, +Goal, +Origin, -Class)
%
% Classify Goal appearing in TB and called from a clause with head
% Origin. For directives Origin is [].
goal_classification(_, Goal, _, meta) :-
var(Goal), !.
goal_classification(_, Goal, Origin, recursion) :-
callable(Goal),
functor(Goal, Name, Arity),
functor(Origin, Name, Arity), !.
goal_classification(TB, Goal, _, How) :-
colour_state_source_id(TB, SourceId),
xref_defined(SourceId, Goal, How),
How \= public(_), !.
goal_classification(_TB, Goal, _, Class) :-
goal_classification(Goal, Class), !.
goal_classification(_TB, _Goal, _, undefined).
% goal_classification(+Goal, -Class)
%
% Multifile hookable classification for non-local goals.
goal_classification(Goal, built_in) :-
built_in_predicate(Goal), !.
goal_classification(Goal, autoload) :- % SWI-Prolog
functor(Goal, Name, Arity),
'$in_library'(Name, Arity, _Path), !.
goal_classification(Goal, global) :- % SWI-Prolog
current_predicate(_, user:Goal), !.
goal_classification(SS, expanded) :- % XPCE (TBD)
functor(SS, send_super, A),
A >= 2, !.
goal_classification(SS, expanded) :- % XPCE (TBD)
functor(SS, get_super, A),
A >= 3, !.
classify_head(TB, Goal, exported) :-
colour_state_source_id(TB, SourceId),
xref_exported(SourceId, Goal), !.
classify_head(_TB, Goal, hook) :-
xref_hook(Goal), !.
classify_head(TB, Goal, hook) :-
colour_state_source_id(TB, SourceId),
xref_module(SourceId, M),
xref_hook(M:Goal), !.
classify_head(TB, Goal, unreferenced) :-
colour_state_source_id(TB, SourceId),
\+ (xref_called(SourceId, Goal, By), By \= Goal), !.
classify_head(TB, Goal, How) :-
colour_state_source_id(TB, SourceId),
xref_defined(SourceId, Goal, How), !.
classify_head(_TB, Goal, built_in) :-
built_in_predicate(Goal), !.
classify_head(_TB, _Goal, undefined).
built_in_predicate(Goal) :-
predicate_property(system:Goal, built_in), !.
built_in_predicate(module(_, _)).
built_in_predicate(if(_)).
built_in_predicate(elif(_)).
built_in_predicate(else).
built_in_predicate(endif).
% Specify colours for individual goals.
goal_colours(module(_,_), built_in-[identifier,exports]).
goal_colours(use_module(_), built_in-[file]).
goal_colours(use_module(File,_), built_in-[file,imports(File)]).
goal_colours(reexport(_), built_in-[file]).
goal_colours(reexport(File,_), built_in-[file,imports(File)]).
goal_colours(dynamic(_), built_in-[predicates]).
goal_colours(thread_local(_), built_in-[predicates]).
goal_colours(module_transparent(_), built_in-[predicates]).
goal_colours(multifile(_), built_in-[predicates]).
goal_colours(volatile(_), built_in-[predicates]).
goal_colours(public(_), built_in-[predicates]).
goal_colours(consult(_), built_in-[file]).
goal_colours(include(_), built_in-[file]).
goal_colours(ensure_loaded(_), built_in-[file]).
goal_colours(load_files(_,_), built_in-[file,classify]).
goal_colours(setof(_,_,_), built_in-[classify,setof,classify]).
goal_colours(bagof(_,_,_), built_in-[classify,setof,classify]).
goal_colours(predicate_options(_,_,_), built_in-[predicate,classify,classify]).
% Database access
goal_colours(assert(_), built_in-[db]).
goal_colours(asserta(_), built_in-[db]).
goal_colours(assertz(_), built_in-[db]).
goal_colours(assert(_,_), built_in-[db,classify]).
goal_colours(asserta(_,_), built_in-[db,classify]).
goal_colours(assertz(_,_), built_in-[db,classify]).
goal_colours(retract(_), built_in-[db]).
goal_colours(retractall(_), built_in-[db]).
goal_colours(clause(_,_), built_in-[db,classify]).
goal_colours(clause(_,_,_), built_in-[db,classify,classify]).
% misc
goal_colours(set_prolog_flag(_,_), built_in-[prolog_flag_name,classify]).
goal_colours(current_prolog_flag(_,_), built_in-[prolog_flag_name,classify]).
% XPCE stuff
goal_colours(pce_autoload(_,_), classify-[classify,file]).
goal_colours(pce_image_directory(_), classify-[directory]).
goal_colours(new(_, _), built_in-[classify,pce_new]).
goal_colours(send_list(_,_,_), built_in-pce_arg_list).
goal_colours(send(_,_), built_in-[pce_arg,pce_selector]).
goal_colours(get(_,_,_), built_in-[pce_arg,pce_selector,pce_arg]).
goal_colours(send_super(_,_), built_in-[pce_arg,pce_selector]).
goal_colours(get_super(_,_), built_in-[pce_arg,pce_selector,pce_arg]).
goal_colours(get_chain(_,_,_), built_in-[pce_arg,pce_selector,pce_arg]).
goal_colours(Pce, built_in-pce_arg) :-
compound(Pce),
functor(Pce, Functor, _),
pce_functor(Functor).
pce_functor(send).
pce_functor(get).
pce_functor(send_super).
pce_functor(get_super).
/*******************************
* SPECIFIC HEADS *
*******************************/
head_colours(file_search_path(_,_), hook-[identifier,classify]).
head_colours(library_directory(_), hook-[file]).
head_colours(resource(_,_,_), hook-[identifier,classify,file]).
head_colours(Var, _) :-
var(Var), !,
fail.
head_colours(M:H, Colours) :-
atom(M), callable(H),
xref_hook(M:H), !,
Colours = hook - [ hook, hook-classify ].
head_colours(M:H, Colours) :-
M == user,
head_colours(H, HC),
HC = hook - _, !,
Colours = hook - [ hook, HC ].
head_colours(M:_, meta-[module(M),extern(M)]).
/*******************************
* STYLES *
*******************************/
%% def_style(+Pattern, -Style)
%
% Define the style used for the given pattern. Definitions here
% can be overruled by defining rules for
% emacs_prolog_colours:style/2
def_style(goal(built_in,_), [colour(blue)]).
def_style(goal(imported(_),_), [colour(blue)]).
def_style(goal(autoload,_), [colour(navy_blue)]).
def_style(goal(global,_), [colour(navy_blue)]).
def_style(goal(undefined,_), [colour(red)]).
def_style(goal(thread_local(_),_), [colour(magenta), underline(true)]).
def_style(goal(dynamic(_),_), [colour(magenta)]).
def_style(goal(multifile(_),_), [colour(navy_blue)]).
def_style(goal(expanded,_), [colour(blue), underline(true)]).
def_style(goal(extern(_),_), [colour(blue), underline(true)]).
def_style(goal(recursion,_), [underline(true)]).
def_style(goal(meta,_), [colour(red4)]).
def_style(goal(foreign(_),_), [colour(darkturquoise)]).
def_style(goal(local(_),_), []).
def_style(goal(constraint(_),_), [colour(darkcyan)]).
def_style(option_name, [colour('#3434ba')]).
def_style(no_option_name, [colour(red)]).
def_style(head(exported), [colour(blue), bold(true)]).
def_style(head(public(_)), [colour('#016300'), bold(true)]).
def_style(head(extern(_)), [colour(blue), bold(true)]).
def_style(head(dynamic), [colour(magenta), bold(true)]).
def_style(head(multifile), [colour(navy_blue), bold(true)]).
def_style(head(unreferenced), [colour(red), bold(true)]).
def_style(head(hook), [colour(blue), underline(true)]).
def_style(head(meta), []).
def_style(head(constraint(_)), [colour(darkcyan), bold(true)]).
def_style(head(_), [bold(true)]).
def_style(module(_), [colour(dark_slate_blue)]).
def_style(comment, [colour(dark_green)]).
def_style(directive, [background(grey90)]).
def_style(method(_), [bold(true)]).
def_style(var, [colour(red4)]).
def_style(singleton, [bold(true), colour(red4)]).
def_style(unbound, [colour(red), bold(true)]).
def_style(quoted_atom, [colour(navy_blue)]).
def_style(string, [colour(navy_blue)]).
def_style(nofile, [colour(red)]).
def_style(file(_), [colour(blue), underline(true)]).
def_style(directory(_), [colour(blue)]).
def_style(class(built_in,_), [colour(blue), underline(true)]).
def_style(class(library(_),_), [colour(navy_blue), underline(true)]).
def_style(class(local(_,_,_),_), [underline(true)]).
def_style(class(user(_),_), [underline(true)]).
def_style(class(user,_), [underline(true)]).
def_style(class(undefined,_), [colour(red), underline(true)]).
def_style(prolog_data, [colour(blue), underline(true)]).
def_style(flag_name(_), [colour(blue)]).
def_style(no_flag_name(_), [colour(red)]).
def_style(keyword(_), [colour(blue)]).
def_style(identifier, [bold(true)]).
def_style(delimiter, [bold(true)]).
def_style(expanded, [colour(blue), underline(true)]).
def_style(hook, [colour(blue), underline(true)]).
def_style(error, [background(orange)]).
def_style(type_error(_), [background(orange)]).
def_style(syntax_error(_,_), [background(orange)]).
%% syntax_colour(?Class, ?Attributes) is nondet.
%
% True when a range classified Class must be coloured using
% Attributes. Attributes is a list of:
%
% * colour(ColourName)
% * background(ColourName)
% * bold(Boolean)
% * underline(Boolean)
%
% Attributes may be the empty list. This is used for cases where
% -for example- a menu is associated with the fragment. If
% syntax_colour/2 fails, no fragment is created for the region.
syntax_colour(Class, Attributes) :-
( style(Class, Attributes) % user hook
; def_style(Class, Attributes) % system default
).
%% term_colours(+Term, -FunctorColour, -ArgColours)
%
% Define colourisation for specific terms.
term_colours((?- Directive), Colours) :-
term_colours((:- Directive), Colours).
term_colours((prolog:Head --> _),
expanded - [ expanded - [ expanded,
expanded - [ identifier
]
],
classify
]) :-
prolog_message_hook(Head).
prolog_message_hook(message(_)).
prolog_message_hook(error_message(_)).
prolog_message_hook(message_context(_)).
prolog_message_hook(message_location(_)).
% XPCE rules
term_colours(variable(_, _, _, _),
expanded - [ identifier,
classify,
classify,
comment
]).
term_colours(variable(_, _, _),
expanded - [ identifier,
classify,
atom
]).
term_colours(handle(_, _, _),
expanded - [ classify,
classify,
classify
]).
term_colours(handle(_, _, _, _),
expanded - [ classify,
classify,
classify,
classify
]).
term_colours(class_variable(_,_,_,_),
expanded - [ identifier,
pce(type),
pce(default),
comment
]).
term_colours(class_variable(_,_,_),
expanded - [ identifier,
pce(type),
pce(default)
]).
term_colours(delegate_to(_),
expanded - [ classify
]).
term_colours((:- encoding(_)),
expanded - [ expanded - [ classify
]
]).
term_colours((:- pce_begin_class(_, _, _)),
expanded - [ expanded - [ identifier,
pce_new,
comment
]
]).
term_colours((:- pce_begin_class(_, _)),
expanded - [ expanded - [ identifier,
pce_new
]
]).
term_colours((:- pce_extend_class(_)),
expanded - [ expanded - [ identifier
]
]).
term_colours((:- pce_end_class),
expanded - [ expanded
]).
term_colours((:- pce_end_class(_)),
expanded - [ expanded - [ identifier
]
]).
term_colours((:- use_class_template(_)),
expanded - [ expanded - [ pce_new
]
]).
term_colours((:- emacs_begin_mode(_,_,_,_,_)),
expanded - [ expanded - [ identifier,
classify,
classify,
classify,
classify
]
]).
term_colours((:- emacs_extend_mode(_,_)),
expanded - [ expanded - [ identifier,
classify
]
]).
term_colours((:- pce_group(_)),
expanded - [ expanded - [ identifier
]
]).
term_colours((:- pce_global(_, new(_))),
expanded - [ expanded - [ identifier,
pce_arg
]
]).
term_colours((:- emacs_end_mode),
expanded - [ expanded
]).
term_colours(pce_ifhostproperty(_,_),
expanded - [ classify,
classify
]).
term_colours((_,_),
error - [ classify,
classify
]).
specified_item(_, Var, TB, Pos) :-
var(Var), !,
colourise_term_arg(Var, TB, Pos).
% generic classification
specified_item(classify, Term, TB, Pos) :- !,
colourise_term_arg(Term, TB, Pos).
% classify as head
specified_item(head, Term, TB, Pos) :- !,
colourise_clause_head(Term, TB, Pos).
% expanded head (DCG=2, ...)
specified_item(head(+N), Term, TB, Pos) :- !,
colourise_extended_head(Term, N, TB, Pos).
% M:Head
specified_item(extern(M), Term, TB, Pos) :- !,
colourise_extern_head(Term, M, TB, Pos).
% classify as body
specified_item(body, Term, TB, Pos) :- !,
colourise_body(Term, TB, Pos).
specified_item(setof, Term, TB, Pos) :- !,
colourise_setof(Term, TB, Pos).
specified_item(meta(MetaSpec), Term, TB, Pos) :- !,
colourise_meta_arg(MetaSpec, Term, TB, Pos).
% DCG goal in body
specified_item(dcg, Term, TB, Pos) :- !,
colourise_dcg(Term, [], TB, Pos).
% assert/retract arguments
specified_item(db, Term, TB, Pos) :- !,
colourise_db(Term, TB, Pos).
% files
specified_item(file, Term, TB, Pos) :- !,
colourise_files(Term, TB, Pos).
% directory
specified_item(directory, Term, TB, Pos) :- !,
colourise_directory(Term, TB, Pos).
% [Name/Arity, ...]
specified_item(exports, Term, TB, Pos) :- !,
colourise_exports(Term, TB, Pos).
% [Name/Arity, ...]
specified_item(imports(File), Term, TB, Pos) :- !,
colourise_imports(Term, File, TB, Pos).
% Name/Arity, ...
specified_item(predicates, Term, TB, Pos) :- !,
colourise_declarations(Term, TB, Pos).
% Name/Arity
specified_item(predicate, Term, TB, Pos) :- !,
colourise_declaration(Term, TB, Pos).
% set_prolog_flag(Name, _)
specified_item(prolog_flag_name, Term, TB, Pos) :- !,
colourise_prolog_flag_name(Term, TB, Pos).
% XPCE new argument
specified_item(pce_new, Term, TB, Pos) :- !,
( atom(Term)
-> colourise_class(Term, TB, Pos)
; compound(Term)
-> functor(Term, Class, _),
Pos = term_position(_,_,FF, FT, ArgPos),
colourise_class(Class, TB, FF-FT),
specified_items(pce_arg, Term, TB, ArgPos)
; colourise_term_arg(Term, TB, Pos)
).
% Generic XPCE arguments
specified_item(pce_arg, new(X), TB,
term_position(_,_,_,_,[ArgPos])) :- !,
specified_item(pce_new, X, TB, ArgPos).
specified_item(pce_arg, new(X, T), TB,
term_position(_,_,_,_,[P1, P2])) :- !,
colourise_term_arg(X, TB, P1),
specified_item(pce_new, T, TB, P2).
specified_item(pce_arg, @(Ref), TB, Pos) :- !,
colourise_term_arg(@(Ref), TB, Pos).
specified_item(pce_arg, prolog(Term), TB,
term_position(_,_,FF,FT,[ArgPos])) :- !,
colour_item(prolog_data, TB, FF-FT),
colourise_term_arg(Term, TB, ArgPos).
specified_item(pce_arg, Term, TB, Pos) :-
compound(Term),
Term \= [_|_], !,
specified_item(pce_new, Term, TB, Pos).
specified_item(pce_arg, Term, TB, Pos) :- !,
colourise_term_arg(Term, TB, Pos).
% List of XPCE arguments
specified_item(pce_arg_list, List, TB, list_position(_,_,Elms,Tail)) :- !,
colourise_list_args(Elms, Tail, List, TB, pce_arg).
specified_item(pce_arg_list, Term, TB, Pos) :- !,
specified_item(pce_arg, Term, TB, Pos).
% XPCE selector
specified_item(pce_selector, Term, TB,
term_position(_,_,_,_,ArgPos)) :- !,
specified_items(pce_arg, Term, TB, ArgPos).
specified_item(pce_selector, Term, TB, Pos) :-
colourise_term_arg(Term, TB, Pos).
% Nested specification
specified_item(FuncSpec-ArgSpecs, Term, TB,
term_position(_,_,FF,FT,ArgPos)) :- !,
specified_item(FuncSpec, Term, TB, FF-FT),
specified_items(ArgSpecs, Term, TB, ArgPos).
% Nested for {...}
specified_item(FuncSpec-[ArgSpec], {Term}, TB,
brace_term_position(F,T,ArgPos)) :- !,
specified_item(FuncSpec, {Term}, TB, F-T),
specified_item(ArgSpec, Term, TB, ArgPos).
% Specified
specified_item(FuncSpec-ElmSpec, List, TB, list_position(F,T,ElmPos,TailPos)) :- !,
FT is F + 1,
AT is T - 1,
colour_item(FuncSpec, TB, F-FT),
colour_item(FuncSpec, TB, AT-T),
specified_list(ElmSpec, List, TB, ElmPos, TailPos).
specified_item(Class, _, TB, Pos) :-
colour_item(Class, TB, Pos).
% specified_items(+Spec, +T, +TB, +PosList)
specified_items(Specs, Term, TB, PosList) :-
is_list(Specs), !,
specified_arglist(Specs, 1, Term, TB, PosList).
specified_items(Spec, Term, TB, PosList) :-
specified_argspec(PosList, Spec, 1, Term, TB).
specified_arglist([], _, _, _, _).
specified_arglist(_, _, _, _, []) :- !. % Excess specification args
specified_arglist([S0|ST], N, T, TB, [P0|PT]) :-
arg(N, T, Term),
specified_item(S0, Term, TB, P0),
NN is N + 1,
specified_arglist(ST, NN, T, TB, PT).
specified_argspec([], _, _, _, _).
specified_argspec([P0|PT], Spec, N, T, TB) :-
arg(N, T, Term),
specified_item(Spec, Term, TB, P0),
NN is N + 1,
specified_argspec(PT, Spec, NN, T, TB).
% specified_list(+Spec, +List, +TB, +PosList, TailPos)
specified_list([], [], _, [], _).
specified_list([HS|TS], [H|T], TB, [HP|TP], TailPos) :- !,
specified_item(HS, H, TB, HP),
specified_list(TS, T, TB, TP, TailPos).
specified_list(Spec, [H|T], TB, [HP|TP], TailPos) :-
specified_item(Spec, H, TB, HP),
specified_list(Spec, T, TB, TP, TailPos).
specified_list(_, _, _, [], none) :- !.
specified_list(Spec, Tail, TB, [], TailPos) :-
specified_item(Spec, Tail, TB, TailPos).
/*******************************
* DESCRIPTIONS *
*******************************/
syntax_message(Class) -->
message(Class), !.
syntax_message(goal(Class, Goal)) --> !,
goal_message(Class, Goal).
syntax_message(class(Type, Class)) --> !,
xpce_class_message(Type, Class).
goal_message(meta, _) -->
[ 'Meta call' ].
goal_message(recursion, _) -->
[ 'Recursive call' ].
goal_message(undefined, _) -->
[ 'Call to undefined predicate' ].
goal_message(expanded, _) -->
[ 'Expanded goal' ].
goal_message(global, _) -->
[ 'Auto-imported from module user' ].
goal_message(Class, Goal) -->
{ predicate_name(Goal, PI) },
[ 'Call to ~w predicate ~q'-[Class,PI] ].
xpce_class_message(Type, Class) -->
[ 'XPCE ~w class ~q'-[Type, Class] ].