View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  1985-2026, University of Amsterdam
    7                              VU University Amsterdam
    8                              SWI-Prolog Solutions b.v.
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module('$toplevel',
   38          [ '$initialise'/0,            % start Prolog
   39            '$toplevel'/0,              % Prolog top-level (re-entrant)
   40            '$compile'/0,               % `-c' toplevel
   41            '$config'/0,                % --dump-runtime-variables toplevel
   42            initialize/0,               % Run program initialization
   43            version/0,                  % Write initial banner
   44            version/1,                  % Add message to the banner
   45            prolog/0,                   % user toplevel predicate
   46            '$query_loop'/0,            % toplevel predicate
   47            '$execute_query'/3,         % +Query, +Bindings, -Truth
   48            '$answer_class'/1,          % -Class
   49            residual_goals/1,           % +Callable
   50            (initialization)/1,         % initialization goal (directive)
   51            '$thread_init'/0,           % initialise thread
   52            (thread_initialization)/1   % thread initialization goal
   53            ]).   54
   55
   56                 /*******************************
   57                 *         VERSION BANNER       *
   58                 *******************************/
   59
   60:- dynamic prolog:version_msg/1.   61:- multifile prolog:version_msg/1.
 version is det
Print the Prolog banner message and messages registered using version/1.
   68version :-
   69    print_message(banner, welcome).
 version(+Message) is det
Add message to version/0
   75:- multifile
   76    system:term_expansion/2.   77
   78system:term_expansion((:- version(Message)),
   79                      prolog:version_msg(Message)).
   80
   81version(Message) :-
   82    (   prolog:version_msg(Message)
   83    ->  true
   84    ;   assertz(prolog:version_msg(Message))
   85    ).
   86
   87
   88                /********************************
   89                *         INITIALISATION        *
   90                *********************************/
 load_init_file(+ScriptMode) is det
Load the user customization file. This can be done using swipl -f file or simply using swipl. In the first case we search the file both directly and over the alias user_app_config. In the latter case we only use the alias.
   99load_init_file(_) :-
  100    '$cmd_option_val'(init_file, OsFile),
  101    !,
  102    prolog_to_os_filename(File, OsFile),
  103    load_init_file(File, explicit).
  104load_init_file(prolog) :-
  105    !,
  106    load_init_file('init.pl', implicit).
  107load_init_file(none) :-
  108    !,
  109    load_init_file('init.pl', implicit).
  110load_init_file(_).
 loaded_init_file(?Base, ?AbsFile)
Used by prolog_load_context/2 to confirm we are loading a script.
  116:- dynamic
  117    loaded_init_file/2.             % already loaded init files
  118
  119load_init_file(none, _) :- !.
  120load_init_file(Base, _) :-
  121    loaded_init_file(Base, _),
  122    !.
  123load_init_file(InitFile, explicit) :-
  124    exists_file(InitFile),
  125    !,
  126    ensure_loaded(user:InitFile).
  127load_init_file(Base, _) :-
  128    absolute_file_name(user_app_config(Base), InitFile,
  129                       [ access(read),
  130                         file_errors(fail)
  131                       ]),
  132    !,
  133    asserta(loaded_init_file(Base, InitFile)),
  134    load_files(user:InitFile,
  135               [ scope_settings(false)
  136               ]).
  137load_init_file('init.pl', implicit) :-
  138    (   current_prolog_flag(windows, true),
  139        absolute_file_name(user_profile('swipl.ini'), InitFile,
  140                           [ access(read),
  141                             file_errors(fail)
  142                           ])
  143    ;   expand_file_name('~/.swiplrc', [InitFile]),
  144        exists_file(InitFile)
  145    ),
  146    !,
  147    print_message(warning, backcomp(init_file_moved(InitFile))).
  148load_init_file(_, _).
  149
  150'$load_system_init_file' :-
  151    loaded_init_file(system, _),
  152    !.
  153'$load_system_init_file' :-
  154    '$cmd_option_val'(system_init_file, Base),
  155    Base \== none,
  156    current_prolog_flag(home, Home),
  157    file_name_extension(Base, rc, Name),
  158    atomic_list_concat([Home, '/', Name], File),
  159    absolute_file_name(File, Path,
  160                       [ file_type(prolog),
  161                         access(read),
  162                         file_errors(fail)
  163                       ]),
  164    asserta(loaded_init_file(system, Path)),
  165    load_files(user:Path,
  166               [ silent(true),
  167                 scope_settings(false)
  168               ]),
  169    !.
  170'$load_system_init_file'.
  171
  172'$load_script_file' :-
  173    loaded_init_file(script, _),
  174    !.
  175'$load_script_file' :-
  176    '$cmd_option_val'(script_file, OsFiles),
  177    load_script_files(OsFiles).
  178
  179load_script_files([]).
  180load_script_files([OsFile|More]) :-
  181    prolog_to_os_filename(File, OsFile),
  182    (   absolute_file_name(File, Path,
  183                           [ file_type(prolog),
  184                             access(read),
  185                             file_errors(fail)
  186                           ])
  187    ->  asserta(loaded_init_file(script, Path)),
  188        load_files(user:Path),
  189        load_files(user:More)
  190    ;   throw(error(existence_error(script_file, File), _))
  191    ).
  192
  193
  194                 /*******************************
  195                 *       AT_INITIALISATION      *
  196                 *******************************/
  197
  198:- meta_predicate
  199    initialization(0).  200
  201:- '$iso'((initialization)/1).
 initialization :Goal
Runs Goal after loading the file in which this directive appears as well as after restoring a saved state.
See also
- initialization/2
  210initialization(Goal) :-
  211    Goal = _:G,
  212    prolog:initialize_now(G, Use),
  213    !,
  214    print_message(warning, initialize_now(G, Use)),
  215    initialization(Goal, now).
  216initialization(Goal) :-
  217    initialization(Goal, after_load).
  218
  219:- multifile
  220    prolog:initialize_now/2,
  221    prolog:message//1,
  222    prolog:line_editor_attributes/2.    % +Off, +On
  223
  224prolog:initialize_now(load_foreign_library(_),
  225                      'use :- use_foreign_library/1 instead').
  226prolog:initialize_now(load_foreign_library(_,_),
  227                      'use :- use_foreign_library/2 instead').
  228
  229prolog:message(initialize_now(Goal, Use)) -->
  230    [ 'Initialization goal ~p will be executed'-[Goal],nl,
  231      'immediately for backward compatibility reasons', nl,
  232      '~w'-[Use]
  233    ].
  234
  235'$run_initialization' :-
  236    '$set_prolog_file_extension',
  237    '$run_initialization'(_, []),
  238    '$thread_init'.
 initialize
Run goals registered with :- initialization(Goal, program).. Stop with an exception if a goal fails or raises an exception.
  245initialize :-
  246    forall('$init_goal'(when(program), Goal, Ctx),
  247           run_initialize(Goal, Ctx)).
  248
  249run_initialize(Goal, Ctx) :-
  250    (   catch(Goal, E, true),
  251        (   var(E)
  252        ->  true
  253        ;   throw(error(initialization_error(E, Goal, Ctx), _))
  254        )
  255    ;   throw(error(initialization_error(failed, Goal, Ctx), _))
  256    ).
  257
  258
  259                 /*******************************
  260                 *     THREAD INITIALIZATION    *
  261                 *******************************/
  262
  263:- meta_predicate
  264    thread_initialization(0).  265:- dynamic
  266    '$at_thread_initialization'/1.
 thread_initialization :Goal
Run Goal now and everytime a new thread is created.
  272thread_initialization(Goal) :-
  273    assert('$at_thread_initialization'(Goal)),
  274    call(Goal),
  275    !.
 $thread_init
Called by start_thread() from pl-thread.c before the thread's goal.
  281'$thread_init' :-
  282    set_prolog_flag(toplevel_thread, false),
  283    (   '$at_thread_initialization'(Goal),
  284        (   call(Goal)
  285        ->  fail
  286        ;   fail
  287        )
  288    ;   true
  289    ).
  290
  291
  292                 /*******************************
  293                 *     FILE SEARCH PATH (-p)    *
  294                 *******************************/
 $set_file_search_paths is det
Process -p PathSpec options.
  300'$set_file_search_paths' :-
  301    '$cmd_option_val'(search_paths, Paths),
  302    (   '$member'(Path, Paths),
  303        atom_chars(Path, Chars),
  304        (   phrase('$search_path'(Name, Aliases), Chars)
  305        ->  '$reverse'(Aliases, Aliases1),
  306            forall('$member'(Alias, Aliases1),
  307                   asserta(user:file_search_path(Name, Alias)))
  308        ;   print_message(error, commandline_arg_type(p, Path))
  309        ),
  310        fail ; true
  311    ).
  312
  313'$search_path'(Name, Aliases) -->
  314    '$string'(NameChars),
  315    [=],
  316    !,
  317    {atom_chars(Name, NameChars)},
  318    '$search_aliases'(Aliases).
  319
  320'$search_aliases'([Alias|More]) -->
  321    '$string'(AliasChars),
  322    path_sep,
  323    !,
  324    { '$make_alias'(AliasChars, Alias) },
  325    '$search_aliases'(More).
  326'$search_aliases'([Alias]) -->
  327    '$string'(AliasChars),
  328    '$eos',
  329    !,
  330    { '$make_alias'(AliasChars, Alias) }.
  331
  332path_sep -->
  333    { current_prolog_flag(path_sep, Sep) },
  334    [Sep].
  335
  336'$string'([]) --> [].
  337'$string'([H|T]) --> [H], '$string'(T).
  338
  339'$eos'([], []).
  340
  341'$make_alias'(Chars, Alias) :-
  342    catch(term_to_atom(Alias, Chars), _, fail),
  343    (   atom(Alias)
  344    ;   functor(Alias, F, 1),
  345        F \== /
  346    ),
  347    !.
  348'$make_alias'(Chars, Alias) :-
  349    atom_chars(Alias, Chars).
  350
  351
  352                 /*******************************
  353                 *   LOADING ASSIOCIATED FILES  *
  354                 *******************************/
 argv_prolog_files(-Files, -ScriptMode) is det
Update the Prolog flag argv, extracting the leading script files. This is called after the C based parser removed Prolog options such as -q, -f none, etc. These options are available through '$cmd_option_val'/2.

Our task is to update the Prolog flag argv and return a list of the files to be loaded. The rules are:

Arguments:
ScriptMode- is one of
exe
Program is a saved state
prolog
One or more *.pl files on commandline
script
Single existing file on commandline
app
[path:]cli-name on commandline
none
Normal interactive session
  388argv_prolog_files([], exe) :-
  389    current_prolog_flag(saved_program_class, runtime),
  390    !,
  391    clean_argv.
  392argv_prolog_files(Files, ScriptMode) :-
  393    current_prolog_flag(argv, Argv),
  394    no_option_files(Argv, Argv1, Files, ScriptMode),
  395    (   (   nonvar(ScriptMode)
  396        ;   Argv1 == []
  397        )
  398    ->  (   Argv1 \== Argv
  399        ->  set_prolog_flag(argv, Argv1)
  400        ;   true
  401        )
  402    ;   '$usage',
  403        halt(1)
  404    ).
  405
  406no_option_files([--|Argv], Argv, [], ScriptMode) :-
  407    !,
  408    (   ScriptMode = none
  409    ->  true
  410    ;   true
  411    ).
  412no_option_files([Opt|_], _, _, ScriptMode) :-
  413    var(ScriptMode),
  414    sub_atom(Opt, 0, _, _, '-'),
  415    !,
  416    '$usage',
  417    halt(1).
  418no_option_files([OsFile|Argv0], Argv, [File|T], ScriptMode) :-
  419    file_name_extension(_, Ext, OsFile),
  420    user:prolog_file_type(Ext, prolog),
  421    !,
  422    ScriptMode = prolog,
  423    prolog_to_os_filename(File, OsFile),
  424    no_option_files(Argv0, Argv, T, ScriptMode).
  425no_option_files([OsScript|Argv], Argv, [Script], ScriptMode) :-
  426    var(ScriptMode),
  427    !,
  428    prolog_to_os_filename(PlScript, OsScript),
  429    (   exists_file(PlScript)
  430    ->  Script = PlScript,
  431        ScriptMode = script
  432    ;   cli_script(OsScript, Script)
  433    ->  ScriptMode = app,
  434        set_prolog_flag(app_name, OsScript)
  435    ;   '$existence_error'(file, PlScript)
  436    ).
  437no_option_files(Argv, Argv, [], ScriptMode) :-
  438    (   ScriptMode = none
  439    ->  true
  440    ;   true
  441    ).
  442
  443cli_script(CLI, Script) :-
  444    (   sub_atom(CLI, Pre, _, Post, ':')
  445    ->  sub_atom(CLI, 0, Pre, _, SearchPath),
  446        sub_atom(CLI, _, Post, 0, Base),
  447        Spec =.. [SearchPath, Base]
  448    ;   Spec = app(CLI)
  449    ),
  450    absolute_file_name(Spec, Script,
  451                       [ file_type(prolog),
  452                         access(exist),
  453                         file_errors(fail)
  454                       ]).
  455
  456clean_argv :-
  457    (   current_prolog_flag(argv, [--|Argv])
  458    ->  set_prolog_flag(argv, Argv)
  459    ;   true
  460    ).
 win_associated_files(+Files)
If SWI-Prolog is started as <exe> <file>.<ext>, where <ext> is the extension registered for associated files, set the Prolog flag associated_file, switch to the directory holding the file and -if possible- adjust the window title.
  469win_associated_files(Files) :-
  470    (   Files = [File|_]
  471    ->  absolute_file_name(File, AbsFile),
  472        set_prolog_flag(associated_file, AbsFile),
  473        forall(prolog:set_app_file_config(Files), true)
  474    ;   true
  475    ).
  476
  477:- multifile
  478    prolog:set_app_file_config/1.               % +Files
 start_pldoc
If the option --pldoc[=port] is given, load the PlDoc system.
  484start_pldoc :-
  485    '$cmd_option_val'(pldoc_server, Server),
  486    (   Server == ''
  487    ->  call((doc_server(_), doc_browser))
  488    ;   catch(atom_number(Server, Port), _, fail)
  489    ->  call(doc_server(Port))
  490    ;   print_message(error, option_usage(pldoc)),
  491        halt(1)
  492    ).
  493start_pldoc.
 load_associated_files(+Files)
Load Prolog files specified from the commandline.
  500load_associated_files(Files) :-
  501    load_files(user:Files).
  502
  503hkey('HKEY_CURRENT_USER/Software/SWI/Prolog').
  504hkey('HKEY_LOCAL_MACHINE/Software/SWI/Prolog').
  505
  506'$set_prolog_file_extension' :-
  507    current_prolog_flag(windows, true),
  508    hkey(Key),
  509    catch(win_registry_get_value(Key, fileExtension, Ext0),
  510          _, fail),
  511    !,
  512    (   atom_concat('.', Ext, Ext0)
  513    ->  true
  514    ;   Ext = Ext0
  515    ),
  516    (   user:prolog_file_type(Ext, prolog)
  517    ->  true
  518    ;   asserta(user:prolog_file_type(Ext, prolog))
  519    ).
  520'$set_prolog_file_extension'.
  521
  522
  523                /********************************
  524                *        TOPLEVEL GOALS         *
  525                *********************************/
 $initialise is semidet
Called from PL_initialise() to do the Prolog part of the initialization. If an exception occurs, this is printed and '$initialise' fails.
  533'$initialise' :-
  534    catch(initialise_prolog, E, initialise_error(E)).
  535
  536initialise_error(unwind(abort)) :- !.
  537initialise_error(unwind(halt(_))) :- !.
  538initialise_error(E) :-
  539    print_message(error, initialization_exception(E)),
  540    fail.
  541
  542initialise_prolog :-
  543    apply_defines,
  544    init_optimise,
  545    '$run_initialization',
  546    '$load_system_init_file',                   % -F file
  547    set_toplevel,                               % set `toplevel_goal` flag from -t
  548    '$set_file_search_paths',                   % handle -p alias=dir[:dir]*
  549    init_debug_flags,
  550    setup_app,
  551    start_pldoc,                                % handle --pldoc[=port]
  552    main_thread_init.
 main_thread_init
Deal with the Epilog toplevel. If the flag epilog is set and xpce is around, create an epilog window and complete the user part of the initialization in the epilog thread.
  560:- if(current_prolog_flag(threads, true)).  561main_thread_init :-
  562    current_prolog_flag(epilog, true),
  563    thread_self(main),
  564    current_prolog_flag(xpce, true),
  565    exists_source(library(epilog)),
  566    !,
  567    setup_theme,
  568    catch(setup_backtrace, E, print_message(warning, E)),
  569    use_module(library(epilog)),
  570    set_thread(main, class(system)),
  571    call(epilog([ init(user_thread_init),
  572                  main(true)
  573                ])).
  574main_thread_init :-
  575    set_thread(main, class(console)),
  576    setup_theme,
  577    user_thread_init.
  578:- else.  579main_thread_init :-
  580    setup_theme,
  581    user_thread_init.
  582:- endif.
 user_thread_init
Complete the toplevel startup. This may run in a separate thread.
  589user_thread_init :-
  590    opt_attach_packs,
  591    argv_prolog_files(Files, ScriptMode),
  592    load_init_file(ScriptMode),                 % -f file
  593    catch(setup_colors, E, print_message(warning, E)),
  594    win_associated_files(Files),                % swipl-win: cd and update title
  595    '$load_script_file',                        % -s file (may be repeated)
  596    load_associated_files(Files),
  597    '$cmd_option_val'(goals, Goals),            % -g goal (may be repeated)
  598    (   ScriptMode == app
  599    ->  run_program_init,                       % initialization(Goal, program)
  600        run_main_init(true)
  601    ;   Goals == [],
  602        \+ '$init_goal'(when(_), _, _)          % no -g or -t or initialization(program)
  603    ->  version                                 % default interactive run
  604    ;   run_init_goals(Goals),                  % run -g goals
  605        (   load_only                           % used -l to load
  606        ->  version
  607        ;   run_program_init,                   % initialization(Goal, program)
  608            run_main_init(false)                % initialization(Goal, main)
  609        )
  610    ).
 setup_theme
  614:- multifile
  615    prolog:theme/1.  616
  617setup_theme :-
  618    current_prolog_flag(theme, Theme),
  619    exists_source(library(theme/Theme)),
  620    !,
  621    use_module(library(theme/Theme)).
  622setup_theme.
 apply_defines
Handle -Dflag[=value] options
  628apply_defines :-
  629    '$cmd_option_val'(defines, Defs),
  630    apply_defines(Defs).
  631
  632apply_defines([]).
  633apply_defines([H|T]) :-
  634    apply_define(H),
  635    apply_defines(T).
  636
  637apply_define(Def) :-
  638    sub_atom(Def, B, _, A, '='),
  639    !,
  640    sub_atom(Def, 0, B, _, Flag),
  641    sub_atom(Def, _, A, 0, Value0),
  642    (   '$current_prolog_flag'(Flag, Value0, _Scope, Access, Type)
  643    ->  (   Access \== write
  644        ->  '$permission_error'(set, prolog_flag, Flag)
  645        ;   text_flag_value(Type, Value0, Value)
  646        ),
  647	set_prolog_flag(Flag, Value)
  648    ;   (   atom_number(Value0, Value)
  649	->  true
  650	;   Value = Value0
  651	),
  652	set_defined(Flag, Value)
  653    ).
  654apply_define(Def) :-
  655    atom_concat('no-', Flag, Def),
  656    !,
  657    set_user_boolean_flag(Flag, false).
  658apply_define(Def) :-
  659    set_user_boolean_flag(Def, true).
  660
  661set_user_boolean_flag(Flag, Value) :-
  662    current_prolog_flag(Flag, Old),
  663    !,
  664    (   Old == Value
  665    ->  true
  666    ;   set_prolog_flag(Flag, Value)
  667    ).
  668set_user_boolean_flag(Flag, Value) :-
  669    set_defined(Flag, Value).
  670
  671text_flag_value(integer, Text, Int) :-
  672    atom_number(Text, Int),
  673    !.
  674text_flag_value(float, Text, Float) :-
  675    atom_number(Text, Float),
  676    !.
  677text_flag_value(term, Text, Term) :-
  678    term_string(Term, Text, []),
  679    !.
  680text_flag_value(_, Value, Value).
  681
  682set_defined(Flag, Value) :-
  683    define_options(Flag, Options), !,
  684    create_prolog_flag(Flag, Value, Options).
 define_options(+Flag, -Options)
Define the options with which to create Flag. This can be used for known flags to control -for example- their type.
  691define_options('SDL_VIDEODRIVER', []).
  692define_options(_, [warn_not_accessed(true)]).
 init_optimise
Load library(apply_macros) if -O is effective.
  698init_optimise :-
  699    current_prolog_flag(optimise, true),
  700    !,
  701    use_module(user:library(apply_macros)).
  702init_optimise.
  703
  704opt_attach_packs :-
  705    current_prolog_flag(packs, true),
  706    !,
  707    attach_packs.
  708opt_attach_packs.
  709
  710set_toplevel :-
  711    '$cmd_option_val'(toplevel, TopLevelAtom),
  712    catch(term_to_atom(TopLevel, TopLevelAtom), E,
  713          (print_message(error, E),
  714           halt(1))),
  715    create_prolog_flag(toplevel_goal, TopLevel, [type(term)]).
  716
  717load_only :-
  718    current_prolog_flag(os_argv, OSArgv),
  719    memberchk('-l', OSArgv),
  720    current_prolog_flag(argv, Argv),
  721    \+ memberchk('-l', Argv).
 run_init_goals(+Goals) is det
Run registered initialization goals on order. If a goal fails, execution is halted.
  728run_init_goals([]).
  729run_init_goals([H|T]) :-
  730    run_init_goal(H),
  731    run_init_goals(T).
  732
  733run_init_goal(Text) :-
  734    catch(term_to_atom(Goal, Text), E,
  735          (   print_message(error, init_goal_syntax(E, Text)),
  736              halt(2)
  737          )),
  738    run_init_goal(Goal, Text).
 run_program_init is det
Run goals registered using
  744run_program_init :-
  745    forall('$init_goal'(when(program), Goal, Ctx),
  746           run_init_goal(Goal, @(Goal,Ctx))).
  747
  748run_main_init(_) :-
  749    findall(Goal-Ctx, '$init_goal'(when(main), Goal, Ctx), Pairs),
  750    '$last'(Pairs, Goal-Ctx),
  751    !,
  752    (   current_prolog_flag(toplevel_goal, default)
  753    ->  set_prolog_flag(toplevel_goal, halt)
  754    ;   true
  755    ),
  756    run_init_goal(Goal, @(Goal,Ctx)).
  757run_main_init(true) :-
  758    '$existence_error'(initialization, main).
  759run_main_init(_).
  760
  761run_init_goal(Goal, Ctx) :-
  762    (   catch_with_backtrace(user:Goal, E, true)
  763    ->  (   var(E)
  764        ->  true
  765        ;   init_goal_failed(E, Ctx)
  766        )
  767    ;   (   current_prolog_flag(verbose, silent)
  768        ->  Level = silent
  769        ;   Level = error
  770        ),
  771        print_message(Level, init_goal_failed(failed, Ctx)),
  772        halt(1)
  773    ).
  774
  775init_goal_failed(E, Ctx) :-
  776    print_message(error, init_goal_failed(E, Ctx)),
  777    init_goal_failed(E).
  778
  779init_goal_failed(_) :-
  780    thread_self(main),
  781    !,
  782    halt(2).
  783init_goal_failed(_).
 init_debug_flags is det
Initialize the various Prolog flags that control the debugger and toplevel.
  790init_debug_flags :-
  791    Keep = [keep(true)],
  792    create_prolog_flag(answer_write_options,
  793                       [ quoted(true), portray(true), max_depth(10),
  794                         spacing(next_argument)], Keep),
  795    create_prolog_flag(prompt_alternatives_on, determinism, Keep),
  796    create_prolog_flag(toplevel_extra_white_line, true, Keep),
  797    create_prolog_flag(toplevel_print_factorized, false, Keep),
  798    create_prolog_flag(print_write_options,
  799                       [ portray(true), quoted(true), numbervars(true) ],
  800                       Keep),
  801    create_prolog_flag(toplevel_residue_vars, false, Keep),
  802    create_prolog_flag(toplevel_list_wfs_residual_program, true, Keep),
  803    '$set_debugger_write_options'(print).
 setup_backtrace
Initialise printing a backtrace.
  809setup_backtrace :-
  810    (   \+ current_prolog_flag(backtrace, false),
  811        load_setup_file(library(prolog_stack))
  812    ->  true
  813    ;   true
  814    ).
 setup_colors is det
Setup interactive usage by enabling colored output.
  820setup_colors :-
  821    (   \+ current_prolog_flag(color_term, false),
  822        stream_property(user_input, tty(true)),
  823        stream_property(user_error, tty(true)),
  824        stream_property(user_output, tty(true)),
  825        \+ getenv('TERM', dumb),
  826        load_setup_file(user:library(ansi_term))
  827    ->  true
  828    ;   true
  829    ).
 setup_history
Enable per-directory persistent history.
  835setup_history :-
  836    (   \+ current_prolog_flag(save_history, false),
  837        stream_property(user_input, tty(true)),
  838        \+ current_prolog_flag(readline, false),
  839        load_setup_file(library(prolog_history))
  840    ->  prolog_history(enable)
  841    ;   true
  842    ).
 setup_readline
Setup line editing.
  848setup_readline :-
  849    (   stream_property(user_input, tty(true)),
  850        current_prolog_flag(tty_control, true),
  851        \+ getenv('TERM', dumb),
  852        (   current_prolog_flag(readline, ReadLine)
  853        ->  true
  854        ;   ReadLine = true
  855        ),
  856        readline_library(ReadLine, Library),
  857        (   load_setup_file(library(Library))
  858        ->  true
  859        ;   current_prolog_flag(epilog, true),
  860            print_message(warning,
  861                          error(existence_error(library, library(Library)),
  862                                _)),
  863            fail
  864        )
  865    ->  set_prolog_flag(readline, Library)
  866    ;   set_prolog_flag(readline, false)
  867    ).
  868
  869readline_library(true, Library) :-
  870    !,
  871    preferred_readline(Library).
  872readline_library(false, _) :-
  873    !,
  874    fail.
  875readline_library(Library, Library).
  876
  877preferred_readline(editline).
 load_setup_file(+File) is semidet
Load a file and fail silently if the file does not exist.
  883load_setup_file(File) :-
  884    catch(load_files(File,
  885                     [ silent(true),
  886                       if(not_loaded)
  887                     ]), error(_,_), fail).
 setup_app is det
When running as an "app", behave as such. The behaviour depends on the platform.
Windows
If Prolog is started using --win_app, try to change directory to <My Documents>\Prolog.
  899:- if(current_prolog_flag(windows,true)).  900
  901setup_app :-
  902    current_prolog_flag(associated_file, _),
  903    !.
  904setup_app :-
  905    '$cmd_option_val'(win_app, true),
  906    !,
  907    catch(my_prolog, E, print_message(warning, E)).
  908setup_app.
  909
  910my_prolog :-
  911    win_folder(personal, MyDocs),
  912    atom_concat(MyDocs, '/Prolog', PrologDir),
  913    (   ensure_dir(PrologDir)
  914    ->  working_directory(_, PrologDir)
  915    ;   working_directory(_, MyDocs)
  916    ).
  917
  918ensure_dir(Dir) :-
  919    exists_directory(Dir),
  920    !.
  921ensure_dir(Dir) :-
  922    catch(make_directory(Dir), E, (print_message(warning, E), fail)).
  923
  924:- elif(current_prolog_flag(apple, true)).  925use_app_settings(true).                        % Indicate we need app settings
  926
  927setup_app :-
  928    apple_set_locale,
  929    current_prolog_flag(associated_file, _),
  930    !.
  931setup_app :-
  932    current_prolog_flag(bundle, true),
  933    current_prolog_flag(epilog, true),
  934    getenv('__CFBundleIdentifier', _),
  935    !,
  936    setup_macos_app.
  937setup_app.
  938
  939apple_set_locale :-
  940    (   getenv('LC_CTYPE', 'UTF-8'),
  941        apple_current_locale_identifier(LocaleID),
  942        atom_concat(LocaleID, '.UTF-8', Locale),
  943        catch(setlocale(ctype, _Old, Locale), _, fail)
  944    ->  setenv('LANG', Locale),
  945        unsetenv('LC_CTYPE')
  946    ;   true
  947    ).
  948
  949setup_macos_app :-
  950    restore_working_directory,
  951    !.
  952setup_macos_app :-
  953    expand_file_name('~/Prolog', [PrologDir]),
  954    (   exists_directory(PrologDir)
  955    ->  true
  956    ;   catch(make_directory(PrologDir), MkDirError,
  957              print_message(warning, MkDirError))
  958    ),
  959    catch(working_directory(_, PrologDir), CdError,
  960          print_message(warning, CdError)),
  961    !.
  962setup_macos_app.
  963
  964:- elif(current_prolog_flag(emscripten, true)).  965setup_app.
  966:- else.  967use_app_settings(true).                        % Indicate we need app settings
  968
  969% Other (Unix-like) platforms.
  970setup_app :-
  971    running_as_app,
  972    restore_working_directory,
  973    !.
  974setup_app.
 running_as_app is semidet
True if we were started from the dock.
  980running_as_app :-
  981%   getenv('FLATPAK_SANDBOX_DIR', _),
  982    current_prolog_flag(epilog, true),
  983    stream_property(In, file_no(0)),
  984    \+ stream_property(In, tty(true)),
  985    !.
  986
  987:- endif.  988
  989
  990:- if((current_predicate(use_app_settings/1),
  991       use_app_settings(true))).  992
  993
  994                /*******************************
  995                *    APP WORKING DIRECTORY     *
  996                *******************************/
  997
  998save_working_directory :-
  999    working_directory(WD, WD),
 1000    app_settings(Settings),
 1001    (   Settings.get(working_directory) == WD
 1002    ->  true
 1003    ;   app_save_settings(Settings.put(working_directory, WD))
 1004    ).
 1005
 1006restore_working_directory :-
 1007    at_halt(save_working_directory),
 1008    app_settings(Settings),
 1009    WD = Settings.get(working_directory),
 1010    catch(working_directory(_, WD), _, fail),
 1011    !.
 1012
 1013                /*******************************
 1014                *           SETTINGS           *
 1015                *******************************/
 app_settings(-Settings:dict) is det
Get a dict holding the persistent application settings.
 1021app_settings(Settings) :-
 1022    app_settings_file(File),
 1023    access_file(File, read),
 1024    catch(setup_call_cleanup(
 1025              open(File, read, In, [encoding(utf8)]),
 1026              read_term(In, Settings, []),
 1027              close(In)),
 1028          Error,
 1029          (print_message(warning, Error), fail)),
 1030    !.
 1031app_settings(#{}).
 app_save_settings(+Settings:dict) is det
Save the given application settings dict.
 1037app_save_settings(Settings) :-
 1038    app_settings_file(File),
 1039    catch(setup_call_cleanup(
 1040              open(File, write, Out, [encoding(utf8)]),
 1041              write_term(Out, Settings,
 1042                         [ quoted(true),
 1043                           module(system), % default operators
 1044                           fullstop(true),
 1045                           nl(true)
 1046                         ]),
 1047              close(Out)),
 1048          Error,
 1049          (print_message(warning, Error), fail)).
 1050
 1051
 1052app_settings_file(File) :-
 1053    absolute_file_name(user_app_config('app_settings.pl'), File,
 1054                       [ access(write),
 1055                         file_errors(fail)
 1056                       ]).
 1057:- endif.% app_settings
 1058
 1059                /*******************************
 1060                *           TOPLEVEL           *
 1061                *******************************/
 1062
 1063:- '$hide'('$toplevel'/0).              % avoid in the GUI stacktrace
 $toplevel
Called from PL_toplevel()
 1069'$toplevel' :-
 1070    '$runtoplevel',
 1071    print_message(informational, halt).
 $runtoplevel
Actually run the toplevel. The values default and prolog both start the interactive toplevel, where prolog implies the user gave -t prolog.
See also
- prolog/0 is the default interactive toplevel
 1081'$runtoplevel' :-
 1082    current_prolog_flag(toplevel_goal, TopLevel0),
 1083    toplevel_goal(TopLevel0, TopLevel),
 1084    user:TopLevel.
 1085
 1086:- dynamic  setup_done/0. 1087:- volatile setup_done/0. 1088
 1089toplevel_goal(default, '$query_loop') :-
 1090    !,
 1091    setup_interactive.
 1092toplevel_goal(prolog, '$query_loop') :-
 1093    !,
 1094    setup_interactive.
 1095toplevel_goal(Goal, Goal).
 1096
 1097setup_interactive :-
 1098    setup_done,
 1099    !.
 1100setup_interactive :-
 1101    asserta(setup_done),
 1102    catch(setup_backtrace, E, print_message(warning, E)),
 1103    catch(setup_readline,  E, print_message(warning, E)),
 1104    catch(setup_history,   E, print_message(warning, E)).
 $compile
Toplevel called when invoked with -c option.
 1110'$compile' :-
 1111    (   catch('$compile_', E, (print_message(error, E), halt(1)))
 1112    ->  true
 1113    ;   print_message(error, error(goal_failed('$compile'), _)),
 1114        halt(1)
 1115    ),
 1116    halt.                               % set exit code
 1117
 1118'$compile_' :-
 1119    '$load_system_init_file',
 1120    catch(setup_colors, _, true),
 1121    '$set_file_search_paths',
 1122    init_debug_flags,
 1123    '$run_initialization',
 1124    opt_attach_packs,
 1125    use_module(library(qsave)),
 1126    qsave:qsave_toplevel.
 $config
Toplevel when invoked with --dump-runtime-variables
 1132'$config' :-
 1133    '$load_system_init_file',
 1134    '$set_file_search_paths',
 1135    init_debug_flags,
 1136    '$run_initialization',
 1137    load_files(library(prolog_config)),
 1138    (   catch(prolog_dump_runtime_variables, E,
 1139              (print_message(error, E), halt(1)))
 1140    ->  true
 1141    ;   print_message(error, error(goal_failed(prolog_dump_runtime_variables),_))
 1142    ).
 1143
 1144
 1145                /********************************
 1146                *    USER INTERACTIVE LOOP      *
 1147                *********************************/
 prolog:repl_loop_hook(+BeginEnd, +BreakLevel) is nondet
Multifile hook that allows acting on starting/stopping the interactive REPL loop. Called as
forall(prolog:repl_loop_hook(BeginEnd, BreakLevel), true)
Arguments:
BeginEnd- is one of begin or end
BreakLevel- is 0 for the normal toplevel, -1 when non-interactive and >0 for break environments.
 1160:- multifile
 1161    prolog:repl_loop_hook/2.
 prolog
Run the Prolog toplevel. This is now the same as break/0, which pretends to be in a break-level if there is a parent environment.
 1169prolog :-
 1170    break.
 1171
 1172:- create_prolog_flag(toplevel_mode, backtracking, []).
 $query_loop
Run the normal Prolog query loop. Note that the query is not protected by catch/3. Dealing with unhandled exceptions is done by the C-function query_loop(). This ensures that unhandled exceptions are really unhandled (in Prolog).
 1181'$query_loop' :-
 1182    break_level(BreakLev),
 1183    setup_call_cleanup(
 1184        notrace(call_repl_loop_hook(begin, BreakLev, IsToplevel)),
 1185        '$query_loop'(BreakLev),
 1186        notrace(call_repl_loop_hook(end, BreakLev, IsToplevel))).
 1187
 1188call_repl_loop_hook(begin, BreakLev, IsToplevel) =>
 1189    (   current_prolog_flag(toplevel_thread, IsToplevel)
 1190    ->  true
 1191    ;   IsToplevel = false
 1192    ),
 1193    set_prolog_flag(toplevel_thread, true),
 1194    call_repl_loop_hook_(begin, BreakLev).
 1195call_repl_loop_hook(end, BreakLev, IsToplevel) =>
 1196    set_prolog_flag(toplevel_thread, IsToplevel),
 1197    call_repl_loop_hook_(end, BreakLev).
 1198
 1199call_repl_loop_hook_(BeginEnd, BreakLev) :-
 1200    forall(prolog:repl_loop_hook(BeginEnd, BreakLev), true).
 1201
 1202
 1203'$query_loop'(BreakLev) :-
 1204    current_prolog_flag(toplevel_mode, recursive),
 1205    !,
 1206    read_expanded_query(BreakLev, Query, Bindings),
 1207    (   Query == end_of_file
 1208    ->  print_message(query, query(eof))
 1209    ;   '$call_no_catch'('$execute_query'(Query, Bindings, _)),
 1210        (   current_prolog_flag(toplevel_mode, recursive)
 1211        ->  '$query_loop'(BreakLev)
 1212        ;   '$switch_toplevel_mode'(backtracking),
 1213            '$query_loop'(BreakLev)     % Maybe throw('$switch_toplevel_mode')?
 1214        )
 1215    ).
 1216'$query_loop'(BreakLev) :-
 1217    repeat,
 1218        read_expanded_query(BreakLev, Query, Bindings),
 1219        (   Query == end_of_file
 1220        ->  !, print_message(query, query(eof))
 1221        ;   '$execute_query'(Query, Bindings, _),
 1222            (   current_prolog_flag(toplevel_mode, recursive)
 1223            ->  !,
 1224                '$switch_toplevel_mode'(recursive),
 1225                '$query_loop'(BreakLev)
 1226            ;   fail
 1227            )
 1228        ).
 1229
 1230break_level(BreakLev) :-
 1231    (   current_prolog_flag(break_level, BreakLev)
 1232    ->  true
 1233    ;   BreakLev = -1
 1234    ).
 1235
 1236read_expanded_query(BreakLev, ExpandedQuery, ExpandedBindings) :-
 1237    '$current_typein_module'(TypeIn),
 1238    (   stream_property(user_input, tty(true))
 1239    ->  '$system_prompt'(TypeIn, BreakLev, Prompt),
 1240        decorate_prompt('|    ', Continue),
 1241        prompt(Old, Continue)
 1242    ;   Prompt = '',
 1243        prompt(Old, '')
 1244    ),
 1245    reset_answer_count,
 1246    trim_stacks,
 1247    trim_heap,
 1248    repeat,
 1249      (   catch(call_cleanup(read_query(Prompt, Query, Bindings),
 1250                             end_input_style),
 1251                error(io_error(_,_),_), fail)
 1252      ->  prompt(_, Old),
 1253          catch(call_expand_query(Query, ExpandedQuery,
 1254                                  Bindings, ExpandedBindings),
 1255                Error,
 1256                (print_message(error, Error), fail))
 1257      ;   set_prolog_flag(debug_on_error, false),
 1258          thread_exit(io_error)
 1259      ),
 1260    !.
 read_query(+Prompt, -Goal, -Bindings) is det
Read the next query. The first clause deals with the case where !-based history is enabled. The second is used if we have command line editing.
 1269:- multifile
 1270    prolog:history/2. 1271
 1272:- if(current_prolog_flag(emscripten, true)). 1273read_query(_Prompt, Goal, Bindings) :-
 1274    '$can_yield',
 1275    !,
 1276    await(query, GoalString),
 1277    term_string(Goal, GoalString, [variable_names(Bindings)]).
 1278:- endif. 1279read_query(Prompt, Goal, Bindings) :-
 1280    prolog:history(current_input, enabled),
 1281    !,
 1282    decorate_prompt(Prompt, DPrompt),
 1283    read_term_with_history(
 1284        Goal,
 1285        [ show(h),
 1286          help('!h'),
 1287          no_save([trace]),
 1288          prompt(DPrompt),
 1289          variable_names(Bindings)
 1290        ]).
 1291read_query(Prompt, Goal, Bindings) :-
 1292    remove_history_prompt(Prompt, Prompt0),
 1293    decorate_prompt(Prompt0, Prompt1),
 1294    repeat,                                 % over syntax errors
 1295    prompt1(Prompt1),
 1296    read_query_line(user_input, Line),
 1297    '$current_typein_module'(TypeIn),
 1298    catch(read_term_from_atom(Line, Goal,
 1299                              [ variable_names(Bindings),
 1300                                module(TypeIn),
 1301                                blob(resolve)
 1302                              ]), E,
 1303          (   print_message(error, E),
 1304              fail
 1305          )),
 1306    !.
 read_query_line(+Input, -Query:atom) is det
Read a query as an atom. If Query is '$silent'(Goal), execute Goal in module user and read the next query. This supports injecting goals in some GNU-Emacs modes.
 1314read_query_line(Input, Line) :-
 1315    stream_property(Input, error(true)),
 1316    !,
 1317    Line = end_of_file.
 1318read_query_line(Input, Line) :-
 1319    catch(read_term_as_atom(Input, Line0), Error, true),
 1320    end_input_style,                    % before a possible syntax error
 1321    save_debug_after_read,
 1322    (   var(Error)
 1323    ->  (   catch(term_string(Goal, Line0), error(_,_), fail),
 1324            Goal = '$silent'(SilentGoal)
 1325        ->  Error = error(_,_),
 1326            catch_with_backtrace(ignore(SilentGoal), Error,
 1327                                 print_message(error, Error)),
 1328            read_query_line(Input, Line)
 1329        ;   Line = Line0
 1330        )
 1331    ;   catch(print_message(error, Error), _, true),
 1332        (   Error = error(syntax_error(_),_)
 1333        ->  fail
 1334        ;   throw(Error)
 1335        )
 1336    ).
 read_term_as_atom(+Input, -Line)
Read the next term as an atom and skip to the newline or a non-space character.
 1343read_term_as_atom(In, Line) :-
 1344    '$raw_read'(In, Line),
 1345    (   Line == end_of_file
 1346    ->  true
 1347    ;   skip_to_nl(In)
 1348    ).
 skip_to_nl(+Input) is det
Read input after the term. Skips white space and %... comment until the end of the line or a non-blank character.
 1355skip_to_nl(In) :-
 1356    repeat,
 1357    peek_char(In, C),
 1358    (   C == '%'
 1359    ->  skip(In, '\n')
 1360    ;   char_type(C, space)
 1361    ->  get_char(In, _),
 1362        C == '\n'
 1363    ;   true
 1364    ),
 1365    !.
 1366
 1367remove_history_prompt('', '') :- !.
 1368remove_history_prompt(Prompt0, Prompt) :-
 1369    atom_chars(Prompt0, Chars0),
 1370    clean_history_prompt_chars(Chars0, Chars1),
 1371    delete_leading_blanks(Chars1, Chars),
 1372    atom_chars(Prompt, Chars).
 1373
 1374clean_history_prompt_chars([], []).
 1375clean_history_prompt_chars(['~', !|T], T) :- !.
 1376clean_history_prompt_chars([H|T0], [H|T]) :-
 1377    clean_history_prompt_chars(T0, T).
 1378
 1379delete_leading_blanks([' '|T0], T) :-
 1380    !,
 1381    delete_leading_blanks(T0, T).
 1382delete_leading_blanks(L, L).
 1383
 1384
 1385                 /*******************************
 1386                 *        TOPLEVEL DEBUG        *
 1387                 *******************************/
 save_debug_after_read
Called right after the toplevel read to save the debug status if it was modified from the GUI thread using e.g.
thread_signal(main, gdebug)
bug
- Ideally, the prompt would change if debug mode is enabled. That is hard to realise with all the different console interfaces supported by SWI-Prolog.
 1402save_debug_after_read :-
 1403    current_prolog_flag(debug, true),
 1404    !,
 1405    save_debug.
 1406save_debug_after_read.
 1407
 1408save_debug :-
 1409    (   tracing,
 1410        notrace
 1411    ->  Tracing = true
 1412    ;   Tracing = false
 1413    ),
 1414    current_prolog_flag(debug, Debugging),
 1415    set_prolog_flag(debug, false),
 1416    create_prolog_flag(query_debug_settings,
 1417                       debug(Debugging, Tracing), []).
 1418
 1419restore_debug :-
 1420    current_prolog_flag(query_debug_settings, debug(Debugging, Tracing)),
 1421    set_prolog_flag(debug, Debugging),
 1422    (   Tracing == true
 1423    ->  trace
 1424    ;   true
 1425    ).
 1426
 1427:- initialization
 1428    create_prolog_flag(query_debug_settings, debug(false, false), []). 1429
 1430
 1431                /********************************
 1432                *            PROMPTING          *
 1433                ********************************/
 $answer_class(-Class) is semidet
Colour class for the answer that is being written, or fail if it must not be decorated. Class is answer(odd) or answer(even), alternating over the answers of a single query. Using a different background colour for both stripes the answers, which separates the answers of a non-deterministic query.

Only an answer that shows bindings, residual goals or delays is decorated: true. and false. are not answers to stripe.

Exported (and thus $-prefixed) because it is used by boot/messages.pl. It is not intended for use by applications.

 1449'$answer_class'(Class) :-
 1450    nb_current('$answer_class', Class),
 1451    Class \== none.
 1452
 1453answer_count(Count) :-
 1454    (   nb_current('$answer_count', C)
 1455    ->  Count = C
 1456    ;   Count = 0
 1457    ).
 1458
 1459reset_answer_count :-
 1460    nb_setval('$answer_count', 0),
 1461    no_answer.
 no_answer is det
The message about to be written is not an answer that shows bindings. Used for true., false. and the empty line that ends the interaction.
 1469no_answer :-
 1470    nb_setval('$answer_class', none).
 next_answer(+Bindings, +Delays, +Residuals) is det
Start a new answer. See '$answer_class'/1.
 1476next_answer([], true, []-[]) :-
 1477    !,
 1478    no_answer.
 1479next_answer(_Bindings, _Delays, _Residuals) :-
 1480    answer_count(C0),
 1481    C is C0+1,
 1482    nb_setval('$answer_count', C),
 1483    (   C mod 2 =:= 0
 1484    ->  Class = answer(even)
 1485    ;   Class = answer(odd)
 1486    ),
 1487    nb_setval('$answer_class', Class).
 decorate_prompt(+Plain, -Decorated) is det
Add ANSI escape sequences to the prompt Plain. The result has a three-part structure:
  1. The attributes of the colour class input followed by `\e[K`. As the prompt is written at the start of a line this paints the entire line, which makes a background colour extend to the right margin.
  2. The attributes of the colour class prompt, the prompt itself and a reset.
  3. The attributes of input again. These remain in effect while the user is typing, which is how the typed text is coloured differently from the output. end_input_style/0 cancels this once the query has been read.

Note that the line editor (see library(editline)) does not count escape sequences towards the prompt width and neither does line_position/2.

 1509decorate_prompt('', Prompt) :-
 1510    !,
 1511    Prompt = ''.                        % not connected to a terminal
 1512decorate_prompt(Plain, Decorated) :-
 1513    prompt_sgr(input, Input),
 1514    prompt_sgr(prompt, Prompt),
 1515    line_editor_attributes(Input),
 1516    (   Input == '',
 1517        Prompt == ''
 1518    ->  Decorated = Plain
 1519    ;   Input == ''                     % nothing to paint the line with
 1520    ->  atomic_list_concat([Prompt, Plain, '\e[0m'], Decorated)
 1521    ;   atomic_list_concat([Input, '\e[K', Prompt, Plain, '\e[0m', Input],
 1522                           Decorated)
 1523    ).
 line_editor_attributes(+Input) is det
Tell the line editor how to switch the decoration of the input line off and on again. The line editor erases the rows the line no longer uses when it gets shorter, for example when a wrapped line is shortened or when we move to a shorter history entry. Erasing paints with the current background colour, so it must switch our attributes off first and put them back afterwards.

This is called each time we build a prompt rather than once, so that a theme loaded at run time is picked up.

See also
- the hook prolog:line_editor_attributes/2, implemented by library(editline).
 1540line_editor_attributes(Input) :-
 1541    (   Input == ''
 1542    ->  Off = '', On = ''
 1543    ;   Off = '\e[0m', On = Input
 1544    ),
 1545    ignore(prolog:line_editor_attributes(Off, On)).
 1546
 1547prompt_sgr(Class, Sequence) :-
 1548    colour_console,
 1549    current_predicate(ansi_term:ansi_sgr/2),
 1550    catch(ansi_term:ansi_sgr(Class, String), _, fail),
 1551    String \== "",
 1552    !,
 1553    atom_string(Sequence, String).
 1554prompt_sgr(_, '').
 1555
 1556colour_console :-
 1557    current_prolog_flag(color_term, true),
 1558    stream_property(user_output, tty(true)).
 end_input_style is det
Cancel the attributes installed by decorate_prompt/2 once the query has been read. Without this, output of the query would be written using the attributes of the colour class input.
 1566end_input_style :-
 1567    (   colour_console
 1568    ->  write(user_output, '\e[0m'),
 1569        flush_output(user_output)
 1570    ;   true
 1571    ).
 1572
 1573'$system_prompt'(Module, BrekLev, Prompt) :-
 1574    current_prolog_flag(toplevel_prompt, PAtom),
 1575    atom_codes(PAtom, P0),
 1576    (    Module \== user
 1577    ->   '$substitute'('~m', [Module, ': '], P0, P1)
 1578    ;    '$substitute'('~m', [], P0, P1)
 1579    ),
 1580    (    BrekLev > 0
 1581    ->   '$substitute'('~l', ['[', BrekLev, '] '], P1, P2)
 1582    ;    '$substitute'('~l', [], P1, P2)
 1583    ),
 1584    current_prolog_flag(query_debug_settings, debug(Debugging, Tracing)),
 1585    (    Tracing == true
 1586    ->   '$substitute'('~d', ['[trace] '], P2, P3)
 1587    ;    Debugging == true
 1588    ->   '$substitute'('~d', ['[debug] '], P2, P3)
 1589    ;    '$substitute'('~d', [], P2, P3)
 1590    ),
 1591    atom_chars(Prompt, P3).
 1592
 1593'$substitute'(From, T, Old, New) :-
 1594    atom_codes(From, FromCodes),
 1595    phrase(subst_chars(T), T0),
 1596    '$append'(Pre, S0, Old),
 1597    '$append'(FromCodes, Post, S0) ->
 1598    '$append'(Pre, T0, S1),
 1599    '$append'(S1, Post, New),
 1600    !.
 1601'$substitute'(_, _, Old, Old).
 1602
 1603subst_chars([]) -->
 1604    [].
 1605subst_chars([H|T]) -->
 1606    { atomic(H),
 1607      !,
 1608      atom_codes(H, Codes)
 1609    },
 1610    Codes,
 1611    subst_chars(T).
 1612subst_chars([H|T]) -->
 1613    H,
 1614    subst_chars(T).
 1615
 1616
 1617                /********************************
 1618                *           EXECUTION           *
 1619                ********************************/
 $execute_query(Goal, Bindings, -Truth) is det
Execute Goal using Bindings.
 1625'$execute_query'(Var, _, true) :-
 1626    var(Var),
 1627    !,
 1628    print_message(informational, var_query(Var)).
 1629'$execute_query'(Goal, Bindings, Truth) :-
 1630    '$current_typein_module'(TypeIn),
 1631    '$dwim_correct_goal'(TypeIn:Goal, Bindings, Corrected),
 1632    !,
 1633    setup_call_cleanup(
 1634        '$set_source_module'(M0, TypeIn),
 1635        expand_goal(Corrected, Expanded),
 1636        '$set_source_module'(M0)),
 1637    print_message(silent, toplevel_goal(Expanded, Bindings)),
 1638    '$execute_goal2'(Expanded, Bindings, Truth).
 1639'$execute_query'(_, _, false) :-
 1640    notrace,
 1641    no_answer,
 1642    print_message(query, query(no)).
 1643
 1644'$execute_goal2'(Goal, Bindings, true) :-
 1645    restore_debug,
 1646    '$current_typein_module'(TypeIn),
 1647    residue_vars(TypeIn:Goal, Vars, TypeIn:Delays, Chp),
 1648    deterministic(Det),
 1649    (   save_debug
 1650    ;   restore_debug, fail
 1651    ),
 1652    flush_output(user_output),
 1653    (   Det == true
 1654    ->  DetOrChp = true
 1655    ;   DetOrChp = Chp
 1656    ),
 1657    call_expand_answer(Goal, Bindings, NewBindings),
 1658    (    \+ \+ write_bindings(NewBindings, Vars, Delays, DetOrChp)
 1659    ->   !
 1660    ).
 1661'$execute_goal2'(_, _, false) :-
 1662    save_debug,
 1663    no_answer,
 1664    print_message(query, query(no)).
 1665
 1666residue_vars(Goal, Vars, Delays, Chp) :-
 1667    current_prolog_flag(toplevel_residue_vars, true),
 1668    !,
 1669    '$wfs_call'(call_residue_vars(stop_backtrace(Goal, Chp), Vars), Delays).
 1670residue_vars(Goal, [], Delays, Chp) :-
 1671    '$wfs_call'(stop_backtrace(Goal, Chp), Delays).
 1672
 1673stop_backtrace(Goal, Chp) :-
 1674    toplevel_call(Goal),
 1675    prolog_current_choice(Chp).
 1676
 1677toplevel_call(Goal) :-
 1678    call(Goal),
 1679    no_lco.
 1680
 1681no_lco.
 write_bindings(+Bindings, +ResidueVars, +Delays, +DetOrChp) is semidet
Write bindings resulting from a query. The flag prompt_alternatives_on determines whether the user is prompted for alternatives. groundness gives the classical behaviour, determinism is considered more adequate and informative.

Succeeds if the user accepts the answer and fails otherwise.

Arguments:
ResidueVars- are the residual constraints and provided if the prolog flag toplevel_residue_vars is set to project.
 1697write_bindings(Bindings, ResidueVars, Delays, DetOrChp) :-
 1698    '$current_typein_module'(TypeIn),
 1699    translate_bindings(Bindings, Bindings1, ResidueVars, TypeIn:Residuals),
 1700    omit_qualifier(Delays, TypeIn, Delays1),
 1701    next_answer(Bindings1, Delays1, Residuals),
 1702    write_bindings2(Bindings, Bindings1, Residuals, Delays1, DetOrChp).
 1703
 1704write_bindings2(OrgBindings, [], Residuals, Delays, _) :-
 1705    current_prolog_flag(prompt_alternatives_on, groundness),
 1706    !,
 1707    name_vars(OrgBindings, [], t(Residuals, Delays)),
 1708    print_message(query, query(yes(Delays, Residuals))).
 1709write_bindings2(OrgBindings, Bindings, Residuals, Delays, true) :-
 1710    current_prolog_flag(prompt_alternatives_on, determinism),
 1711    !,
 1712    name_vars(OrgBindings, Bindings, t(Residuals, Delays)),
 1713    print_message(query, query(yes(Bindings, Delays, Residuals))).
 1714write_bindings2(OrgBindings, Bindings, Residuals, Delays, Chp) :-
 1715    repeat,
 1716        name_vars(OrgBindings, Bindings, t(Residuals, Delays)),
 1717        print_message(query, query(more(Bindings, Delays, Residuals))),
 1718        get_respons(Action, Chp),
 1719    (   Action == redo
 1720    ->  !, fail
 1721    ;   Action == show_again
 1722    ->  fail
 1723    ;   !,
 1724        no_answer,
 1725        print_message(query, query(done))
 1726    ).
 name_vars(+OrgBinding, +Bindings, +Term) is det
Give a name _[A-Z][0-9]* to all variables in Term, that do not have a name due to Bindings. Singleton variables in Term are named _. The behavior depends on these Prolog flags:
toplevel_name_variables
Only act when true, else name_vars/3 is a no-op.
toplevel_print_anon

Variables are named by unifying them to '$VAR'(Name)

Arguments:
Bindings- is a list Name=Value
 1742name_vars(OrgBindings, Bindings, Term) :-
 1743    current_prolog_flag(toplevel_name_variables, true),
 1744    answer_flags_imply_numbervars,
 1745    !,
 1746    '$term_multitons'(t(Bindings,Term), Vars),
 1747    bindings_var_names(OrgBindings, Bindings, VarNames),
 1748    name_vars_(Vars, VarNames, 0),
 1749    term_variables(t(Bindings,Term), SVars),
 1750    anon_vars(SVars).
 1751name_vars(_OrgBindings, _Bindings, _Term).
 1752
 1753name_vars_([], _, _).
 1754name_vars_([H|T], Bindings, N) :-
 1755    name_var(Bindings, Name, N, N1),
 1756    H = '$VAR'(Name),
 1757    name_vars_(T, Bindings, N1).
 1758
 1759anon_vars([]).
 1760anon_vars(['$VAR'('_')|T]) :-
 1761    anon_vars(T).
 name_var(+Reserved, -Name, +N0, -N) is det
True when Name is a valid name for a new variable where the search is guided by the number N0. Name may not appear in Reserved.
 1768name_var(Reserved, Name, N0, N) :-
 1769    between(N0, infinite, N1),
 1770    I is N1//26,
 1771    J is 0'A + N1 mod 26,
 1772    (   I == 0
 1773    ->  format(atom(Name), '_~c', [J])
 1774    ;   format(atom(Name), '_~c~d', [J, I])
 1775    ),
 1776    \+ memberchk(Name, Reserved),
 1777    !,
 1778    N is N1+1.
 bindings_var_names(+OrgBindings, +TransBindings, -VarNames) is det
Find the joined set of variable names in the original bindings and translated bindings. When generating new names, we better also omit names that appear in the original bindings (but not in the translated bindigns).
 1787bindings_var_names(OrgBindings, TransBindings, VarNames) :-
 1788    phrase(bindings_var_names_(OrgBindings), VarNames0, Tail),
 1789    phrase(bindings_var_names_(TransBindings), Tail, []),
 1790    sort(VarNames0, VarNames).
 bindings_var_names_(+Bindings)// is det
Produce a list of variable names that appear in Bindings. This deals both with the single and joined representation of bindings.
 1797bindings_var_names_([]) --> [].
 1798bindings_var_names_([H|T]) -->
 1799    binding_var_names(H),
 1800    bindings_var_names_(T).
 1801
 1802binding_var_names(binding(Vars,_Value,_Subst)) ==>
 1803    var_names(Vars).
 1804binding_var_names(Name=_Value) ==>
 1805    [Name].
 1806
 1807var_names([]) --> [].
 1808var_names([H|T]) --> [H], var_names(T).
 answer_flags_imply_numbervars
True when the answer will be written recognising '$VAR'(N). If this is not the case we should not try to name the variables.
 1816answer_flags_imply_numbervars :-
 1817    current_prolog_flag(answer_write_options, Options),
 1818    numbervars_option(Opt),
 1819    '$option'(Opt, Options),
 1820    !.
 1821
 1822numbervars_option(portray(true)).
 1823numbervars_option(portrayed(true)).
 1824numbervars_option(numbervars(true)).
 residual_goals(:NonTerminal)
Directive that registers NonTerminal as a collector for residual goals.
 1831:- multifile
 1832    residual_goal_collector/1. 1833
 1834:- meta_predicate
 1835    residual_goals(2). 1836
 1837residual_goals(NonTerminal) :-
 1838    throw(error(context_error(nodirective, residual_goals(NonTerminal)), _)).
 1839
 1840system:term_expansion((:- residual_goals(NonTerminal)),
 1841                      '$toplevel':residual_goal_collector(M2:Head)) :-
 1842    \+ current_prolog_flag(xref, true),
 1843    prolog_load_context(module, M),
 1844    strip_module(M:NonTerminal, M2, Head),
 1845    '$must_be'(callable, Head).
 prolog:residual_goals// is det
DCG that collects residual goals that are not associated with the answer through attributed variables.
 1852:- public prolog:residual_goals//0. 1853
 1854prolog:residual_goals -->
 1855    { findall(NT, residual_goal_collector(NT), NTL) },
 1856    collect_residual_goals(NTL).
 1857
 1858collect_residual_goals([]) --> [].
 1859collect_residual_goals([H|T]) -->
 1860    ( call(H) -> [] ; [] ),
 1861    collect_residual_goals(T).
 prolog:translate_bindings(+Bindings0, -Bindings, +ResidueVars, +ResidualGoals, -Residuals) is det
Translate the raw variable bindings resulting from successfully completing a query into a binding list and list of residual goals suitable for human consumption.
Arguments:
Bindings- is a list of binding(Vars,Value,Substitutions), where Vars is a list of variable names. E.g. binding(['A','B'],42,[])` means that both the variable A and B have the value 42. Values may contain terms '$VAR'(Name) to indicate sharing with a given variable. Value is always an acyclic term. If cycles appear in the answer, Substitutions contains a list of substitutions that restore the original term.
Residuals- is a pair of two lists representing residual goals. The first element of the pair are residuals related to the query variables and the second are related that are disconnected from the query.
 1886:- public
 1887    prolog:translate_bindings/5. 1888:- meta_predicate
 1889    prolog:translate_bindings(+, -, +, +, :). 1890
 1891prolog:translate_bindings(Bindings0, Bindings, ResVars, ResGoals, Residuals) :-
 1892    translate_bindings(Bindings0, Bindings, ResVars, ResGoals, Residuals),
 1893    name_vars(Bindings0, Bindings, t(ResVars, ResGoals, Residuals)).
 1894
 1895% should not be required.
 1896prolog:name_vars(Bindings, Term) :- name_vars([], Bindings, Term).
 1897prolog:name_vars(Bindings0, Bindings, Term) :- name_vars(Bindings0, Bindings, Term).
 1898
 1899translate_bindings(Bindings0, Bindings, ResidueVars, Residuals) :-
 1900    prolog:residual_goals(ResidueGoals, []),
 1901    translate_bindings(Bindings0, Bindings, ResidueVars, ResidueGoals,
 1902                       Residuals).
 1903
 1904translate_bindings(Bindings0, Bindings, [], [], _:[]-[]) :-
 1905    term_attvars(Bindings0, []),
 1906    !,
 1907    join_same_bindings(Bindings0, Bindings1),
 1908    factorize_bindings(Bindings1, Bindings2),
 1909    bind_vars(Bindings2, Bindings3),
 1910    filter_bindings(Bindings3, Bindings).
 1911translate_bindings(Bindings0, Bindings, ResidueVars, ResGoals0,
 1912                   TypeIn:Residuals-HiddenResiduals) :-
 1913    project_constraints(Bindings0, ResidueVars),
 1914    hidden_residuals(ResidueVars, Bindings0, HiddenResiduals0),
 1915    omit_qualifiers(HiddenResiduals0, TypeIn, HiddenResiduals),
 1916    copy_term(Bindings0+ResGoals0, Bindings1+ResGoals1, Residuals0),
 1917    '$append'(ResGoals1, Residuals0, Residuals1),
 1918    omit_qualifiers(Residuals1, TypeIn, Residuals),
 1919    join_same_bindings(Bindings1, Bindings2),
 1920    factorize_bindings(Bindings2, Bindings3),
 1921    bind_vars(Bindings3, Bindings4),
 1922    filter_bindings(Bindings4, Bindings).
 1923
 1924hidden_residuals(ResidueVars, Bindings, Goal) :-
 1925    term_attvars(ResidueVars, Remaining),
 1926    term_attvars(Bindings, QueryVars),
 1927    subtract_vars(Remaining, QueryVars, HiddenVars),
 1928    copy_term(HiddenVars, _, Goal).
 1929
 1930subtract_vars(All, Subtract, Remaining) :-
 1931    sort(All, AllSorted),
 1932    sort(Subtract, SubtractSorted),
 1933    ord_subtract(AllSorted, SubtractSorted, Remaining).
 1934
 1935ord_subtract([], _Not, []).
 1936ord_subtract([H1|T1], L2, Diff) :-
 1937    diff21(L2, H1, T1, Diff).
 1938
 1939diff21([], H1, T1, [H1|T1]).
 1940diff21([H2|T2], H1, T1, Diff) :-
 1941    compare(Order, H1, H2),
 1942    diff3(Order, H1, T1, H2, T2, Diff).
 1943
 1944diff12([], _H2, _T2, []).
 1945diff12([H1|T1], H2, T2, Diff) :-
 1946    compare(Order, H1, H2),
 1947    diff3(Order, H1, T1, H2, T2, Diff).
 1948
 1949diff3(<,  H1, T1,  H2, T2, [H1|Diff]) :-
 1950    diff12(T1, H2, T2, Diff).
 1951diff3(=, _H1, T1, _H2, T2, Diff) :-
 1952    ord_subtract(T1, T2, Diff).
 1953diff3(>,  H1, T1, _H2, T2, Diff) :-
 1954    diff21(T2, H1, T1, Diff).
 project_constraints(+Bindings, +ResidueVars) is det
Call <module>:project_attributes/2 if the Prolog flag toplevel_residue_vars is set to project.
 1962project_constraints(Bindings, ResidueVars) :-
 1963    !,
 1964    term_attvars(Bindings, AttVars),
 1965    phrase(attribute_modules(AttVars), Modules0),
 1966    sort(Modules0, Modules),
 1967    term_variables(Bindings, QueryVars),
 1968    project_attributes(Modules, QueryVars, ResidueVars).
 1969project_constraints(_, _).
 1970
 1971project_attributes([], _, _).
 1972project_attributes([M|T], QueryVars, ResidueVars) :-
 1973    (   current_predicate(M:project_attributes/2),
 1974        catch(M:project_attributes(QueryVars, ResidueVars), E,
 1975              print_message(error, E))
 1976    ->  true
 1977    ;   true
 1978    ),
 1979    project_attributes(T, QueryVars, ResidueVars).
 1980
 1981attribute_modules([]) --> [].
 1982attribute_modules([H|T]) -->
 1983    { get_attrs(H, Attrs) },
 1984    attrs_modules(Attrs),
 1985    attribute_modules(T).
 1986
 1987attrs_modules([]) --> [].
 1988attrs_modules(att(Module, _, More)) -->
 1989    [Module],
 1990    attrs_modules(More).
 join_same_bindings(Bindings0, Bindings)
Join variables that are bound to the same value. Note that we return the last value. This is because the factorization may be different and ultimately the names will be printed as V1 = V2, ... VN = Value. Using the last, Value has the factorization of VN.
 2001join_same_bindings([], []).
 2002join_same_bindings([Name=V0|T0], [[Name|Names]=V|T]) :-
 2003    take_same_bindings(T0, V0, V, Names, T1),
 2004    join_same_bindings(T1, T).
 2005
 2006take_same_bindings([], Val, Val, [], []).
 2007take_same_bindings([Name=V1|T0], V0, V, [Name|Names], T) :-
 2008    V0 == V1,
 2009    !,
 2010    take_same_bindings(T0, V1, V, Names, T).
 2011take_same_bindings([Pair|T0], V0, V, Names, [Pair|T]) :-
 2012    take_same_bindings(T0, V0, V, Names, T).
 omit_qualifiers(+QGoals, +TypeIn, -Goals) is det
Omit unneeded module qualifiers from QGoals relative to the given module TypeIn.
 2021omit_qualifiers([], _, []).
 2022omit_qualifiers([Goal0|Goals0], TypeIn, [Goal|Goals]) :-
 2023    omit_qualifier(Goal0, TypeIn, Goal),
 2024    omit_qualifiers(Goals0, TypeIn, Goals).
 2025
 2026omit_qualifier(M:G0, TypeIn, G) :-
 2027    M == TypeIn,
 2028    !,
 2029    omit_meta_qualifiers(G0, TypeIn, G).
 2030omit_qualifier(M:G0, TypeIn, G) :-
 2031    predicate_property(TypeIn:G0, imported_from(M)),
 2032    \+ predicate_property(G0, transparent),
 2033    !,
 2034    G0 = G.
 2035omit_qualifier(_:G0, _, G) :-
 2036    predicate_property(G0, built_in),
 2037    \+ predicate_property(G0, transparent),
 2038    !,
 2039    G0 = G.
 2040omit_qualifier(M:G0, _, M:G) :-
 2041    atom(M),
 2042    !,
 2043    omit_meta_qualifiers(G0, M, G).
 2044omit_qualifier(G0, TypeIn, G) :-
 2045    omit_meta_qualifiers(G0, TypeIn, G).
 2046
 2047omit_meta_qualifiers(V, _, V) :-
 2048    var(V),
 2049    !.
 2050omit_meta_qualifiers((QA,QB), TypeIn, (A,B)) :-
 2051    !,
 2052    omit_qualifier(QA, TypeIn, A),
 2053    omit_qualifier(QB, TypeIn, B).
 2054omit_meta_qualifiers(tnot(QA), TypeIn, tnot(A)) :-
 2055    !,
 2056    omit_qualifier(QA, TypeIn, A).
 2057omit_meta_qualifiers(freeze(V, QGoal), TypeIn, freeze(V, Goal)) :-
 2058    callable(QGoal),
 2059    !,
 2060    omit_qualifier(QGoal, TypeIn, Goal).
 2061omit_meta_qualifiers(when(Cond, QGoal), TypeIn, when(Cond, Goal)) :-
 2062    callable(QGoal),
 2063    !,
 2064    omit_qualifier(QGoal, TypeIn, Goal).
 2065omit_meta_qualifiers(G, _, G).
 bind_vars(+BindingsIn, -Bindings)
Bind variables to '$VAR'(Name), so they are printed by the names used in the query. Note that by binding in the reverse order, variables bound to one another come out in the natural order.
 2074bind_vars(Bindings0, Bindings) :-
 2075    bind_query_vars(Bindings0, Bindings, SNames),
 2076    bind_skel_vars(Bindings, Bindings, SNames, 1, _).
 2077
 2078bind_query_vars([], [], []).
 2079bind_query_vars([binding(Names,Var,[Var2=Cycle])|T0],
 2080                [binding(Names,Cycle,[])|T], [Name|SNames]) :-
 2081    Var == Var2,                   % also implies var(Var)
 2082    !,
 2083    '$last'(Names, Name),
 2084    Var = '$VAR'(Name),
 2085    bind_query_vars(T0, T, SNames).
 2086bind_query_vars([B|T0], [B|T], AllNames) :-
 2087    B = binding(Names,Var,Skel),
 2088    bind_query_vars(T0, T, SNames),
 2089    (   var(Var), \+ attvar(Var), Skel == []
 2090    ->  AllNames = [Name|SNames],
 2091        '$last'(Names, Name),
 2092        Var = '$VAR'(Name)
 2093    ;   AllNames = SNames
 2094    ).
 2095
 2096
 2097
 2098bind_skel_vars([], _, _, N, N).
 2099bind_skel_vars([binding(_,_,Skel)|T], Bindings, SNames, N0, N) :-
 2100    bind_one_skel_vars(Skel, Bindings, SNames, N0, N1),
 2101    bind_skel_vars(T, Bindings, SNames, N1, N).
 bind_one_skel_vars(+Subst, +Bindings, +VarName, +N0, -N)
Give names to the factorized variables that do not have a name yet. This introduces names _S<N>, avoiding duplicates. If a factorized variable shares with another binding, use the name of that variable.
To be done
- Consider the call below. We could remove either of the A = x(1). Which is best?
?- A = x(1), B = a(A,A).
A = x(1),
B = a(A, A), % where
    A = x(1).
 2120bind_one_skel_vars([], _, _, N, N).
 2121bind_one_skel_vars([Var=Value|T], Bindings, Names, N0, N) :-
 2122    (   var(Var)
 2123    ->  (   '$member'(binding(Names, VVal, []), Bindings),
 2124            same_term(Value, VVal)
 2125        ->  '$last'(Names, VName),
 2126            Var = '$VAR'(VName),
 2127            N2 = N0
 2128        ;   between(N0, infinite, N1),
 2129            atom_concat('_S', N1, Name),
 2130            \+ memberchk(Name, Names),
 2131            !,
 2132            Var = '$VAR'(Name),
 2133            N2 is N1 + 1
 2134        )
 2135    ;   N2 = N0
 2136    ),
 2137    bind_one_skel_vars(T, Bindings, Names, N2, N).
 factorize_bindings(+Bindings0, -Factorized)
Factorize cycles and sharing in the bindings.
 2144factorize_bindings([], []).
 2145factorize_bindings([Name=Value|T0], [binding(Name, Skel, Subst)|T]) :-
 2146    '$factorize_term'(Value, Skel, Subst0),
 2147    (   current_prolog_flag(toplevel_print_factorized, true)
 2148    ->  Subst = Subst0
 2149    ;   only_cycles(Subst0, Subst)
 2150    ),
 2151    factorize_bindings(T0, T).
 2152
 2153
 2154only_cycles([], []).
 2155only_cycles([B|T0], List) :-
 2156    (   B = (Var=Value),
 2157        Var = Value,
 2158        acyclic_term(Var)
 2159    ->  only_cycles(T0, List)
 2160    ;   List = [B|T],
 2161        only_cycles(T0, T)
 2162    ).
 filter_bindings(+Bindings0, -Bindings)
Remove bindings that must not be printed. There are two of them: Variables whose name start with '_' and variables that are only bound to themselves (or, unbound).
 2171filter_bindings([], []).
 2172filter_bindings([H0|T0], T) :-
 2173    hide_vars(H0, H),
 2174    (   (   arg(1, H, [])
 2175        ;   self_bounded(H)
 2176        )
 2177    ->  filter_bindings(T0, T)
 2178    ;   T = [H|T1],
 2179        filter_bindings(T0, T1)
 2180    ).
 2181
 2182hide_vars(binding(Names0, Skel, Subst), binding(Names, Skel, Subst)) :-
 2183    hide_names(Names0, Skel, Subst, Names).
 2184
 2185hide_names([], _, _, []).
 2186hide_names([Name|T0], Skel, Subst, T) :-
 2187    (   anon_var_name(Name),
 2188        current_prolog_flag(toplevel_print_anon, false)
 2189    ->  true
 2190    ;   Subst == [],
 2191        Skel == '$VAR'(Name)
 2192    ),
 2193    !,
 2194    hide_names(T0, Skel, Subst, T).
 2195hide_names([Name|T0], Skel, Subst, [Name|T]) :-
 2196    hide_names(T0, Skel, Subst, T).
 2197
 2198%   anon_var_name(+Name) is semidet.
 2199%
 2200%   True if Name is `_X`, or `?_X` if the flag `var_prefix` is `?`.
 2201
 2202anon_var_name(Name) :-
 2203    (   sub_atom(Name, 0, 1, _, '_')
 2204    ->  S = 1
 2205    ;   sub_atom(Name, 0, 1, _, P),
 2206        char_type(P, prolog_symbol),
 2207        sub_atom(Name, 1, 1, _, '_')
 2208    ->  S = 2
 2209    ),
 2210    sub_atom(Name, S, 1, _, Next),
 2211    char_type(Next, prolog_var_start).
 2212
 2213self_bounded(binding([Name], Value, [])) :-
 2214    Value == '$VAR'(Name).
 get_respons(-Action, +Chp)
Read the continuation entered by the user.
 2220:- if(current_prolog_flag(emscripten, true)). 2221get_respons(Action, Chp) :-
 2222    '$can_yield',
 2223    !,
 2224    repeat,
 2225        await(more, CommandS),
 2226        atom_string(Command, CommandS),
 2227        more_action(Command, Chp, Action),
 2228        (   Action == again
 2229        ->  print_message(query, query(action)),
 2230            fail
 2231        ;   !
 2232        ).
 2233:- endif. 2234get_respons(Action, Chp) :-
 2235    repeat,
 2236        flush_output(user_output),
 2237        get_single_char(Code),
 2238        find_more_command(Code, Command, Feedback, Style),
 2239        (   Style \== '-'
 2240        ->  print_message(query, if_tty([ansi(Style, '~w', [Feedback])]))
 2241        ;   true
 2242        ),
 2243        more_action(Command, Chp, Action),
 2244        (   Action == again
 2245        ->  print_message(query, query(action)),
 2246            fail
 2247        ;   !
 2248        ).
 2249
 2250find_more_command(-1, end_of_file, 'EOF', warning) :-
 2251    !.
 2252find_more_command(Code, Command, Feedback, Style) :-
 2253    more_command(Command, Atom, Feedback, Style),
 2254    '$in_reply'(Code, Atom),
 2255    !.
 2256find_more_command(Code, again, '', -) :-
 2257    print_message(query, no_action(Code)).
 2258
 2259more_command(help,        '?h',        '',          -).
 2260more_command(redo,        ';nrNR \t',  ';',         bold).
 2261more_command(trace,       'tT',        '; [trace]', comment).
 2262more_command(continue,    'ca\n\ryY.', '.',         bold).
 2263more_command(break,       'b',         '',          -).
 2264more_command(choicepoint, '*',         '',          -).
 2265more_command(write,       'w',         '[write]',   comment).
 2266more_command(print,       'p',         '[print]',   comment).
 2267more_command(depth_inc,   '+',         Change,      comment) :-
 2268    (   print_depth(Depth0)
 2269    ->  depth_step(Step),
 2270        NewDepth is Depth0*Step,
 2271        format(atom(Change), '[max_depth(~D)]', [NewDepth])
 2272    ;   Change = 'no max_depth'
 2273    ).
 2274more_command(depth_dec,   '-',         Change,      comment) :-
 2275    (   print_depth(Depth0)
 2276    ->  depth_step(Step),
 2277        NewDepth is max(1, Depth0//Step),
 2278        format(atom(Change), '[max_depth(~D)]', [NewDepth])
 2279    ;   Change = '[max_depth(10)]'
 2280    ).
 2281
 2282more_action(help, _, Action) =>
 2283    Action = again,
 2284    print_message(help, query(help)).
 2285more_action(redo, _, Action) =>			% Next
 2286    Action = redo.
 2287more_action(trace, _, Action) =>
 2288    Action = redo,
 2289    trace,
 2290    save_debug.
 2291more_action(continue, _, Action) =>             % Stop
 2292    Action = continue.
 2293more_action(break, _, Action) =>
 2294    Action = show_again,
 2295    break.
 2296more_action(choicepoint, Chp, Action) =>
 2297    Action = show_again,
 2298    print_last_chpoint(Chp).
 2299more_action(end_of_file, _, Action) =>
 2300    Action = show_again,
 2301    halt(0).
 2302more_action(again, _, Action) =>
 2303    Action = again.
 2304more_action(Command, _, Action),
 2305    current_prolog_flag(answer_write_options, Options0),
 2306    print_predicate(Command, Options0, Options) =>
 2307    Action = show_again,
 2308    set_prolog_flag(answer_write_options, Options).
 2309
 2310print_depth(Depth) :-
 2311    current_prolog_flag(answer_write_options, Options),
 2312    '$option'(max_depth(Depth), Options),
 2313    !.
 print_predicate(+Action, +Options0, -Options) is semidet
Modify the answer_write_options value according to the user command.
 2320print_predicate(write, Options0, Options) :-
 2321    edit_options([-portrayed(true),-portray(true)],
 2322                 Options0, Options).
 2323print_predicate(print, Options0, Options) :-
 2324    edit_options([+portrayed(true)],
 2325                 Options0, Options).
 2326print_predicate(depth_inc, Options0, Options) :-
 2327    (   '$select'(max_depth(D0), Options0, Options1)
 2328    ->  depth_step(Step),
 2329        D is D0*Step,
 2330        Options = [max_depth(D)|Options1]
 2331    ;   Options = Options0
 2332    ).
 2333print_predicate(depth_dec, Options0, Options) :-
 2334    (   '$select'(max_depth(D0), Options0, Options1)
 2335    ->  depth_step(Step),
 2336        D is max(1, D0//Step),
 2337        Options = [max_depth(D)|Options1]
 2338    ;   D = 10,
 2339        Options = [max_depth(D)|Options0]
 2340    ).
 2341
 2342depth_step(5).
 2343
 2344edit_options([], Options, Options).
 2345edit_options([H|T], Options0, Options) :-
 2346    edit_option(H, Options0, Options1),
 2347    edit_options(T, Options1, Options).
 2348
 2349edit_option(-Term, Options0, Options) =>
 2350    (   '$select'(Term, Options0, Options)
 2351    ->  true
 2352    ;   Options = Options0
 2353    ).
 2354edit_option(+Term, Options0, Options) =>
 2355    functor(Term, Name, 1),
 2356    functor(Var, Name, 1),
 2357    (   '$select'(Var, Options0, Options1)
 2358    ->  Options = [Term|Options1]
 2359    ;   Options = [Term|Options0]
 2360    ).
 print_last_chpoint(+Chp) is det
Print the last choicepoint when an answer is nondeterministic.
 2366print_last_chpoint(Chp) :-
 2367    current_predicate(print_last_choice_point/0),
 2368    !,
 2369    print_last_chpoint_(Chp).
 2370print_last_chpoint(Chp) :-
 2371    use_module(library(prolog_stack), [print_last_choicepoint/2]),
 2372    print_last_chpoint_(Chp).
 2373
 2374print_last_chpoint_(Chp) :-
 2375    print_last_choicepoint(Chp, [message_level(information)]).
 2376
 2377
 2378                 /*******************************
 2379                 *          EXPANSION           *
 2380                 *******************************/
 2381
 2382:- user:dynamic(expand_query/4). 2383:- user:multifile(expand_query/4). 2384
 2385call_expand_query(Goal, Expanded, Bindings, ExpandedBindings) :-
 2386    (   '$replace_toplevel_vars'(Goal, Expanded0, Bindings, ExpandedBindings0)
 2387    ->  true
 2388    ;   Expanded0 = Goal, ExpandedBindings0 = Bindings
 2389    ),
 2390    (   user:expand_query(Expanded0, Expanded, ExpandedBindings0, ExpandedBindings)
 2391    ->  true
 2392    ;   Expanded = Expanded0, ExpandedBindings = ExpandedBindings0
 2393    ).
 2394
 2395
 2396:- dynamic
 2397    user:expand_answer/2,
 2398    prolog:expand_answer/3. 2399:- multifile
 2400    user:expand_answer/2,
 2401    prolog:expand_answer/3. 2402
 2403call_expand_answer(Goal, BindingsIn, BindingsOut) :-
 2404    (   prolog:expand_answer(Goal, BindingsIn, BindingsOut)
 2405    ->  true
 2406    ;   user:expand_answer(BindingsIn, BindingsOut)
 2407    ->  true
 2408    ;   BindingsOut = BindingsIn
 2409    ),
 2410    '$save_toplevel_vars'(BindingsOut),
 2411    !.
 2412call_expand_answer(_, Bindings, Bindings)