1/*  Part of Refactoring Tools for SWI-Prolog
    2
    3    Author:        Edison Mera
    4    E-mail:        efmera@gmail.com
    5    WWW:           https://github.com/edisonm/refactor
    6    Copyright (C): 2013, Process Design Center, Breda, The Netherlands.
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(ref_replace,
   36          [replace/5,
   37           op(100,xfy,($@)),
   38           op(100,xfy,(@@))
   39          ]).

Basic Term Expansion operations

This library provides the predicate replace/5, which is the basic entry point for all the refactoring scenarios.

Note for implementors/hackers:

*/

   59:- use_module(library(apply)).   60:- use_module(library(codesio)).   61:- use_module(library(lists)).   62:- use_module(library(occurs)).   63:- use_module(library(option)).   64:- use_module(library(pairs)).   65:- use_module(library(settings)).   66:- use_module(library(atomics_string)).   67:- use_module(library(solution_sequences)).   68:- use_module(library(neck)).   69:- use_module(library(term_size)).   70:- use_module(library(prolog_source), []). % expand/4
   71:- use_module(library(readutil)).   72:- use_module(library(fix_termpos)).   73:- use_module(library(mapnargs)).   74:- use_module(library(ref_changes)).   75:- use_module(library(ref_context)).   76:- use_module(library(ref_msgtype)).   77:- use_module(library(ref_message)).   78:- use_module(library(seek_text)).   79:- use_module(library(term_info)).   80:- use_module(library(sequence_list)).   81:- use_module(library(clambda)).   82:- use_module(library(mapilist)).   83:- use_module(library(linearize)).   84:- use_module(library(substitute)).   85:- use_module(library(subpos_utils)).   86:- use_module(library(transpose)).   87:- use_module(library(option_utils)).   88:- use_module(library(countsols)).   89:- use_module(library(conc_forall)).   90
   91:- init_expansors.   92
   93:- thread_local
   94    command_db/1.   95
   96:- multifile
   97    prolog:xref_open_source/2.  % +SourceId, -Stream
   98
   99:- thread_local
  100    rportray_pos/2,
  101    ref_position/3,
  102    rportray_skip/0.  103
  104:- meta_predicate
  105    apply_commands(?, +, +, ?, +, +, +, +, 5),
  106    fixpoint_file(+, +, 0 ),
  107    reindent(+, +, 0 ),
  108    replace(+, ?, ?, 0, :),
  109    rportray_list(+, +, 2, +, +),
  110    with_context(?, ?, ?, ?, -, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?),
  111    with_cond_braces_2(4, ?, ?, ?, ?, ?, ?),
  112    with_counters(0, +),
  113    with_styles(0, +),
  114    with_output_to_string(-, 0 ),
  115    with_output_to_string(-, 0, 0 ),
  116    with_output_to_string(-, -, -, 0, 0 ).
 replace(+Level, +Pattern, +Into, :Expander, :Options) is det
Given a Level of operation, in all terms of the source code that subsumes Pattern, replace each Pattern with Into, provided that Expander succeeds. Expander can be used to finalize the shape of Into as well as to veto the expansion (if fails). The Options argument is used to control the behavior and scope of the replacement.

The predicate is efficient enough to be used also as a walker to capture all matches of Term, by printing a message and failing. For example:

replace(
    sent,
    (:-use_module(X)), _,
    (refactor_message(information, format("~w", [X])), fail),
    [file(F)])

will display all the occurrences of use_module/1 declarations in the file F. This would be useful for some complex refactoring scenarios.

The levels of operations stablishes where to look for matching terms, and could take one of the following values:

  412replace(Level, Patt, Into, Expander, MOptions) :-
  414    meta_options(replace_meta_option, MOptions, Options),
  415    with_styles(with_counters(do_replace(Level, Patt, Into, Expander, Options),
  416                              Options), [-singleton])
  416.
  417
  418replace_meta_option(decrease_metric).
  419
  420curr_style(Style, CurrStyle) :-
  421    arg(1, Style, Name),
  422    ( style_check(?(Name))
  423    ->CurrStyle = +Name
  424    ; CurrStyle = -Name
  425    ).
  426
  427with_styles(Goal, StyleL) :-
  428    maplist(curr_style, StyleL, OldStyleL),
  429    setup_call_cleanup(maplist(style_check, StyleL),
  430                       Goal,
  431                       maplist(style_check, OldStyleL)).
  432
  433% Note: To avoid this hook be applied more than once, we record the positions
  434% already refactorized in ref_position/3.
  435
  436remove_attribute(Attr, Var) :-
  437    del_attr(Var, Attr).
  438
  439:- public do_goal_expansion/2.  440
  441do_goal_expansion(Term, TermPos) :-
  442    compound(TermPos),
  443    arg(1, TermPos, From),
  444    arg(2, TermPos, To),
  445    nonvar(From),
  446    nonvar(To),
  447    refactor_context(file, File),
  448    \+ ref_position(File, From, To),
  449    assertz(ref_position(File, From, To)),
  450    term_variables(Term, Vars),
  451    ( refactor_context(cleanup_attributes, yes)
  452    ->maplist(remove_attribute('$var_info'), Vars)
  453    ; true
  454    ),
  455    refactor_context(goal_args, ga(Pattern, Into, Expander)),
  456    '$current_source_module'(M),
  457    b_getval('$variable_names', VNL),
  458    with_varnames(
  459        forall(substitute_term_norec(sub, M, Term, TermPos, 999, data(Pattern, Into, Expander, TermPos), Command),
  460               assertz(command_db(Command))),
  461        VNL).
  462
  463do_replace(Level, Patt, Into, Expander, Options) :-
  464    setup_call_cleanup(
  465        prepare_level(Level, Ref),
  466        apply_ec_term_level(Level, Patt, Into, Expander, Options),
  467        cleanup_level(Level, Ref)).
  468
  469prepare_level(goal, Ref) :-
  470    !,
  471    asserta((system:goal_expansion(G, P, _, _) :-
  472                 once(do_goal_expansion(G, P)),fail), Ref).
  473prepare_level(_, _).
  474
  475cleanup_level(goal, Ref) :- !,
  476    erase(Ref),
  477    retractall(ref_position(_, _, _)).
  478cleanup_level(_, _).
  479
  480with_counters(Goal, Options1) :-
  481    foldl(select_option_default,
  482          [max_tries(MaxTries)-MaxTries],
  483          Options1, Options),
  484    with_refactor_context(
  485        ( Goal,
  486          refactor_context(count, Count),
  487          refactor_context(tries, Tries),
  488          foldl(select_option_default,
  489                [changes(Count)-Count,
  490                 tries(Tries)  -Tries],
  491                Options, _),
  492          message_type(Type),
  493          print_message(Type,
  494                        format("~w changes of ~w attempts", [Count, Tries]))
  495        ),
  496        [max_tries],
  497        [MaxTries]
  498    ).
  499
  500param_module_file(clause(CRef), M, File) :-
  501    clause_property(CRef, file(File)),
  502    clause_property(CRef, module(M)).
  503param_module_file(mfiled(MFileD), M, File) :-
  504    get_dict(M1, MFileD, FileD),
  505    ( M1 = (-)
  506    ->true
  507    ; M = M1
  508    ),
  509    get_dict(File, FileD, _).
  510
  511apply_ec_term_level(Level, Patt, Into, Expander, Options1) :-
  512    (Level = goal -> DExpand=yes ; DExpand = no),
  513    (Level = sent -> SentPattern = Patt ; true), % speed up
  514    option(module(M), Options1, M),
  515    foldl(select_option_default,
  516          [max_tries(MaxTries)-MaxTries,
  517           syntax_errors(SE)-error,
  518           subterm_positions(SentPos)-SentPos,
  519           term_position(Pos)-Pos,
  520           conj_width(ConjWidth)-160, % In (_,_), try to wrap lines
  521           term_width(TermWidth)-160, % In terms, try to wrap lines
  522           list_width(ListWidth)-160, % In lists, try to wrap lines
  523           linearize(Linearize)-[],
  524           sentence(SentPattern)-SentPattern,
  525           comments(Comments)-Comments,
  526           expand(Expand)-DExpand,
  527           expanded(Expanded)-Expanded,
  528           cleanup_attributes(CleanupAttributes)-yes,
  529           fixpoint(FixPoint)-decreasing,
  530           max_changes(Max)-Max,
  531           variable_names(VNL)-VNL,
  532           vars_prefix(Prefix)-'V',
  533           file(AFile)-AFile,
  534            % By default refactor even non loaded files
  535           loaded(Loaded)-false
  536          ],
  537          Options1, Options2),
  538    ( option(clause(CRef), Options2)
  539    ->MFileParam = clause(CRef),
  540      clause_property(CRef, line_count(Line)),
  541      merge_options([line(Line)], Options2, Options3)
  542    ; option_module_files([loaded(Loaded), file(AFile)|Options2], MFileD),
  543      MFileParam = mfiled(MFileD),
  544      Options3 = Options2
  545    ),
  546    Options = [syntax_errors(SE),
  547               subterm_positions(SentPos),
  548               term_position(Pos),
  549               variable_names(VNL),
  550               conj_width(ConjWidth),
  551               term_width(TermWidth),
  552               list_width(ListWidth),
  553               comments(Comments)|Options3],
  554    ignore(( var(AFile),
  555             File = AFile
  556           )),
  557    setup_call_cleanup(
  558        ( '$current_source_module'(OldM)
  559          % freeze(M, '$set_source_module'(_, M))
  560        ),
  561        process_sentences(
  562            MFileParam, FixPoint, Max, SentPattern, Options, CleanupAttributes, M, File, Expanded, Expand, Pos,
  563            ga(Patt, Into, Expander), Linearize, MaxTries, Prefix, Level, data(Patt, Into, Expander, SentPos)),
  564        '$set_source_module'(_, OldM)).
  565
  566param_module_file_sorted(MFileParam, M, File) :-
  567    order_by([desc(Size)],
  568             ( param_module_file(MFileParam, M, File),
  569               ignore(catch(size_file(File, Size), _, Size = 0 ))
  570             )).
  571
  572process_sentences(
  573    MFileParam, FixPoint, Max, SentPattern, Options, CleanupAttributes, M, File, Expanded, Expand,
  574    Pos, GoalArgs, Linearize, MaxTries, Prefix, Level, Data) :-
  575    index_change(Index),
  576    ini_counter(0, STries),
  577    ini_counter(0, SCount),
  578    option(concurrent(Conc), Options, true),
  579    cond_forall(
  580        Conc,
  581        param_module_file_sorted(MFileParam, M, File),
  582        process_sentence_file(
  583            Index, FixPoint, Max, SentPattern, Options, CleanupAttributes,
  584            M, File, Expanded, Expand, Pos, GoalArgs, Linearize, MaxTries,
  585            Prefix, Level, Data, Tries, Count),
  586        ( inc_counter(STries, Tries, _),
  587          inc_counter(SCount, Count, _)
  588        )),
  589    STries = count(Tries),
  590    SCount = count(Count),
  591    set_refactor_context(tries, Tries),
  592    set_refactor_context(count, Count).
  593
  594fixpoint_file(none, _, Goal) :- ignore(Goal).
  595fixpoint_file(true, Max, Goal) :-
  596    repeat,
  597      set_refactor_context(modified, false),
  598      ignore(Goal),
  599      refactor_context(count, Count),
  600      ( nonvar(Max),
  601        Count >= Max
  602      ->!
  603      ; true
  604      ),
  605      ( refactor_context(modified, false)
  606      ->!
  607      ; print_message(informational,
  608                      format("Restarting expansion", [])),
  609        fail
  610      ).
  611
  612rec_fixpoint_file(rec,   P, F) :- rec_ff(P, F).
  613rec_fixpoint_file(norec, P, F) :- norec_ff(P, F).
  614
  615rec_ff(decreasing, none).
  616rec_ff(file,       true).
  617rec_ff(term,       none).
  618rec_ff(true,       none).
  619rec_ff(none,       none).
  620
  621norec_ff(decreasing, none).
  622norec_ff(file,       true).
  623norec_ff(term,       none).
  624norec_ff(true,       true).
  625norec_ff(none,       none).
  626
  627process_sentence_file(Index, FixPoint, Max, SentPattern, Options, CleanupAttributes,
  628                      M, File, Expanded, Expand, Pos, GoalArgs,
  629                      Linearize, MaxTries, Prefix, Level, Data, Tries, Count) :-
  630    maplist(set_refactor_context,
  631            [bindings, cleanup_attributes, comments, expanded, file, goal_args, modified,
  632             tries, count, max_tries, options, pos, prefix, sent_pattern, sentence, subpos],
  633            [Bindings, CleanupAttributes,  Comments, Expanded, File, GoalArgs,  false,
  634             0,     0,     MaxTries,  Options, Pos, Prefix, SentPattern,  Sent,     SentPos]),
  635    \+ \+ ( option(comments(Comments),  Options, Comments),
  636            option(subterm_positions(SentPos), Options, SentPos),
  637            option(variable_names(VNL), Options, VNL),
  638            option(term_position(Pos), Options, Pos),
  639            level_rec(Level, Rec),
  640            rec_fixpoint_file(Rec, FixPoint, FPFile),
  641            fixpoint_file(FPFile, Max,
  642                          apply_commands(
  643                              Index, File, Level, M, Rec, FixPoint, Max, Pos,
  644                              gen_module_command(
  645                                  SentPattern, Options, Expand, SentPos, Expanded,
  646                                  Linearize, Sent, VNL, Bindings, Data)))
  647          ),
  648    refactor_context(tries, Tries),
  649    refactor_context(count, Count).
  650
  651binding_varname(VNL, Var=Term) -->
  652    ( { atomic(Term),
  653        Term \= [],
  654        atomic_concat('_Atm_', Term, Name)
  655      ; member(Name=Var1, VNL),
  656        Var1==Term
  657      }
  658    ->[Name=Var]
  659    ; []
  660    ).
  661
  662gen_module_command(SentPattern, Options, Expand, SentPos, Expanded, Linearize,
  663                   Sent, VNL, Bindings, Data, Level, M, In, Text, Command) :-
  664    ref_fetch_term_info(SentPattern, RawSent, In, Options, Once),
  665    b_setval('$variable_names', VNL),
  666    set_refactor_context(text, Text),
  667    expand_if_required(Expand, M, RawSent, SentPos, In, Expanded),
  668    make_linear_if_required(RawSent, Linearize, Sent, Bindings),
  669    foldl(binding_varname(VNL), Bindings, RVNL, VNL),
  670    S = solved(no),
  671    ( true
  672    ; arg(1, S, yes)
  673    ->cond_cut_once(Once),
  674      fail
  675    ),
  676    set_refactor_context(variable_names, RVNL),
  677    substitute_term_level(Level, M, Sent, SentPos, 1200, Data, Command),
  678    nb_setarg(1, S, yes).
  679
  680cond_cut_once(once).
  681cond_cut_once(mult(CP)) :- prolog_cut_to(CP).
  682
  683ref_fetch_term_info(SentPattern, Sent, In, Options, once) :-
  684    nonvar(SentPattern),
  685    memberchk(SentPattern, [[], end_of_file]),
  686    !,
  687    ref_term_info_file(SentPattern, Sent, In, Options).
  688ref_fetch_term_info(SentPattern, Sent, In, Options, mult(CP)) :-
  689    repeat,
  690      prolog_current_choice(CP),
  691      ( fetch_term_info(SentPattern, Sent, Options, In)
  692      ; !,
  693        fail
  694      ).
  695
  696ref_term_info_file(end_of_file, end_of_file, In, Options) :-
  697    seek(In, 0, eof, Size),
  698    ref_term_null_option(Size, In, Options).
  699ref_term_info_file([], [], In, Options) :-
  700    seek(In, 0, bof, 0),
  701    ref_term_null_option(0, In, Options).
  702
  703ref_term_null_option(Size, In, Options) :-
  704    option(comments([]), Options),
  705    option(subterm_positions(Size-Size), Options),
  706    stream_property(In, position(Pos)),
  707    option(term_position(Pos), Options),
  708    option(variable_names([]), Options).
  709
  710expand_if_required(Expand, M, Sent, SentPos, In, Expanded) :-
  711    ( Expand = no
  712    ->Expanded = Sent
  713    ; '$expand':expand_terms(prolog_source:expand, Sent, SentPos, In, Expanded)
  714    ),
  715    ignore(( '$set_source_module'(CM, CM),
  716             M = CM
  717           )),
  718    prolog_source:update_state(Sent, Expanded, M).
  719
  720make_linear_if_required(Sent, Linearize, Linear, Bindings) :-
  721    foldl(linearize, Linearize, Sent-Bindings, Linear-[]).
  722
  723linearize(Which, Sent-Bindings1, Linear-Bindings) :-
  724    linearize(Which, Sent, Linear, Bindings1, Bindings).
  725
  726prolog:xref_open_source(File, Fd) :-
  727    nb_current(ti_open_source, yes),
  728    !,
  729    ( pending_change(_, File, Text)
  730    ->true
  731    ; read_file_to_string(File, Text, [])
  732    ),
  733    open_codes_stream(Text, Fd).
  734    % set_refactor_context(text, Text). % NOTE: update_state/2 has the side effect of
  735                                     % modify refactor_text
  736
  737substitute_term_level(goal, _, _, _, _, _, Cmd) :-
  738    retract(command_db(Cmd)).
  739substitute_term_level(term, M, Sent, SentPos, Priority, Data, Cmd) :-
  740    substitute_term_rec(M, Sent, SentPos, Priority, Data, Cmd).
  741substitute_term_level(sent, M, Sent, SentPos, Priority, Data, Cmd) :-
  742    substitute_term_norec(top, M, Sent, SentPos, Priority, Data, Cmd).
  743substitute_term_level(head, M, Sent, SentPos, Priority, Data, Cmd) :-
  744    substitute_term_head(norec, M, Sent, SentPos, Priority, Data, Cmd).
  745substitute_term_level(head_rec, M, Sent, SentPos, Priority, Data, Cmd) :-
  746    substitute_term_head(rec, M, Sent, SentPos, Priority, Data, Cmd).
  747substitute_term_level(body, M, Sent, SentPos, _, Data, Cmd) :-
  748    substitute_term_body(norec, M, Sent, SentPos, Data, Cmd).
  749substitute_term_level(body_rec, M, Sent, SentPos, _, Data, Cmd) :-
  750    substitute_term_body(rec, M, Sent, SentPos, Data, Cmd).
  751
  752substitute_term_body(Rec, M, Sent, parentheses_term_position(_, _, TermPos), Data, Cmd) :-
  753    !,
  754    substitute_term_body(Rec, M, Sent, TermPos, Data, Cmd).
  755substitute_term_body(Rec, M, (_ :- Body), term_position(_, _, _, _, [_, BodyPos]), Data,
  756                     Cmd) :-
  757    term_priority((_ :- Body), M, 2, Priority),
  758    substitute_term(Rec, sub, M, Body, BodyPos, Priority, Data, Cmd).
  759substitute_term_body(Rec, M, (_ --> Body), term_position(_, _, _, _, [_, BodyPos]), Data,
  760                     Cmd) :-
  761    term_priority((_ --> Body), M, 2, Priority),
  762    substitute_term(Rec, sub, M, Body, BodyPos, Priority, Data, Cmd).
  763
  764substitute_term_head(Rec, M, Clause, parentheses_term_position(_, _, TermPos), Priority,
  765                     Data, Cmd) :-
  766    !,
  767    substitute_term_head(Rec, M, Clause, TermPos, Priority, Data, Cmd).
  768substitute_term_head(Rec, M, Clause, TermPos, Priority, Data, Cmd) :-
  769    ( ( Clause = (MHead :- _)
  770      ; Clause = (MHead --> _)
  771      )
  772    ->( nonvar(MHead),
  773        MHead = IM:Head
  774      ->term_priority(IM:Head, M, 2, HPriority),
  775        term_position(_, _, _, _, [MHPos, _]) = TermPos,
  776        mhead_pos(MHPos, HeadPos)
  777      ; Head = MHead,
  778        term_priority(Clause, M, 1, HPriority),
  779        term_position(_, _, _, _, [HeadPos, _]) = TermPos
  780      )
  781    ; Clause \= (:- _),
  782      Head = Clause,
  783      HPriority = Priority,
  784      HeadPos = TermPos
  785    ),
  786    substitute_term(Rec, sub, M, Head, HeadPos, HPriority, Data, Cmd).
  787
  788mhead_pos(parentheses_term_position(_, _, Pos), HPos) :- !, mhead_pos(Pos, HPos).
  789mhead_pos(term_position(_, _, _, _, [_, HPos]), HPos).
  790
  791substitute_term(rec, _, M, Term, TermPos, Priority, Data, Cmd) :-
  792    substitute_term_rec(M, Term, TermPos, Priority, Data, Cmd).
  793substitute_term(norec, Level, M, Term, TermPos, Priority, Data, Cmd) :-
  794    substitute_term_norec(Level, M, Term, TermPos, Priority, Data, Cmd).
  795
  796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  797% ANCILLARY PREDICATES:
  798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  799
  800level_rec(goal,     norec).
  801level_rec(term,     rec).
  802level_rec(sent,     norec).
  803level_rec(head,     norec).
  804level_rec(head_rec, rec).
  805level_rec(body,     norec).
  806level_rec(body_rec, rec).
  807
  808rec_fixpoint_term(norec, _, not).
  809rec_fixpoint_term(rec,   P, F) :- rec_ft(P, F).
  810
  811rec_ft(decreasing, dec).
  812rec_ft(file,       not).
  813rec_ft(term,       rec).
  814rec_ft(true,       rec).
  815rec_ft(none,       not).
  816rec_ft(false,      not).
  817
  818% This is weird due to the operators
  819apply_commands(Index, File, Level, M, Rec, FixPoint, Max, Pos, GenModuleCommand) :-
  820    ( pending_change(_, File, Text1)
  821    ->true
  822    ; exists_file(File)
  823    ->read_file_to_string(File, Text1, [])
  824    ; Text1 = ""
  825    ),
  826    rec_fixpoint_term(Rec, FixPoint, FPTerm),
  827    with_refactor_context(
  828        with_source_file(
  829            File, In,
  830            apply_commands_stream(
  831                FPTerm, GenModuleCommand, File, Level, M, nocs, Max, Pos, In, Text1, Text)),
  832        [file], [File]),
  833    ( Text1 \= Text
  834    ->nb_set_refactor_context(modified, true),
  835      save_change(Index, File-Text)
  836    ; true
  837    ).
  838
  839decreasing_recursion(nocs, _).
  840decreasing_recursion(subst(_, _, _, _, S1),
  841                     subst(_, _, _, _, S2)) :-
  842    freeze(S2, S1 > S2).
  843
  844do_recursion(dec(G), C, G, C).
  845do_recursion(rec(G), _, G, nocs).
  846
  847rec_command_info(not, _, not).
  848rec_command_info(rec, G, rec(C)) :- copy_term(G, C).
  849rec_command_info(dec, G, dec(C)) :- copy_term(G, C).
  850
  851increase_counter(Count1) :-
  852    refactor_context(count, Count),
  853    succ(Count, Count1),
  854    nb_set_refactor_context(count, Count1).
  855
  856fix_exception(error(Error, stream(_,  Line, Row, Pos)), File,
  857              error(Error, file(File, Line, Row, Pos))) :- !.
  858fix_exception(E, _, E).
  859
  860do_genmcmd(GenModuleCommand, File, Level, M, CS, Max, In, Text, Command) :-
  861    decreasing_recursion(CS, Command),
  862    catch(call(GenModuleCommand, Level, M, In, Text, Command),
  863          E1,
  864          ( fix_exception(E1, File, E),
  865            print_message(error, E),
  866            fail
  867          )),
  868    increase_counter(Count1),
  869    ( nonvar(Max),
  870      Count1 >= Max
  871    ->!
  872    ; true
  873    ).
  874
  875:- thread_local subtext_db/2.  876
  877apply_commands_stream(FPTerm, GenModuleCommand, File, Level, M, CS, Max, Pos, In, Text1, Text) :-
  878    retractall(subtext_db(_, _)),
  879    apply_commands_stream(1, FPTerm, GenModuleCommand, File, Level, M, CS, Max, Pos, In, Text1, Text).
  880
  881apply_commands_stream(RecNo, FPTerm, GenModuleCommand, File, Level, M, CS, Max, Pos, In, Text1, Text) :-
  882    IPosText = ipt(0 ),
  883    rec_command_info(FPTerm, GenModuleCommand, CI),
  884    ignore(
  885        forall(
  886            do_genmcmd(GenModuleCommand, File, Level, M, CS, Max, In, Text1, Command),
  887            apply_commands_stream_each(
  888                RecNo, FPTerm, File, CI, M, Max, Pos, Command, Text1, IPosText))),
  889    IPosText = ipt(Pos1),
  890    sub_string(Text1, Pos1, _, 0, Text3),
  891    findall(SubText, retract(subtext_db(RecNo, SubText)), TextL, [Text3]),
  892    atomics_to_string(TextL, Text).
  893
  894apply_commands_stream_each(RecNo1, FPTerm, File, CI, M, Max, Pos1, Command, Text, IPosText) :-
  895    apply_change(Text, M, Command, FromToPText1),
  896    ( do_recursion(CI, Command, GenModuleCommand, CS),
  897      FromToPText1 = t(From, To, PasteText1),
  898      get_out_pos(Text, Pos1, From, LPos),
  899      line_pos(LPos, atom(LeftText)),
  900      atomics_to_string([LeftText, PasteText1], Text1),
  901      setup_call_cleanup(
  902          ( atomics_to_string([Text1, "."], TextS),
  903            open_codes_stream(TextS, In),
  904            stream_property(In, position(Pos3)),
  905            succ(RecNo1, RecNo)
  906          ),
  907          with_refactor_context(
  908              apply_commands_stream(RecNo, FPTerm, GenModuleCommand, File,
  909                                    term, M, CS, Max, Pos3, In, Text1, Text2),
  910              [text], [TextS]),
  911          close(In))
  912    ->atomics_string([LeftText, PasteText2], Text2),
  913      FromToPText = t(From, To, PasteText2)
  914    ; FromToPText = FromToPText1
  915    ),
  916    string_concat_to(RecNo1, Text, FromToPText, IPosText).
  917
  918get_out_pos(Text, Pos, From, LPos) :-
  919    stream_position_data(line_position, Pos, LPos1),
  920    stream_position_data(char_count, Pos, Pos1),
  921    Length is max(0, From-Pos1),
  922    sub_string(Text, Pos1, Length, _, Text2),
  923    with_output_to(atom(_),
  924                   ( line_pos(LPos1),
  925                     format("~s", [Text2]),
  926                     stream_property(current_output, position(Pos2)),
  927                     stream_position_data(line_position, Pos2, LPos)
  928                   )).
  929
  930/* This was too slow --EMM
  931get_out_pos(RText, Pos-Text1, From, LPos) :-
  932    Length is max(0, From - Pos),
  933    sub_string(RText, Pos, Length, _, Text2),
  934    string_concat(Text1, Text2, Text3),
  935    textpos_line(Text3, From, LPos).
  936*/
  937
  938string_concat_to(RecNo, Text, t(From, To, Text2), IPos) :-
  939    IPos = ipt(Pos),
  940    Length is max(0, From - Pos),
  941    sub_string(Text, Pos, Length, _, Text1),
  942    nb_setarg(1, IPos, To),
  943    assertz(subtext_db(RecNo, Text1)),
  944    ignore(space_succ_operators(RecNo, Text1, Text2)),
  945    assertz(subtext_db(RecNo, Text2)).
 space_succ_operators(+RecNo, +Text1, +Text2) is semidet
Adds an extra space to avoid melting of successive operators
  950space_succ_operators(RecNo, Text1, Text2) :-
  951    sub_string(Text1, _, 1, 0, Char1),
  952    sub_string(Text2, 0, 1, _, Char2),
  953    char_type(Char1, prolog_symbol),
  954    char_type(Char2, prolog_symbol),
  955    assertz(subtext_db(RecNo, " ")).
  956
  957gen_new_variable_name(VNL, Prefix, Count, Name) :-
  958    atom_concat(Prefix, Count, Name),
  959    \+ member(Name=_, VNL), !.
  960gen_new_variable_name(VNL, Prefix, Count1, Name) :-
  961    succ(Count1, Count),
  962    gen_new_variable_name(VNL, Prefix, Count, Name).
  963
  964will_occurs(Var, Sent, Pattern, Into, VNL, T) :-
  965    findall(N,
  966            ( member(Name=Var1, VNL),
  967              Name \= '_',
  968              Var==Var1
  969            ->member(Name=Var2, VNL),
  970              will_occurs(Var2, Sent, Pattern, Into, N)
  971            ; will_occurs(Var,  Sent, Pattern, Into, N)
  972            ), NL),
  973    sum_list(NL, T).
  974
  975will_occurs(Var, Sent, Pattern, Into, N) :-
  976    occurrences_of_var(Var, Sent, SN),
  977    occurrences_of_var(Var, Pattern, PN),
  978    occurrences_of_var(Var, Into, IN),
  979    N is SN-PN+IN.
  980
  981gen_new_variable_names([], _, _, _, _, _, _, VNL, VNL).
  982gen_new_variable_names([Var|VarL], [Name1|NameL], Prefix, Count1,
  983                       Sent, Pattern, Into, VNL1, VNL) :-
  984    ( nonvar(Name1)
  985    ->VNL2 = VNL1,
  986      Count = Count1
  987    ; will_occurs(Var, Sent, Pattern, Into, VNL1, N),
  988      N > 1
  989    ->gen_new_variable_name(VNL1, Prefix, Count1, Name),
  990      succ(Count1, Count),
  991      VNL2 = [Name=Var|VNL1]
  992    ; VNL2 = ['_'=Var|VNL1],
  993      Count = Count1
  994    ),
  995    gen_new_variable_names(VarL, NameL, Prefix, Count, Sent, Pattern, Into, VNL2, VNL).
  996
  997level_1_term(V) :- var(V), !, fail.
  998level_1_term('$RM').
  999level_1_term('$C'(_, Into)) :- level_1_term(Into).
 1000level_1_term('$TEXT'(_)).
 1001level_1_term('$TEXT'(_, _)).
 1002level_1_term('$TEXTQ'(_)).
 1003level_1_term('$TEXTQ'(_, _)).
 1004level_1_term('$LISTC'(_)).
 1005level_1_term('$LISTC.NL'(_)).
 1006
 1007apply_change(Text, M, subst(TermPos, Options, Term, Into, _),
 1008             t(From, To, PasteText)) :-
 1009    ( level_1_term(Into)
 1010    ->ITermPos = TermPos
 1011    ; get_innerpos(TermPos, ITermPos)
 1012    ),
 1013    arg(1, ITermPos, From),
 1014    arg(2, ITermPos, To1),
 1015    call_cleanup(
 1016        with_output_to_string(
 1017            PasteText,
 1018            with_from(
 1019                with_termpos(
 1020                    print_expansion_1(Into, Term, ITermPos,
 1021                                      [ module(M),
 1022                                        text(Text)
 1023                                        |Options
 1024                                      ], Text, To1, To),
 1025                    TermPos),
 1026                From)
 1027        ),
 1028        retractall(rportray_pos(_, _))).
 1029
 1030wr_options([portray_goal(ref_replace:rportray),
 1031            spacing(next_argument),
 1032            numbervars(true),
 1033            quoted(true),
 1034            partial(true),
 1035            character_escapes(false)]).
 1036
 1037call_expander(Expander, TermPos, Pattern, Into) :-
 1038    refactor_context(tries, Tries),
 1039    refactor_context(max_tries, MaxTries),
 1040    ( nonvar(MaxTries)
 1041    ->Tries < MaxTries
 1042    ; true
 1043    ),
 1044    succ(Tries, Tries1),
 1045    nb_set_refactor_context(tries, Tries1),
 1046    with_refactor_context(catch(once(Expander), Error,
 1047                              ( refactor_message(error, Error),
 1048                                fail
 1049                              )),
 1050                        [termpos, pattern, into],
 1051                        [TermPos, Pattern, Into]).
 1052
 1053special_term(top, Term1, Into1, Into7, Into) :-
 1054    ( nonvar(Into1),
 1055      escape_term(Into1)
 1056    ->Into = Into7
 1057    ; nonvar(Term1),
 1058      memberchk(Term1, [[], end_of_file])
 1059    ->( \+ is_list(Into1)
 1060      ->List = [Into7]
 1061      ; List = Into7
 1062      ),
 1063      Into = '$LISTC.NL'(List)
 1064    ; var(Into1)
 1065    ->Into = Into7
 1066    ; is_list(Into1),
 1067      same_length(Into1, Term1)
 1068    ->Into = Into7
 1069    ; Into1 = [_|_]
 1070    ->Into = '$LISTC'(Into7)
 1071    ; Into1 = []
 1072    ->Into = '$RM'
 1073    ; Into1 = '$C'(C, [])
 1074    ->Into = '$C'(C, '$RM')
 1075    ; Into = Into7
 1076    ).
 1077special_term(sub_cw, _, _, Term, Term).
 1078special_term(sub,    _, _, Term, Term).
 1079
 1080trim_hacks(Term, Trim) :-
 1081    substitute(trim_hack, Term, Trim).
 1082
 1083trim_hack(Term, Trim) :-
 1084    nonvar(Term),
 1085    do_trim_hack(Term, Trim1),
 1086    trim_hacks(Trim1, Trim).
 1087
 1088do_trim_hack('$@'(Term, _), Term).
 1089do_trim_hack('@@'(Term, _), Term).
 1090do_trim_hack('$C'(_, Term), Term).
 1091do_trim_hack(\\(Term), Term).
 1092do_trim_hack('$NOOP'(_), '').
 1093
 1094remove_hacks(H, T) :-
 1095    trim_hacks(H, S),
 1096    deref_substitution(S, T).
 1097
 1098match_vars_with_names(VNL1, Var, Name) :-
 1099    ignore(( member(Name=Var1, VNL1),
 1100             Var == Var1
 1101           )).
 1102
 1103gen_new_variable_names(Sent, Term, Into, VNL, NewVNL) :-
 1104    refactor_context(prefix, Prefix),
 1105    refactor_context(variable_names, VNL1),
 1106    trim_hacks(Into, TInto),
 1107    term_variables(TInto, VarL),
 1108    maplist(match_vars_with_names(VNL1), VarL, NameL),
 1109    gen_new_variable_names(VarL, NameL, Prefix, 1, Sent, Term, TInto, VNL1, VNL),
 1110    once(append(NewVNL, VNL1, VNL)).
 1111
 1112check_bindings(Sent, Sent2, Options) :-
 1113    ( Sent=@=Sent2
 1114    ->true
 1115    ; option(show_left_bindings(Show), Options, false),
 1116      ( Show = true
 1117      ->refactor_message(warning, format("Bindings occurs: ~w \\=@= ~w.", [Sent2, Sent]))
 1118      ; true
 1119      )
 1120    ).
 1121
 1122:- public
 1123       pattern_size/3. 1124
 1125pattern_size(Term, Pattern, Size) :-
 1126    findall(S,
 1127            ( sub_term(Sub, Term),
 1128              subsumes_term(Pattern, Sub),
 1129              term_size(Sub, S)
 1130            ), SL),
 1131    sum_list(SL, Size).
 1132
 1133fix_subtermpos(Pattern, _, _, _, _) :-
 1134    nonvar(Pattern),
 1135    memberchk(Pattern, [[], end_of_file]), !.
 1136fix_subtermpos(_, Into, Sub, TermPos, Options) :-
 1137    fix_subtermpos(Sub, Into, TermPos, Options).
 1138
 1139fix_subtermpos(sub_cw, _,    _, _). % Do nothing
 1140fix_subtermpos(sub,    _,    TermPos, Options) :-
 1141    fix_subtermpos(TermPos, Options).
 1142fix_subtermpos(top,    Into, TermPos, Options) :-
 1143    ( Into \= [_|_]
 1144    ->fix_termpos(   TermPos, Options)
 1145    ; fix_subtermpos(TermPos, Options)
 1146    ).
 substitute_term_norec(+Sub, +M, +Term, +Priority, +Pattern, +Into, :Expander, +TermPos, SentPos, Cmd) is nondet
Non-recursive version of substitute_term_rec/6.
 1152substitute_term_norec(Sub, M, Term, TermPos1, Priority,
 1153                      data(Pattern1, Into1, Expander, SentPos),
 1154                      subst(TTermPos1, SubstOptions, Term, Into, Size)) :-
 1155    wr_options(WriteOptions),
 1156    refactor_context(sentence,     Sent),
 1157    refactor_context(sent_pattern, SentPattern),
 1158    subsumes_term(SentPattern-Pattern1, Sent-Term),
 1159    refactor_context(options, Options),
 1160    merge_options([priority(Priority),
 1161                   variable_names(VNL),
 1162                   new_variable_names(NewVNL)
 1163                   |WriteOptions], Options, SubstOptions),
 1164    option(decrease_metric(Metric), Options, ref_replace:pattern_size),
 1165    call(Metric, Term, Pattern1, Size),
 1166    with_context(Sub, M, Term, TermPos1, TTermPos1, Priority, Sent, SentPos, Pattern1, Into1, Into, VNL, NewVNL, Expander, Options).
 1167
 1168val_subs(V, S) -->
 1169    ( {var(S)}
 1170    ->{V=S}
 1171    ; [V=S]
 1172    ).
 1173
 1174with_context(Sub, M, Term1, TermPos1, TTermPos1, Priority, Sent1, SentPos1, Pattern1, Into1, Into, VNL, NewVNL, Expander1, Options) :-
 1175    % Suffix numbers in variables should refer to:
 1176    % 1: Term changes during Expander1 execution
 1177    % 2: Substitutions instead of unifications in Into2 due to Term changes in (1)
 1178    % 3: The raw Term, as read from the file
 1179    % 4: Pattern changes during Expander1 execution
 1180    % 5: Original pattern
 1181    refactor_context(sent_pattern, SentPattern1),
 1182    copy_term(SentPattern1-Pattern1-Into1, _Sent5-Term5-Into5),
 1183    copy_term(SentPattern1-Pattern1-Into1, _Sent4-Term4-Into4),
 1184    Pattern1 = Term1,
 1185    SentPattern1 = Sent1,
 1186    term_variables(Sent1-Term1-Into1, Vars1),
 1187    copy_term(Sent1-Term1-Into1-Vars1, Sent3-Term3-Into3-Vars3),
 1188    call_expander(Expander1, TermPos1, Term4, Into4),
 1189    Term2 = Term3,
 1190    foldl(val_subs, Vars3, Vars1, ValSubs, []),
 1191    substitute_values(ValSubs, Into3, Into2),
 1192    check_bindings(Sent1, Sent3, Options),
 1193    gen_new_variable_names(Sent1, Term1, Into1, VNL, NewVNL),
 1194    trim_fake_pos(TermPos1, TTermPos1, N),
 1195    substitute_value(TermPos1, TTermPos1, SentPos1, TSentPos1),
 1196    trim_fake_args_ll(N, [[   _, Term2, Into2],
 1197                          [orig, Term5, Into5],
 1198                          [pexp, Term4, Into4],
 1199                          %[rawt, Term3, Into3], % Not needed since it is implicit in (2)
 1200                          [texp, Term2, Into2]],
 1201                      [[_, TTerm1, TInto1]|SpecTermIntoLL]),
 1202    /* Note: fix_subtermpos/5 is a very expensive predicate, due to that we
 1203       delay its execution until its result be really needed, and we only
 1204       apply it to the subterm positions being affected by the refactoring.
 1205       The predicate performs destructive assignment (as in imperative
 1206       languages), modifying term position once the predicate is called */
 1207    fix_subtermpos(TTerm1, TInto1, Sub, TSentPos1, Options),
 1208    set_refactor_context(subpos, TSentPos1),
 1209    replace_subterm_locations(NewVNL, SpecTermIntoLL, TTerm1, TInto1, M, TTermPos1, Priority, TInto7),
 1210    special_term(Sub, TTerm1, TInto1, TInto7, Into).
 1211
 1212sleq(Term, Into, Term) :- Term == Into.
 1213
 1214subterm_location_same_term([], Term1, Term2, Term1) :-
 1215    % Non-ground dictionaries are not linked but duplicated, therefore we
 1216    % should use ==/2 instead of same_term
 1217    ( is_dict(Term1),
 1218      \+ ground(Term1)
 1219    ->Term1==Term2
 1220    ; same_term(Term1, Term2)
 1221    ),
 1222    !.
 1223subterm_location_same_term([N|L], Term1, Term2, SubTerm) :-
 1224    compound(Term1),
 1225    arg(N, Term1, SubTerm1),
 1226    arg(N, Term2, SubTerm2),
 1227    subterm_location_same_term(L, SubTerm1, SubTerm2, SubTerm).
 1228
 1229:- thread_local partial_path_db/1. 1230
 1231is_scanneable(Term) :-
 1232    compound(Term),
 1233    \+ memberchk(Term, ['$@'(_), '$$'(_), '$G'(_, _)]).
 1234
 1235find_term_path([Spec, Term2, Into2],
 1236               [Spec2, TermLoc2, IntoLoc2, ArgLoc2, SubLoc2],
 1237               [Spec1, TermLoc1, IntoLoc1, ArgLoc1, SubLoc1]) :-
 1238    ( Into2 \== Term2,
 1239      location_subterm_un(IntoLoc2, Into2, is_scanneable, Sub2),
 1240      location_subterm_eq(TermLoc2, Term2, Sub2),
 1241      ArgLoc1 = SubLoc1,
 1242      ( ArgLoc2 = []
 1243      ->Spec1 = Spec2
 1244      ; Spec1 = Spec
 1245      )
 1246    ; ArgLoc2 = [],
 1247      SubLoc2 = [],
 1248      Spec1 = Spec2
 1249    ),
 1250    append(IntoLoc2, SubLoc1, IntoLoc1),
 1251    append(TermLoc2, ArgLoc1, TermLoc1).
 1252
 1253curr_subterm_replacement(SpecTermIntoLL, Term1, Into1, TermLoc1, IntoLoc1, ArgLocL, Size) :-
 1254    retractall(partial_path_db(_)),
 1255    foldl(find_term_path, SpecTermIntoLL,
 1256          [orig, TermLoc, IntoLoc, TermLoc, IntoLoc], [Spec1, TermLoc1, IntoLoc1, _, _]),
 1257    once(location_subterm_un(IntoLoc1, Into1, is_scanneable, Sub1)),
 1258    \+ partial_path_db(IntoLoc1),
 1259    % Next check avoids things like [A|[]] being printed:
 1260    \+ ( memberchk(Spec1, [rawt, texp]),
 1261         Sub1 == []
 1262       ),
 1263    subterm_location(sleq(Arg1, Sub1), Term1, TermLoc1),
 1264    append(IntoLoc1, _, PIntoLoc1),
 1265    assertz(partial_path_db(PIntoLoc1)),
 1266    findall([Ord1, ArgLoc],
 1267            ( subterm_location_same_term(ArgLoc, Arg1, Sub1, ToRep),
 1268              term_size(ToRep, Size1),
 1269              Ord1 is -Size1
 1270            ), ArgLocLU),
 1271    sort(ArgLocLU, ArgLocLL),
 1272    transpose(ArgLocLL, [[Ord1|_], ArgLocL]),
 1273    Size is -Ord1.
 1274
 1275replace_subterm_locations(VNL, SpecTermIntoLL, Term1, Into1, M, TermPos, Priority, Into) :-
 1276    findall(([TermLoc1, IntoLoc1]-ArgLocL),
 1277            order_by([desc(Size)],
 1278                     curr_subterm_replacement(SpecTermIntoLL, Term1, Into1, TermLoc1, IntoLoc1, ArgLocL, Size)),
 1279            TermLocArgLocLL),
 1280    foldl(perform_replacement(VNL, M, TermPos, Priority, Term1, Into1), TermLocArgLocLL, Into1-[], Into-VL),
 1281    maplist(collapse_bindings, VL).
 1282
 1283collapse_bindings(A=B) :- ignore(A=B).
 1284
 1285perform_replacement(VNL, M, TermPos, Priority1, Term1, Into1, [TermLoc, IntoLoc]-ArgLocL, TInto1-VL1, TInto-[Var1=Rep1|VL1]) :-
 1286    % location_subterm_un(TermLoc, Term1, Sub1),
 1287    location_subterm_un(IntoLoc, Into1, Arg1),
 1288    subpos_location(TermLoc, TermPos, SubPos),
 1289    foldl(perform_replacement_2(VNL, SubPos, Arg1), ArgLocL, RepU, []),
 1290    sort(RepU, RepL),
 1291    ( append(L1, [E], TermLoc),
 1292      location_subterm_un(L1, Term1, TP),
 1293      term_priority(TP, M, E, Priority)
 1294    ->true
 1295    ; Priority = Priority1
 1296    ),
 1297    compound(SubPos),
 1298    arg(1, SubPos, From),
 1299    arg(2, SubPos, To),
 1300    From \= To,
 1301    get_innerpos(SubPos, ISubPos),
 1302    Rep1 = '$sb'(SubPos, ISubPos, RepL, Priority, Arg1),
 1303    replace_at_subterm_location(IntoLoc, Var1, TInto1, TInto),
 1304    !.
 1305perform_replacement(_, _, _, _, _, _, _, IntoVL, IntoVL).
 1306
 1307get_innerpos(OSubPos, ISubPos) :-
 1308    OSubPos =.. [F, OFrom, OTo|Args],
 1309    term_innerpos(OFrom, OTo, IFrom, ITo),
 1310    !,
 1311    ISubPos =.. [F, IFrom, ITo|Args].
 1312get_innerpos(SubPos, SubPos).
 1313
 1314replace_at_subterm_location([], Rep, _, Rep).
 1315replace_at_subterm_location([N|L], Rep, Term1, Term2) :-
 1316    compound(Term1),
 1317    compound_name_arguments(Term1, Name, Args1),
 1318    length([_|Left], N),
 1319    append(Left, [Arg1|Right], Args1),
 1320    append(Left, [Arg2|Right], Args2),
 1321    compound_name_arguments(Term2, Name, Args2),
 1322    replace_at_subterm_location(L, Rep, Arg1, Arg2).
 1323
 1324perform_replacement_2(VNL, SubPos, Arg1, ArgLoc) -->
 1325    { subpos_location(ArgLoc, SubPos, ArgPos),
 1326      location_subterm_un(ArgLoc, Arg1, ToRep1)
 1327    },
 1328    ( {var(ToRep1)}
 1329    ->( { member(Name = Var, VNL),
 1330          ToRep1 == Var
 1331        }
 1332      ->['$sb'(ArgPos, '$VAR'(Name))]
 1333      ; []
 1334      )
 1335    ; []
 1336    ).
 1337
 1338fake_pos(T-T).
 trim_fake_pos(+TermPos, -Pos, -N)
remove fake arguments that would be added by dcg
 1343trim_fake_pos(Pos1, Pos, N) :-
 1344    ( nonvar(Pos1),
 1345      Pos1 = term_position(F, T, FF, FT, PosL1),
 1346      nonvar(PosL1)
 1347    ->partition(fake_pos, PosL1, FakePosL, PosL),
 1348      length(FakePosL, N),
 1349      Pos = term_position(F, T, FF, FT, PosL)
 1350    ; Pos = Pos1,
 1351      N = 0
 1352    ).
 1353
 1354trim_fake_args_ll(N, L, T) :-
 1355    maplist(trim_fake_args_l(N), L, T).
 1356
 1357trim_fake_args_l(N, [E|L], [E|T]) :-
 1358    maplist(trim_fake_args(N), L, T).
 1359
 1360trim_fake_args(N, Term1, Term) :-
 1361    ( N > 0,
 1362      Term1 =.. ATerm1,
 1363      length(TE, N),
 1364      append(ATerm, TE, ATerm1),
 1365      Term =.. ATerm
 1366    ->true
 1367    ; Term = Term1
 1368    ).
 substitute_term_rec(+Module, +Term, +TermPos, +Priority, +Data, -Cmd) is nondet
True when Cmd contains a substitution for Pattern by Into in SrcTerm, where Data = data(Pattern, Into, Expander, SentPos). This predicate must be cautious about handling bindings:
 1385substitute_term_rec(M, Term, TermPos, Priority, Data, Cmd) :-
 1386    substitute_term_norec(sub, M, Term, TermPos, Priority, Data, Cmd),
 1387    !.
 1388substitute_term_rec(M, Term, TermPos, _, Data, Cmd) :-
 1389    substitute_term_into(TermPos, M, Term, Data, Cmd).
 1390
 1391substitute_term_into(brace_term_position(_, _, Pos), M, {Term}, Data, Cmd) :-
 1392    substitute_term_rec(M, Term, Pos, 1200, Data, Cmd).
 1393substitute_term_into(parentheses_term_position(_, _, Pos), M, Term, Data, Cmd) :-
 1394    substitute_term_rec(M, Term, Pos, 1200, Data, Cmd).
 1395substitute_term_into(term_position(_, _, _, _, PosL), M, Term, Data, Cmd) :-
 1396    substitute_term_args(PosL, M, Term, Data, Cmd).
 1397substitute_term_into(Pos, M, Term, Data, Cmd) :-
 1398    member(Pos, [list_position(_, _, _, _),
 1399                 sub_list_position(_, _, _, _, _, _, _)]),
 1400    neck,
 1401    substitute_term_list(Pos, M, Term, Data, Cmd).
 1402substitute_term_into(dict_position(_, _, From, To, PosL), M, Term, Data, Cmd) :-
 1403    is_dict(Term, Tag),
 1404    ( substitute_term_norec(sub, M, Tag, From-To, 999, Data, Cmd)
 1405    ; member(Pos, PosL),
 1406      substitute_term_pair(M, Term, Pos, Data, Cmd)
 1407    ).
 1408
 1409substitute_term_pair(M, Term, key_value_position(_, _, _, _, Key, PosK, PosV), Data, Cmd) :-
 1410    ( substitute_term_rec(M, Key, PosK, 999, Data, Cmd)
 1411    ; substitute_term_rec(M, Term.Key, PosV, 999, Data, Cmd)
 1412    ).
 1413
 1414:- use_module(library(listing), []). 1415
 1416term_priority(Term, M, N, Priority) :-
 1417    compound(Term),
 1418    term_priority_gnd(Term, M, N, PrG),
 1419    ( arg(N, Term, Arg),
 1420      term_needs_braces(M:Arg, PrG)
 1421    ->Priority = 999
 1422    ; Priority = PrG
 1423    ).
 1424
 1425term_priority_gnd(Term, M, N, PrG) :-
 1426    functor(Term, F, A),
 1427    ( ( A == 1
 1428      ->( prolog_listing:prefix_op(M:F, PrG) -> true
 1429        ; prolog_listing:postfix_op(M:F, PrG) -> true
 1430        )
 1431      ; A == 2
 1432      ->prolog_listing:infix_op(M:F, Left, Right),
 1433        ( N==1 -> PrG = Left
 1434        ; N==2 -> PrG = Right
 1435        )
 1436      )
 1437    ->true
 1438    ; term_priority((_, _), user, 1, PrG)
 1439    ).
 1440
 1441substitute_term_args(PAL, M, Term, Data, Cmd) :-
 1442    nth1(N, PAL, PA),
 1443    arg(N, Term, Arg),
 1444    term_priority(Term, M, N, Priority),
 1445    substitute_term_rec(M, Arg, PA, Priority, Data, Cmd).
 1446
 1447substitute_term_list(Pos, M, [Elem|Tail], Data, Cmd) :-
 1448    STo = s(1),
 1449    order_by([asc(From)],
 1450             ( member(Loc-Term, [1-Elem, 2-Tail]),
 1451               subpos_location([Loc], Pos, SubPos),
 1452               term_priority([_|_], M, Loc, Priority),
 1453               substitute_term_rec(M, Term, SubPos, Priority, Data, Cmd),
 1454               arg(1, Cmd, TermPos),
 1455               arg(1, TermPos, From)
 1456             )),
 1457    % Trick to avoid overlap:
 1458    arg(1, STo, To1),
 1459    To1 =< From,
 1460    arg(2, TermPos, To),
 1461    nb_setarg(1, STo, To).
 1462
 1463compound_positions(Line1, Pos2, Pos1, Pos) :- Line1 =< 1, !, Pos is Pos1+Pos2.
 1464compound_positions(_, Pos, _, Pos).
 1465
 1466get_output_position(Pos) :-
 1467    ( refactor_context(from, From)
 1468    ->true
 1469    ; From = 0
 1470    ),
 1471    get_output_position(From, Pos).
 1472
 1473get_output_position(From, Pos) :-
 1474    refactor_context(text, Text),
 1475    textpos_line(Text, From, Pos1),
 1476    stream_property(current_output, position(StrPos)),
 1477    stream_position_data(line_count, StrPos, Line1),
 1478    stream_position_data(line_position, StrPos, Pos2),
 1479    compound_positions(Line1, Pos2, Pos1, Pos).
 1480
 1481write_term_dot_nl(Term, OptL) :-
 1482    write_term(Term, OptL),
 1483    write('.\n').
 1484
 1485rportray_clause(Clause, OptL) :- rportray_clause(Clause, 0, OptL).
 1486
 1487% We can not use portray_clause/3 because it does not handle the hooks
 1488% portray_clause_(OptL, Clause) :-
 1489%     portray_clause(current_output, Clause, OptL).
 1490
 1491rportray_clause(C, Pos, OptL1) :-
 1492    option(module(M), OptL1),
 1493    stream_property(current_output, position(SPos1)),
 1494    merge_options([portray_clause(false), partial(false)], OptL1, OptL2),
 1495    write(''),
 1496    write_term(C, OptL2),
 1497    stream_property(current_output, position(SPos2)),
 1498    ( nonvar(C),
 1499      ( stream_position_data(line_count, SPos1, Line1),
 1500        stream_position_data(line_count, SPos2, Line2),
 1501        Line1 \= Line2
 1502      ; stream_position_data(line_position, SPos2, Pos2),
 1503        Pos2 > 80
 1504      )
 1505    ->set_stream_position(current_output, SPos1),
 1506      ( option(priority(CPri), OptL1),
 1507        term_needs_braces(C, M, CPri)
 1508      ->Display = yes,
 1509        succ(Pos, BPos)
 1510      ; Display = no,
 1511        BPos = Pos
 1512      ),
 1513      cond_display(Display, '('),
 1514      merge_options([portray_clause(true)], OptL1, OptL3),
 1515      ( memberchk(C, [(H :- B), (H --> B)])
 1516      ->write(''),
 1517        write_term(H, OptL3),
 1518        functor(C, Neck, _),
 1519        write(' '),
 1520        writeln(Neck),
 1521        line_pos(4+BPos),
 1522        term_priority((_, _), M, 2, Priority),
 1523        merge_options([priority(Priority)], OptL3, OptL4),
 1524        write_b(B, OptL4, 4+BPos)
 1525      ; write(''),
 1526        write_term(C, OptL3)
 1527      ),
 1528      cond_display(Display, ')')
 1529    ; true
 1530    ).
 1531
 1532deref_substitution(Var, Var) :- var(Var), !.
 1533deref_substitution('$sb'(_, _, _, _, Term), Sub) :-
 1534    !,
 1535    deref_substitution(Term, Sub).
 1536deref_substitution(Term, Term).
 1537
 1538write_pos_lines(Pos, Writer, Lines) :-
 1539    write_pos_rawstr(Pos, Writer, String),
 1540    atomics_to_string(Lines, '\n', String).
 1541
 1542write_pos_rawstr(Pos, Writer, String) :-
 1543    with_output_to_string(
 1544        String,
 1545        nl, % start with a new line, since the position is not reseted
 1546        ( line_pos(Pos),
 1547          call(Writer)
 1548        )).
 1549
 1550write_pos_string(Pos, Writer, String) :-
 1551    write_pos_rawstr(Pos, Writer, RawStr),
 1552    pos_indent(Pos, Indent),
 1553    atom_concat(Indent, String, RawStr).
 1554
 1555write_term_lines(Pos, Opt, Term, Lines) :-
 1556    write_pos_lines(Pos, write_term(Term, Opt), Lines).
 1557
 1558write_term_string(Pos, Opt, Term, String) :-
 1559    write_pos_string(Pos, write_term(Term, Opt), String).
 1560
 1561print_subtext_sb_1(Text, Options, '$sb'(SubPos, Term), From, To) :-
 1562    arg(1, SubPos, SubFrom),
 1563    print_subtext(From-SubFrom, Text),
 1564    write_term(Term, Options),
 1565    arg(2, SubPos, To).
 1566
 1567print_subtext_sb_2(Term, TermPos, RepL, Priority, Text, Options) :-
 1568    reindent(TermPos, Text,
 1569             with_cond_braces_2(print_subtext_2, Term, TermPos, RepL, Priority, Text, Options)).
 1570
 1571reindent(TermPos, Text, Goal) :-
 1572    with_output_to_string(RawText, Goal),
 1573    ( \+ sub_string(RawText, _, _, _, '\n') % No need to reindent
 1574    ->SubText = RawText
 1575    ; arg(1, TermPos, From),
 1576      ( seek1_char_left(Text, "\n", From, Distance1)
 1577      ->CropLength1 is From - (Distance1 + 1)
 1578      ; CropLength1 is From
 1579      ),
 1580      offset_pos('$OUTPOS', PrefLength1),
 1581      atomic_list_concat(L1, '\n', RawText),
 1582      L1 = [E|T1], % First line is OK
 1583      Delta is abs(PrefLength1 - CropLength1),
 1584      pos_indent(Delta, ReIndent),
 1585      ( CropLength1 < PrefLength1
 1586      ->% Increment indentation
 1587        A2 = E1,
 1588        A3 = E2
 1589      ; % Decrement indentation
 1590        A2 = E2,
 1591        A3 = E1
 1592      ),
 1593      findall(E2,
 1594              ( member(E1, T1),
 1595                once(( atom_concat(ReIndent, A2, A3)
 1596                     ; E2 = E1
 1597                     ))
 1598              ), L2),
 1599      atomic_list_concat([E|L2], '\n', SubText)
 1600    ),
 1601    print_text(SubText).
 1602
 1603with_cond_braces_2(Call, Term, TermPos, RepL, GPriority, Text, Options) :-
 1604    option(module(M), Options),
 1605    option(priority(Priority), Options),
 1606    fix_position_if_braced(TermPos, M, Term, GPriority, Term, Priority, Display),
 1607    cond_display(Display, '('),
 1608    call(Call, TermPos, RepL, Text, Options),
 1609    cond_display(Display, ')').
 1610
 1611print_subtext_2(sub_list_position(BFrom, To, BTo, _, From, PosL, Tail), RepL, Text, Options) :-
 1612    !,
 1613    print_subtext(BFrom-BTo, Text),
 1614    print_subtext_2(list_position(From, To, PosL, Tail), RepL, Text, Options).
 1615print_subtext_2(TermPos, RepL, Text, Options) :-
 1616    arg(1, TermPos, From),
 1617    arg(2, TermPos, To),
 1618    foldl(print_subtext_sb_1(Text, Options), RepL, From, SubTo),
 1619    print_subtext(SubTo-To, Text).
 1620
 1621:- public
 1622    rportray/2. 1623
 1624/*
 1625rportray('$sb'(TermPos), _) :-
 1626    \+ retract(rportray_skip),
 1627    !,
 1628    refactor_context(text, Text),
 1629    print_subtext(TermPos, Text).
 1630*/
 1631rportray('$sb'(SubPos, _, RepL, Priority, Term), Options) :-
 1632    \+ retract(rportray_skip),
 1633    !,
 1634    % Kludge to get the spaces needed to print Term:
 1635    select_option(portray_goal(PG), Options, Options2, PG),
 1636    stream_property(current_output, position(S1)),
 1637    write_term(Term, Options2),
 1638    stream_property(current_output, position(S2)),
 1639    write_length(Term, Length, Options2),
 1640    stream_position_data(char_count, S1, B1),
 1641    stream_position_data(char_count, S2, B2),
 1642    Offset is B2-B1-Length,
 1643    set_stream_position(current_output, S1),
 1644    % to use seek, Offset must be positive, otherwise it will not work properly
 1645    seek(current_output, Offset, current, _),
 1646    option(text(Text), Options),
 1647    ignore(print_subtext_sb_2(Term, SubPos, RepL, Priority, Text, Options)).
 1648rportray('$@'(Term), Options) :-
 1649    write_term(Term, Options).
 1650rportray('$$'(Term), Options1) :-
 1651    select_option(portray_goal(_), Options1, Options),
 1652    write_term(Term, Options).
 1653rportray(\\(Term), Options) :-
 1654    \+ retract(rportray_skip),
 1655    !,
 1656    assertz(rportray_skip),
 1657    write_term(Term, Options).
 1658% rportray('$sb'(_, _, _, _), _) :- !.
 1659rportray(@@(Term, STerm), Options) :-
 1660    \+ retract(rportray_skip),
 1661    !,
 1662    ( nonvar(STerm),
 1663      STerm = '$sb'(OTermPos, ITermPos, _, _, _)
 1664    ->arg(1, ITermPos, IFrom),
 1665      arg(2, ITermPos, ITo),
 1666      arg(1, OTermPos, OFrom),
 1667      arg(2, OTermPos, OTo),
 1668      option(text(Text), Options),
 1669      print_subtext(OFrom-IFrom, Text),
 1670      write_term(Term, Options),
 1671      print_subtext(ITo-OTo, Text)
 1672    ; write_term(Term, Options)
 1673    ).
 1674% Use a different pattern to guide the printing of Term:
 1675rportray('$@'(Into, '$sb'(_, SubPos, _, Priority, Term)), Options) :-
 1676    !,
 1677    option(text(Text), Options),
 1678    once(print_expansion_sb(Into, Term, SubPos, Priority, Options, Text)).
 1679rportray('$G'(Into, Goal), Opt) :-
 1680    callable(Goal),
 1681    \+ special_term(Goal),
 1682    !,
 1683    with_str_hook(write_term(Into, Opt), Goal).
 1684rportray('$C'(Goal, Into), Opt) :-
 1685    callable(Goal),
 1686    \+ special_term(Goal),
 1687    !,
 1688    call(Goal),
 1689    write_term(Into, Opt).
 1690% Ignore, but process for the side effects
 1691rportray('$NOOP', _) :- !.
 1692rportray('$NOOP'(Term), Opt) :-
 1693    !,
 1694    with_output_to(string(_), write_term(Term, Opt)).
 1695rportray('$TEXT'(T), Opt) :- !, write_t(T, Opt).
 1696rportray('$TEXT'(T, Offs), Opt) :-
 1697    offset_pos(Offs, Pos),
 1698    !,
 1699    line_pos(Pos),
 1700    write_t(T, Opt).
 1701rportray('$TEXTQ'(T), Opt) :- !, write_q(T, Opt).
 1702rportray('$TEXTQ'(T, Offs), Opt) :-
 1703    offset_pos(Offs, Pos),
 1704    !,
 1705    line_pos(Pos),
 1706    write_q(T, Opt).
 1707rportray('$PRETXT'(TXT, Term), Opt) :-
 1708    !,
 1709    write(TXT),
 1710    write_term(Term, Opt).
 1711rportray('$POSTXT'(Term, TXT), Opt) :-
 1712    !,
 1713    write_term(Term, Opt),
 1714    write(TXT).
 1715rportray(H :- B, Opt) :-
 1716    option(portray_clause(true), Opt),
 1717    !,
 1718    offset_pos('$OUTPOS', Pos),
 1719    rportray_clause((H :- B), Pos, Opt).
 1720rportray(H --> B, Opt) :-
 1721    option(portray_clause(true), Opt),
 1722    !,
 1723    offset_pos('$OUTPOS', Pos),
 1724    rportray_clause((H --> B), Pos, Opt).
 1725rportray('$CLAUSE'(C), Opt) :- !, rportray_clause(C, Opt).
 1726rportray('$CLAUSE'(C, Offs), Opt) :-
 1727    !,
 1728    offset_pos(Offs, Pos),
 1729    rportray_clause(C, Pos, Opt).
 1730rportray('$BODY'(B, Offs), Opt) :-
 1731    offset_pos(Offs, Pos),
 1732    !,
 1733    rportray_body(B, Pos, Opt).
 1734rportray('$BODY'(B), Opt) :-
 1735    !,
 1736    offset_pos('$OUTPOS', Pos),
 1737    rportray_body(B, Pos, Opt).
 1738rportray('$BODYB'(B, Offs), Opt) :-
 1739    offset_pos(Offs, Pos),
 1740    !,
 1741    rportray_bodyb(B, Pos, Opt).
 1742rportray('$BODYB'(B), Opt) :-
 1743    !,
 1744    offset_pos('$OUTPOS', Pos),
 1745    rportray_bodyb(B, Pos, Opt).
 1746rportray('$POS'(Name, Term), Opt) :-
 1747    get_output_position(Pos),
 1748    nonvar(Name),
 1749    ( \+ rportray_pos(Name, _)
 1750    ->assertz(rportray_pos(Name, Pos))
 1751    ; refactor_message(warning, format("Position named ~w redefined", [Name])),
 1752      retractall(rportray_pos(Name, _)),
 1753      assertz(rportray_pos(Name, Pos))
 1754    ),
 1755    write_term(Term, Opt).
 1756rportray('$APP'(L1, L2), Opt) :-
 1757    !,
 1758    ( nonvar(L1),
 1759      L1 = '$sb'(OTermPos, ITermPos, RepL1, Priority, Term)
 1760    ->once(( ITermPos = list_position(_, LTo, _, Pos)
 1761           ; ITermPos = sub_list_position(_, LTo, _, _, _, _, Pos)
 1762           ; Pos = ITermPos
 1763           )),
 1764      ( Pos = none
 1765      ->succ(From, LTo),
 1766        ( trim_brackets(L2, L3, Opt)
 1767        ->remove_hacks(L3, T3),
 1768          ( T3 == []
 1769          ->sort(['$sb'(From-From, L3)|RepL1], RepL)
 1770          ; sort(['$sb'(From-From, '$,'('$TEXT'(', '), L3))|RepL1], RepL)
 1771          )
 1772        ; sort(['$sb'(From-From, '$,'('$TEXT'('|'), L2))|RepL1], RepL)
 1773        )
 1774      ; arg(1, Pos, From),
 1775        arg(2, Pos, To),
 1776        sort(['$sb'(From-To, L2)|RepL1], RepL)
 1777      ),
 1778      write_term('$sb'(OTermPos, ITermPos, RepL, Priority, Term), Opt)
 1779    ; append(L, T, L1),
 1780      ( var(T)
 1781      ; T \= [_|_]
 1782      )
 1783    ->append(L, L2, N),
 1784      write_term(N, Opt)
 1785    ).
 1786rportray('$,'(A, B), Opt) :- !, write_term(A, Opt), write_term(B, Opt).
 1787rportray('$LIST'( L), Opt) :- !, rportray_list(L, nb, write_term, '',  Opt).
 1788rportray('$LIST,'(L), Opt) :- !, rportray_list(L, nb, write_term, ',', Opt).
 1789rportray('$LIST,_'(L), Opt) :- !, maplist(term_write_comma_2(Opt), L).
 1790rportray('$LIST'(L, Sep), Opt) :- !, rportray_list(L, nb, write_term, Sep, Opt).
 1791rportray('$LISTC'(CL), Opt) :-
 1792    !,
 1793    merge_options([priority(1200), portray_clause(true)], Opt, Opt1),
 1794    option(text(Text), Opt),
 1795    term_write_sep_list_3(CL, rportray_clause, Text, '.\n', '.\n', Opt1).
 1796rportray('$LISTC.NL'(CL), Opt) :-
 1797    !,
 1798    merge_options([priority(1200), portray_clause(true)], Opt, Opt1),
 1799    option(text(Text), Opt),
 1800    term_write_sep_list_3(CL, rportray_clause, Text, '.\n', '.\n', Opt1),
 1801    write('.\n').
 1802rportray('$LIST.NL'(L), Opt) :-
 1803    !,
 1804    merge_options([priority(1200)], Opt, Opt1),
 1805    rportray_list(L, nb, write_term_dot_nl, '', Opt1).
 1806rportray('$LISTNL.'(L), Opt) :-
 1807    !,
 1808    merge_options([priority(1200)], Opt, Opt1),
 1809    rportray_list(L, nb, write_term, '.\n', Opt1).
 1810rportray('$LIST,NL'(L), Opt) :-
 1811    offset_pos('$OUTPOS', Pos),
 1812    !,
 1813    rportray_list_nl_comma(L, nb, Pos, Opt).
 1814rportray('$LISTNL'(L), Opt) :-
 1815    offset_pos('$OUTPOS', Pos),
 1816    !,
 1817    rportray_list_nl(L, nb, Pos, Opt).
 1818rportray('$TAB'(Term, Offs), Opt) :-
 1819    offset_pos(Offs-'$OUTPOS', Delta),
 1820    !,
 1821    forall(between(1, Delta, _), write(' ')),
 1822    write_term(Term, Opt).
 1823rportray('$LIST,NL'(L, Offs), Opt) :-
 1824    offset_pos(Offs, Pos),
 1825    !,
 1826    rportray_list_nl_comma(L, nb, Pos, Opt).
 1827rportray('$LISTNL'(L, Offs), Opt) :-
 1828    offset_pos(Offs, Pos),
 1829    !,
 1830    rportray_list_nl(L, nb, Pos, Opt).
 1831rportray('$LISTB,NL'(L), Opt) :-
 1832    offset_pos('$OUTPOS'+2, Pos),
 1833    !,
 1834    rportray_list_nl(L, wb(2, Pos), Pos, Opt).
 1835rportray('$LISTB,NL'(L, Offs), Opt) :-
 1836    offset_pos(Offs, Pos),
 1837    !,
 1838    offset_pos(Pos-'$OUTPOS', Delta),
 1839    rportray_list_nl(L, wb(Delta, Pos), Pos, Opt).
 1840rportray('$NL'(Term, Offs), Opt) :-
 1841    offset_pos(Offs, Pos),
 1842    !,
 1843    nl,
 1844    line_pos(Pos),
 1845    write_term(Term, Opt).
 1846rportray('$SEEK'(Term, Offs), Opt) :-
 1847    offset_pos(Offs, Pos),
 1848    seek(current_output, Pos, current, _),
 1849    write_term(Term, Opt).
 1850rportray('$NL', _) :- nl.
 1851rportray('$PRIORITY'(T, Priority), Opt) :-
 1852    integer(Priority),
 1853    !,
 1854    merge_options([priority(Priority)], Opt, Opt1),
 1855    write_term(T, Opt1).
 1856rportray(\+ Term, Opt) :-
 1857    !,
 1858    write_t('\\+ ', Opt),
 1859    write(''),
 1860    term_priority((_, _), user, 1, Priority),
 1861    merge_options([priority(Priority)], Opt, Opt1),
 1862    write_term(Term, Opt1).
 1863rportray('$RM', Opt) :-
 1864    !,
 1865    write_term(true, Opt).
 1866rportray((A, B), Opt) :-
 1867    !,
 1868    ( A == '$RM'
 1869    ->rportray(B, Opt)
 1870    ; B == '$RM'
 1871    ->rportray(A, Opt)
 1872    ; rportray_conj(A, B, Opt)
 1873    ).
 1874rportray([E|T1], Opt) :-
 1875    !,
 1876    ( E == '$RM'
 1877    ->rportray(T1, Opt)
 1878    ; rportray_head_tail(E, T1, Opt)
 1879    ).
 1880% Better formatting:
 1881rportray((:- Decl), Opt) :-
 1882    !,
 1883    offset_pos('$OUTPOS', Pos),
 1884    write(':- '),
 1885    merge_options([priority(1200)], Opt, Opt1),
 1886    option(module(M), Opt),
 1887    ( Decl =.. [Name, Arg],
 1888      once(( current_op(OptPri, Type, M:Name),
 1889             valid_op_type_arity(Type, 1)
 1890           )),
 1891      option(priority(Pri), Opt),
 1892      OptPri =< Pri
 1893    ->NDecl =.. [Name, '$NL'('$BODY'(Arg), Pos+4)]
 1894    ; NDecl = Decl
 1895    ),
 1896    write_term(NDecl, Opt1).
 1897rportray(OperTerm, Opt) :-
 1898    \+ retract(rportray_skip),
 1899    nonvar(OperTerm),
 1900    ( OperTerm =.. [Op, _],
 1901      option(module(M), Opt),
 1902      current_op(_, fx, M:Op),
 1903      sub_string(Op, _, 1, 0, Char1),
 1904      char_type(Char1, prolog_symbol),
 1905      assertz(rportray_skip),
 1906      string_term(OperTerm, Opt, Text),
 1907      atom_concat(Op, Right, Text),
 1908      sub_string(Right, 0, 1, _, Char2),
 1909      char_type(Char2, prolog_symbol)
 1910    ->write_t(Op, Opt),
 1911      write(' '),
 1912      write_t(Right, Opt)
 1913    ; fail
 1914    ),
 1915    !.
 1916rportray(Operator, Opt) :-
 1917    % Fix to avoid useless operator parenthesis
 1918    atom(Operator),
 1919    option(module(M), Opt),
 1920    option(priority(Priority), Opt),
 1921    current_op(OpPriority, _, M:Operator),
 1922    OpPriority < Priority,
 1923    !,
 1924    write_q(Operator, Opt).
 1925rportray(String, Options) :-
 1926    string(String),
 1927    String \= "",
 1928    !,
 1929    rportray_string(String, Options).
 1930% Better formatting:
 1931rportray(Term, OptL) :-
 1932    callable(Term),
 1933    \+ escape_term(Term),
 1934    \+ ctrl(Term),
 1935    \+ skip_format(Term),
 1936    option(module(M), OptL),
 1937    ( ( compact_format(Term)
 1938      ; term_arithexpression(Term, M)
 1939      )
 1940    ->Space = ''
 1941    ; Space = ' '
 1942    ),
 1943    option(term_width(TermWidth), OptL),
 1944    ( Term =.. [Name, Left, Right],
 1945      current_op(OptPri, Type, M:Name),
 1946      valid_op_type_arity(Type, 2)
 1947    ->option(priority(Pri), OptL),
 1948      ( OptPri > Pri
 1949      ->Display = yes
 1950      ; Display = no
 1951      ),
 1952      term_priority_gnd(Term, M, 1, LP),
 1953      merge_options([priority(LP)], OptL, OptL1),
 1954      cond_display(Display, '('),
 1955      offset_pos('$OUTPOS', Pos),
 1956      write_term(Left, OptL1),
 1957      write_space(Space),
 1958      offset_pos('$OUTPOS', Pos2),
 1959      term_priority_gnd(Term, M, 2, RP),
 1960      merge_options([priority(RP)], OptL, OptL2),
 1961      write_pos_lines(Pos2,
 1962                      ( write_q(Name, OptL2),
 1963                        write_space(Space),
 1964                        write_term(Right, OptL2)
 1965                      ), Lines),
 1966      ( Lines = [Line],
 1967        atom_length(Line, Width),
 1968        Width =< TermWidth
 1969      ->pos_indent(Pos2, Indent),
 1970        atom_concat(Indent, Atom, Line),
 1971        write_t(Atom, OptL2)
 1972      ; write_pos_lines(Pos,
 1973                        ( write_q(Name, OptL2),
 1974                          write_space(Space),
 1975                          write_term(Right, OptL2)
 1976                        ), Lines2),
 1977        ( ( maplist(string_length, Lines, WidthL),
 1978            max_list(WidthL, Width),
 1979            Width > TermWidth
 1980          ; length(Lines2, Height2),
 1981            length(Lines,  Height),
 1982            Height2 < Height
 1983          )
 1984        ->nl,
 1985          atomic_list_concat(Lines2, '\n', Atom)
 1986        ; Lines = [Line1|Tail],
 1987          pos_indent(Pos2, Indent),
 1988          atom_concat(Indent, Line, Line1),
 1989          atomic_list_concat([Line|Tail], '\n', Atom)
 1990        ),
 1991        write_t(Atom, OptL2)
 1992      ),
 1993      cond_display(Display, ')')
 1994    ; \+ atomic(Term),
 1995      Term =.. [Name|Args],
 1996      Args = [_, _|_]
 1997      % There is no need to move the argument to another line if the arity is 1,
 1998      % however that could change in the future if we change the format
 1999      % \+ ( Args = [_],
 2000      %      current_op(_, Type, M:Name),
 2001      %      valid_op_type_arity(Type, 1)
 2002      %    )
 2003    ->atom_length(Name, NL),
 2004      offset_pos('$OUTPOS'+NL+1, Pos),
 2005      merge_options([priority(999)], OptL, Opt1),
 2006      maplist(write_term_lines(Pos, Opt1), Args, LinesL),
 2007      pos_indent(Pos, Indent),
 2008      foldl(collect_args(Indent, TermWidth), LinesL, (Pos-2)-[_|T], _-[]),
 2009      atomic_list_concat(T, Atom),
 2010      write_q(Name, Opt1),
 2011      write(''),
 2012      write_t('(',  Opt1),
 2013      write_t(Atom, Opt1),
 2014      write_t(')',  Opt1)
 2015    ),
 2016    !.
 2017
 2018rportray_conj(A, B, Opt) :-
 2019    sequence_list((A, B), AL, []),
 2020    exclude(==('$RM'), AL, L),
 2021    once(append(T, [Last], L)),
 2022    offset_pos('$OUTPOS', Pos),
 2023    term_priority((_, _), user, 1, Priority),
 2024    option(priority(Pri), Opt),
 2025    ( Priority >= Pri
 2026    ->Display = yes
 2027    ; Display = no
 2028    ),
 2029    merge_options([priority(Priority)], Opt, Opt1),
 2030    term_priority((_, _), user, 2, RPri),
 2031    merge_options([priority(RPri)], Opt, Opt2),
 2032    ( ( Display = yes
 2033      ->Format ="(~s~s)",
 2034        succ(Pos, Pos1)
 2035      ; Format = "~s~s",
 2036        Pos1 = Pos
 2037      ),
 2038      length(L, Length),
 2039      pos_indent(Pos1, Indent),
 2040      maplist([Pos1, Opt1, Indent] +\ E^Line^( write_term_lines(Pos1, Opt1, E, Lines),
 2041                                               Lines = [Line1],
 2042                                               string_concat(Indent, Line, Line1)
 2043                                             ), T, LineL1),
 2044      write_term_lines(Pos1, Opt2, Last, LastLines1),
 2045      LastLines1 = [LastLine1],
 2046      atom_concat(Indent, LastLine, LastLine1),
 2047      append(LineL1, [LastLine], StringL),
 2048      maplist(string_length, StringL, WidthL),
 2049      sum_list(WidthL, WidthTotal),
 2050      Sep = ", ",
 2051      string_length(Sep, SepLength),
 2052      option(conj_width(ConjWidth), Opt),
 2053      Pos1 + WidthTotal + (Length - 1) * SepLength < ConjWidth
 2054    ->CloseB = ""
 2055    ; ( Display = yes
 2056      ->Format = "( ~s~s)",
 2057        Pos1 = Pos + 2,
 2058        with_output_to_string(
 2059            CloseB,
 2060            ( nl,
 2061              line_pos(Pos)
 2062            ))
 2063      ; Format = "~s~s",
 2064        CloseB = "",
 2065        Pos1 = Pos
 2066      ),
 2067      maplist(write_term_string(Pos1, Opt1), T, StringL1),
 2068      write_term_string(Pos1, Opt2, Last, LastStr),
 2069      append(StringL1, [LastStr], StringL),
 2070      sep_nl(Pos1, ',', Sep)
 2071    ),
 2072    atomics_to_string(StringL, Sep, S),
 2073    format(atom(Atom), Format, [S, CloseB]),
 2074    write_t(Atom, Opt1).
 2075
 2076rportray_head_tail(E, T1, Opt) :-
 2077    offset_pos('$OUTPOS', Pos),
 2078    succ(Pos, Pos1),
 2079    H = [_|_],
 2080    append(H, T2, [E|T1]),
 2081    ( nonvar(T2),
 2082      T2 = '$sb'(OTermPos, ITermPos, _, _, Term),
 2083      is_list(Term),
 2084      compound(OTermPos),
 2085      !,
 2086      arg(1, OTermPos, TFrom),
 2087      arg(2, OTermPos, TTo),
 2088      arg(1, ITermPos, From),
 2089      arg(2, ITermPos, To),
 2090      write_term_string(Pos, Opt, T2, SB),
 2091      sub_string(SB, 1, _, 1, SC),
 2092      option(text(Text), Opt),
 2093      get_subtext(Text, TFrom, From, SL),
 2094      get_subtext(Text, To, TTo, SR),
 2095      format(atom(ST), "~s~s~s", [SL, SC, SR]),
 2096      ( ( Term == []
 2097        ; Term == '$RM'
 2098        )
 2099      ->T = H,
 2100        EndText = ST
 2101      ; append(H, ['$TEXT'(ST)], T),
 2102        EndText = ""
 2103      )
 2104    ; T2 == [],
 2105      T = H,
 2106      EndText = ""
 2107    ; once(( var(T2)
 2108           ; T2 \= [_|_]
 2109           )),
 2110      T = H,
 2111      write_term_string(Pos1, Opt, T2, ST),
 2112      atom_concat('|', ST, EndText)
 2113    ),
 2114    !,
 2115    write_t('[', Opt),
 2116    term_priority([_|_], user, 1, Priority),
 2117    merge_options([priority(Priority)], Opt, Opt1),
 2118    subtract(T, ['$RM'], [Elem|Tail]),
 2119    write_pos_rawstr(Pos1, write_term(Elem, Opt1), String),
 2120    pos_indent(Pos1, Indent),
 2121    option(list_width(ListWidth), Opt),
 2122    foldl(concat_list_elem(ListWidth, Pos1, Opt1), Tail, String-LinesLL, Last-[Last]),
 2123    ( LinesLL = [S1]
 2124    ->CloseB = "]"
 2125    ; with_output_to_string(
 2126          CloseB,
 2127          ( nl,
 2128            line_pos(Pos),
 2129            write(']')
 2130          )),
 2131      with_output_to(string(Sep), writeln(',')),
 2132      atomic_list_concat(LinesLL, Sep, S1)
 2133    ),
 2134    atom_concat(Indent, S, S1),
 2135    atomic_list_concat([S, EndText, CloseB], Atom),
 2136    write_t(Atom, Opt1).
 2137
 2138concat_list_elem(ListWidth, Pos, Opt1, Elem, String1-LinesL1, String-LinesL) :-
 2139    ( with_output_to_string(
 2140          String, Pos1, Pos2, true,
 2141          ( write(String1),
 2142            write(', '),
 2143            write_term(Elem, Opt1)
 2144          )),
 2145      stream_position_data(line_count, Pos1, L1),
 2146      stream_position_data(line_count, Pos2, L2),
 2147      stream_position_data(char_count, Pos2, B2),
 2148      L1 = L2,
 2149      B2 =< ListWidth
 2150    ->LinesL1 = LinesL
 2151    ; write_pos_rawstr(Pos, write_term(Elem, Opt1), String),
 2152      LinesL1 = [String1|LinesL]
 2153    ).
 2154
 2155write_space(Space) :-
 2156    ( Space = ''
 2157    ->true
 2158    ; write(Space)
 2159    ).
 2160
 2161trim_brackets(L, _, _) :- var(L), !, fail.
 2162trim_brackets(Term, Trim, Opt) :-
 2163    member(Term-Trim, ['$@'(L, E)-'$@'(T, E),
 2164                       '@@'(L, E)-'@@'(T, E)
 2165                      ]),
 2166    neck,
 2167    trim_brackets(L, T, Opt).
 2168trim_brackets('$sb'(OTermPos, ITermPos, RepL1, Priority, Term),
 2169              '$sb'(OTermPos, ITermPos, RepL,  Priority, Term), _) :-
 2170    once(( ITermPos = list_position(From, To, _, _)
 2171         ; ITermPos = sub_list_position(From, To, _, _, _, _, _)
 2172         ; ITermPos = From-To,
 2173           Term == []
 2174         )),
 2175    succ(From, From1),
 2176    succ(To1, To),
 2177    sort(['$sb'(From-From1, '$NOOP'),
 2178          '$sb'(To1-To, '$NOOP')
 2179          |RepL1], RepL).
 2180trim_brackets(L, '$TEXT'(S), Opt) :-
 2181    L = [_|_],
 2182    string_term(L, Opt, S1),
 2183    sub_string(S1, 1, _, 1, S).
 2184
 2185pos_indent(Pos, Indent) :- with_output_to(atom(Indent), line_pos(Pos)).
 2186
 2187collect_args(Indent, TermWidth, LineL, Pos1-[Sep, String|Tail], Pos-Tail) :-
 2188    ( LineL = [Line1],
 2189      string_concat(Indent, String, Line1),
 2190      string_length(String, Width),
 2191      Pos is Pos1 + 2 + Width,
 2192      Pos < TermWidth
 2193    ->Sep = ", "
 2194    ; atom_concat(',\n', Indent, Sep),
 2195      last(LineL, Last),
 2196      string_length(Last, Pos),
 2197      once(( ( atomic_list_concat([Indent, '\n', Indent], IndentNl)
 2198             ; IndentNl = Indent
 2199             ),
 2200             atomics_to_string(LineL, '\n', String1),
 2201             string_concat(IndentNl, String, String1)
 2202           ))
 2203    ).
 2204
 2205pos_value(Pos, Value) :-
 2206    ( rportray_pos(Pos, Value)
 2207    ->true
 2208    ; Pos == '$OUTPOS'
 2209    ->get_output_position(Value)
 2210    ; fail
 2211    ).
 2212
 2213term_arithexpression(X, M) :-
 2214    substitute(sanitize_hacks, X, Y),
 2215    compat_arithexpression(Y, M).
 2216
 2217sanitize_hacks(Term, Into) :-
 2218    nonvar(Term),
 2219    memberchk(Term, ['$sb'(_, _), '$sb'(_, _, _, _, Into)]).
 2220
 2221compat_arithexpression(X, _) :- var(X), !.
 2222compat_arithexpression(X, _) :- number(X), !.
 2223compat_arithexpression(X, M) :- arithmetic:evaluable(X, M), !.
 2224compat_arithexpression(X, M) :-
 2225    callable(X),
 2226    current_arithmetic_function(X),
 2227    forall((compound(X), arg(_, X, V)), compat_arithexpression(V, M)).
 2228
 2229arithexpression(X) :- number(X), !.
 2230arithexpression(X) :-
 2231    callable(X),
 2232    current_arithmetic_function(X),
 2233    forall((compound(X), arg(_, X, V)), arithexpression(V)).
 2234
 2235offset_pos(Offs, Pos) :-
 2236    substitute(pos_value, Offs, Expr),
 2237    arithexpression(Expr),
 2238    catch(Pos is round(Expr), _, fail).
 2239
 2240rportray_list_nl(L, WB, Pos, Opt) :-
 2241    rportray_list_nl_comma(L, WB, Pos, Opt).
 2242
 2243rportray_list_nl_comma(L, WB, Pos, Opt) :-
 2244    rportray_list_nl(',', L, WB, Pos, Opt).
 2245
 2246rportray_list_nl(Pre, L, WB, Pos, Opt) :-
 2247    sep_nl(Pos, Pre, Sep),
 2248    rportray_list(L, WB, write_term, Sep, Opt).
 2249
 2250rportray_list(L, WB, Writer, SepElem, Opt) :-
 2251    option(text(Text), Opt),
 2252    deref_substitution(L, D),
 2253    term_write_sep_list_2(D, WB, Writer, Text, SepElem, '|', Opt).
 2254
 2255term_write_sep_list_2([], nb, _, _, _, _, _) :- !.
 2256term_write_sep_list_2([E|T], WB, Writer, Text, SepElem, SepTail, Opt) :-
 2257    !,
 2258    term_priority([_|_], user, 1, Priority),
 2259    merge_options([priority(Priority)], Opt, Opt1),
 2260    with_output_to_string(
 2261        RawText1,
 2262        ( write(SepElem),
 2263          call(Writer, E, Opt1),
 2264          term_write_sep_list_inner(T, Writer, Text, SepElem, SepTail, Opt1)
 2265        )),
 2266    atom_concat(SepElem, RawText2, RawText1),
 2267    string_length(RawText1, Length),
 2268    ( seek1_char_left(RawText2, '\n', Length, RTTo),
 2269      sub_string(RawText2, RTTo, _, 0, ToTrim),
 2270      string_chars(ToTrim, Chars),
 2271      forall(member(Char, Chars), char_type(Char, space))
 2272    ->sub_string(RawText2, 0, RTTo, _, RawText)
 2273    ; RawText = RawText2
 2274    ),
 2275    ( sub_string(RawText, _, _, _, '\n')
 2276    ->cond_ident_bracket(WB, '['),
 2277      print_text(RawText),
 2278      cond_idend_bracket(WB, ']')
 2279    ; cond_nonid_bracket(WB, '['),
 2280      print_text(RawText),
 2281      cond_nonid_bracket(WB, ']')
 2282    ).
 2283/*
 2284term_write_sep_list_2([E|T], WB, Writer, Text, SepElem, SepTail, Opt) :-
 2285    !,
 2286    term_priority([_|_], user, 1, Priority),
 2287    merge_options([priority(Priority)], Opt, Opt1),
 2288    cond_ident_bracket(WB, '['),
 2289    call(Writer, E, Opt1),
 2290    term_write_sep_list_inner(T, Writer, Text, SepElem, SepTail, Opt1),
 2291    cond_idend_bracket(WB, ']').
 2292*/
 2293term_write_sep_list_2(E, _, Writer, _, _, _, Opt) :- call(Writer, E, Opt).
 2294
 2295cond_ident_bracket(wb(Delta, _), Bracket) :-
 2296    write(Bracket),
 2297    forall(between(2,Delta,_), write(' ')).
 2298cond_ident_bracket(nb, _).
 2299
 2300cond_idend_bracket(wb(Delta, Pos), Bracket) :-
 2301    sep_nl(Pos-Delta, '', SepNl),
 2302    write(SepNl),
 2303    write(Bracket).
 2304cond_idend_bracket(nb, _).
 2305
 2306cond_nonid_bracket(wb(_, _), Bracket) :- write(Bracket).
 2307cond_nonid_bracket(nb, _).
 2308
 2309term_write_sep_list_inner(L, Writer, Text, SepElem, SepTail, Opt) :-
 2310    nonvar(L),
 2311    L = [E|T],
 2312    !,
 2313    write(SepElem),
 2314    call(Writer, E, Opt),
 2315    term_write_sep_list_inner(T, Writer, Text, SepElem, SepTail, Opt).
 2316term_write_sep_list_inner(P, Writer, Text, SepElem, _, Opt) :-
 2317    nonvar(P),
 2318    deref_substitution(P, L),
 2319    L = [_|_],
 2320    !,
 2321    P = '$sb'(SubPos1, ISubPos, RepL, Priority, Term),
 2322    SubPos1 =.. [SPF, From1, To1|SPT],
 2323    string_length(Text, N),
 2324    seekn_char_right(1, Text, N, "[", From1, From2),
 2325    % Remove space, since default indentation of list elements is 2:
 2326    ( sub_string(Text, From2, 1, _, " ")
 2327    ->succ(From2, From)
 2328    ; From = From2
 2329    ),
 2330    seek1_char_left(Text, "]", To1, To),
 2331    SubPos =.. [SPF, From, To|SPT],
 2332    P2 = '$sb'(SubPos, ISubPos, RepL, Priority, Term),
 2333    write(SepElem),
 2334    call(Writer, P2, Opt).
 2335term_write_sep_list_inner(T, Writer, Text, SepElem, SepTail, Opt) :-
 2336    get_pred(T, F),
 2337    write_tail(T, F, Writer, Text, SepElem, SepTail, Opt).
 2338
 2339term_write_sep_list_3([E|T], Writer, Text, SepElem, SepTail, Opt) :-
 2340    !,
 2341    call(Writer, E, Opt),
 2342    get_pred(E, D),
 2343    term_write_sep_list_inner_3(T, D, Writer, Text, SepElem, SepTail, Opt).
 2344term_write_sep_list_3(E, Writer, _, _, _, Opt) :-
 2345    call(Writer, E, Opt).
 2346
 2347get_pred(T, F/A) :-
 2348    deref_substitution(T, C),
 2349    once(clause_head(C, H)),
 2350    deref_substitution(H, D),
 2351    functor(D, F, A).
 2352
 2353clause_head(H :-  _, H).
 2354clause_head(H --> _, H).
 2355clause_head(H,       H).
 2356
 2357
 2358term_write_sep_list_inner_3(L, D, Writer, Text, SepElem, SepTail, Opt) :-
 2359    nonvar(L),
 2360    L = [E|T],
 2361    !,
 2362    write(SepElem),
 2363    get_pred(E, F),
 2364    ignore((D \= F, nl)),
 2365    call(Writer, E, Opt),
 2366    term_write_sep_list_inner_3(T, F, Writer, Text, SepElem, SepTail, Opt).
 2367term_write_sep_list_inner_3(T, D, Writer, Text, SepElem, SepTail, Opt) :-
 2368    write_tail(T, D, Writer, Text, SepElem, SepTail, Opt).
 2369
 2370term_write_comma_2(Opt, Term) :- write_term(Term, Opt), write(', ').
 2371
 2372sep_nl(LinePos, Sep, SepNl) :-
 2373    with_output_to(atom(In), line_pos(LinePos)),
 2374    atomic_list_concat([Sep, '\n', In], SepNl).
 2375
 2376write_tail(T, _, Writer, _, _, SepTail, Opt) :-
 2377    var(T),
 2378    !,
 2379    write(SepTail),
 2380    call(Writer, T, Opt).
 2381write_tail([], _, _, _, _, _, _) :- !.
 2382write_tail('$LIST,NL'(L), _, Writer, Text, _, _, Opt) :-
 2383    !,
 2384    offset_pos('$OUTPOS', Pos),
 2385    sep_nl(Pos, ',', Sep),
 2386    term_write_sep_list_inner(L, Writer, Text, Sep, '|', Opt).
 2387write_tail('$LIST,NL'(L, Offs), _, Writer, Text, _, _, Opt) :-
 2388    offset_pos(Offs, Pos),
 2389    !,
 2390    sep_nl(Pos, ',', Sep),
 2391    term_write_sep_list_inner(L, Writer, Text, Sep, '|', Opt).
 2392write_tail(T, D, Writer, _, _, SepTail, Opt) :-
 2393    get_pred(T, F),
 2394    write(SepTail),
 2395    ignore((D \= F, nl)), % this only makes sense on list of clauses
 2396    call(Writer, T, Opt).
 2397
 2398print_expansion_rm_dot(Text, Before, To) :-
 2399    sub_string(Text, Before, _, 0, Right),
 2400    once(sub_string(Right, Next, _, _, ".")),
 2401    To is Before+Next+2.
 2402
 2403% Hacks that can only work at 1st level:
 2404
 2405print_expansion_1(Into, Term, TermPos, Options, Text, To, To) :-
 2406    var(Into),
 2407    !,
 2408    print_expansion(Into, Term, TermPos, Options, Text).
 2409print_expansion_1('$RM', _, _, _, _, To, To) :- !.
 2410print_expansion_1('$C'(Goal, Into), Term, TermPos, Options, Text, To, To) :-
 2411    \+ ( nonvar(Term),
 2412         Term = '$C'(_, _)
 2413       ),
 2414    !,
 2415    call(Goal),
 2416    print_expansion_1(Into, Term, TermPos, Options, Text, To, To).
 2417print_expansion_1('$TEXT'(Into), _, _, Options, _, To, To) :-
 2418    !,
 2419    write_t(Into, Options).
 2420print_expansion_1('$TEXT'(Into, Offs), _, _, Options, _, To1, To) :-
 2421    offset_pos(Offs, Pos),
 2422    !,
 2423    write_t(Into, Options),
 2424    To is To1+Pos.
 2425print_expansion_1('$TEXTQ'(Into), _, _, Options, _, To, To) :-
 2426    !,
 2427    write_q(Into, Options).
 2428print_expansion_1('$TEXTQ'(Into, Offs), _, _, Options, _, To1, To) :-
 2429    offset_pos(Offs, Pos),
 2430    !,
 2431    write_q(Into, Options),
 2432    To is To1+Pos.
 2433print_expansion_1('$LISTC'(IntoL), _, _, Options1, Text, To, To) :-
 2434    !,
 2435    merge_options([priority(1200), portray_clause(true)], Options1, Options),
 2436    term_write_sep_list_3(IntoL, rportray_clause, Text, '.\n', '.\n', Options).
 2437print_expansion_1('$LISTC.NL'(IntoL), _, _, Options1, Text, To, To) :-
 2438    !,
 2439    merge_options([priority(1200), portray_clause(true)], Options1, Options),
 2440    term_write_sep_list_3(IntoL, rportray_clause, Text, '.\n', '.\n', Options),
 2441    write('.\n').
 2442print_expansion_1(Into, Term, TermPos, Options, Text, To1, To) :-
 2443    print_expansion_2(Into, Term, TermPos, Options, Text, To1, To).
 2444
 2445print_expansion_2(Into, Term, TermPos, Options, Text, To, To) :-
 2446    var(Into),
 2447    !,
 2448    print_expansion(Into, Term, TermPos, Options, Text).
 2449print_expansion_2('$sb'(_, RefPos, RepL, Priority, Into), Term, _, Options, Text, To, To) :-
 2450    nonvar(RefPos),
 2451    \+ ( nonvar(Term),
 2452         Term = '$sb'(_, _, _, _, _),
 2453         Into \= '$sb'(_, _, _, _, _)
 2454       ),
 2455    !,
 2456    print_subtext_sb_2(Into, RefPos, RepL, Priority, Text, Options).
 2457print_expansion_2('$NODOT'(Into), Term, TermPos, Options, Text, To1, To) :-
 2458    !,
 2459    print_expansion_2(Into, Term, TermPos, Options, Text, To1, _),
 2460    print_expansion_rm_dot(Text, To1, To).
 2461print_expansion_2('$LIST.NL'(IntoL), Term, TermPos, Options1, Text, To1, To) :-
 2462    !,
 2463    merge_options([priority(1200)], Options1, Options),
 2464    print_expansion_rm_dot(Text, To1, To),
 2465    term_write_stop_nl_list(IntoL, Term, TermPos, Options, Text).
 2466print_expansion_2(Into, Term, Pos, Options, Text, To, To) :-
 2467    % Hey, this is the place, don't overthink about it (test 60)
 2468    Pos = sub_list_position(_, _, _, From1, STo, PosL, Tail),
 2469    !,
 2470    refactor_context(from, From),
 2471    print_subtext(From-From1, Text),
 2472    ( Into == []
 2473    ->true
 2474    ; Into == '$RM'
 2475    ->true
 2476    ; ( is_list(Into)
 2477      ->true
 2478      ; ( get_subtext(From1-STo, Text, Sep1),
 2479          option(comments(Comments), Options, []),
 2480          replace_sep(",", "|", From1, Comments, Sep1, Sep)
 2481        ->print_text(Sep)
 2482        ; write('|') % just in case, but may be never reached
 2483        )
 2484      ),
 2485      with_from(print_expansion(Into, Term, list_position(From1, To, PosL, Tail), Options, Text), From1)
 2486    ),
 2487    ( is_list(Into),
 2488      Into \== []
 2489    ->true
 2490    ; last(PosL, Pos2),
 2491      arg(2, Pos2, To2),
 2492      print_subtext(To2-To, Text)
 2493    ).
 2494print_expansion_2(Into, Term, TermPos, Options, Text, To, To) :-
 2495    print_expansion(Into, Term, TermPos, Options, Text).
 2496
 2497term_write_stop_nl_list([Into|IntoL], Term, TermPos, Options, Text) :-
 2498    term_write_stop_nl__(Into, Term, TermPos, Options, Text),
 2499    term_write_stop_nl_list(IntoL, Term, TermPos, Options, Text).
 2500term_write_stop_nl_list('$sb'(_, _, _, _, IntoL), Term, TermPos, Options, Text) :-
 2501    term_write_stop_nl_list(IntoL, Term, TermPos, Options, Text).
 2502term_write_stop_nl_list([], _, _, _, _).
 2503
 2504term_write_stop_nl__('$NOOP'(Into), Term, TermPos, Options, Text) :- !,
 2505    with_output_to(string(_),   %Ignore, but process
 2506                   term_write_stop_nl__(Into, Term, TermPos, Options, Text)).
 2507term_write_stop_nl__('$NODOT'(Into), Term, TermPos, Options, Text) :- !,
 2508    print_expansion(Into, Term, TermPos, Options, Text).
 2509term_write_stop_nl__(Into, Term, TermPos, Options, Text) :-
 2510    print_expansion(Into, Term, TermPos, Options, Text),
 2511    write('.'),
 2512    nl.
 2513
 2514% if the term have been in parentheses, in a place where that was
 2515% required, include it!!!
 2516%
 2517fix_position_if_braced(term_position(_, _, _, _, _), M,
 2518                       Term, GPriority, Into, Priority, Display) :-
 2519    ( \+ term_needs_braces(M:Term, GPriority),
 2520      ( nonvar(Into),
 2521        term_needs_braces(M:Into, Priority)
 2522        % \+ term_needs_braces(M:Term, Priority)
 2523      )
 2524    ->Display = yes
 2525    ),
 2526    !.
 2527fix_position_if_braced(_, _, _, _, _, _, no). % fail-safe
 2528
 2529% If Term is a replacement, '$sb'/6, we assume that the substitution will not
 2530% require braces (not sure if this is correct, but it works)
 2531term_needs_braces(_:Term, _) :- \+ callable(Term), !, fail.
 2532% term_needs_braces(M:'$sb'(_, _, _, _, _, Into), Pri) :- !,
 2533%     term_needs_braces(M:Into, Pri).
 2534term_needs_braces(M:Term, Pri) :- term_needs_braces(Term, M, Pri).
 2535
 2536term_needs_braces(Term, M, Pri) :-
 2537    functor(Term, Name, Arity),
 2538    valid_op_type_arity(Type, Arity),
 2539    current_op(OpPri, Type, M:Name),
 2540    OpPri > Pri,
 2541    !.
 2542
 2543cond_display(yes, A) :- write(A).
 2544cond_display(no, _).
 2545
 2546:- meta_predicate
 2547    with_cond_braces(5, +, +, +, +, +, +). 2548
 2549print_expansion_sb(Into, Term, TermPos, Priority, Options, Text) :-
 2550    with_cond_braces(do_print_expansion_sb, Into, Term, TermPos, Priority, Options, Text).
 2551
 2552do_print_expansion_sb(Into, Term, TermPos, Options, Text) :-
 2553    arg(1, TermPos, From),
 2554    with_from(print_expansion_ne(Into, Term, TermPos, Options, Text), From).
 2555
 2556with_cond_braces(Call, Into, Term, TermPos, GPriority, Options, Text) :-
 2557    option(module(M), Options),
 2558    option(priority(Priority), Options),
 2559    fix_position_if_braced(TermPos, M, Term, GPriority, Into, Priority, Display),
 2560    cond_display(Display, '('),
 2561    call(Call, Into, Term, TermPos, Options, Text),
 2562    cond_display(Display, ')').
 2563
 2564% TODO: stream position would be biased --EMM
 2565with_str_hook(Command, StrHook) :-
 2566    with_output_to_string(S1, Command),
 2567    ( call(StrHook, S1, S)
 2568    ->true
 2569    ; S = S1
 2570    ),
 2571    format('~s', [S]).
 print_expansion(?Into:term, ?Term:Term, RefPos, Priority:integer, Options:list, Text:string) is det
 2575print_expansion(Var, _, RefPos, Options, Text) :-
 2576    var(Var),
 2577    !,
 2578    option(new_variable_names(VNL), Options, []),
 2579    ( member(Name=Var1, VNL),
 2580      Var1 == Var
 2581    ->write(Name)
 2582    ; print_subtext(RefPos, Text)
 2583    ).
 2584print_expansion('$sb'(RefPos, _), Term, _, _, Text) :-
 2585    \+ ( nonvar(Term),
 2586         Term = '$sb'(_, _)
 2587       ),
 2588    !,
 2589    print_subtext(RefPos, Text).
 2590print_expansion('$sb'(RefPos, _, RepL, Priority, Into), Term, _RPos, Options, Text) :-
 2591    nonvar(RefPos),
 2592    \+ ( nonvar(Term),
 2593         Term = '$sb'(_, _, _, _, _),
 2594         Into \= '$sb'(_, _, _, _, _)
 2595       ),
 2596    !,
 2597    print_subtext_sb_2(Into, RefPos, RepL, Priority, Text, Options).
 2598print_expansion(Into, Term, RefPos, Options, Text) :-
 2599    print_expansion_ne(Into, Term, RefPos, Options, Text).
 2600
 2601print_expansion_ne('$G'(Into, Goal), Term, RefPos, Options, Text) :-
 2602    \+ ( nonvar(Term),
 2603         Term = '$G'(_, _)
 2604       ),
 2605    !,
 2606    with_str_hook(print_expansion(Into, Term, RefPos, Options, Text), Goal).
 2607print_expansion_ne('$C'(Goal, Into), Term, RefPos, Options, Text) :-
 2608    \+ ( nonvar(Term),
 2609         Term = '$C'(_, _)
 2610       ),
 2611    !,
 2612    call(Goal),
 2613    print_expansion(Into, Term, RefPos, Options, Text).
 2614print_expansion_ne('$,NL', Term, RefPos, Options, Text) :-
 2615    Term \=='$,NL',
 2616    !,
 2618    write(','),
 2619    print_expansion('$NL', Term, RefPos, Options, Text)
 2619.
 2620print_expansion_ne('$NL', Term, _, _, Text) :- % Print an indented new line
 2621    Term \== '$NL',
 2622    !,
 2623    refactor_context(from, From),
 2624    textpos_line(Text, From, LinePos),
 2625    nl,
 2626    line_pos(LinePos).
 2627/*
 2628print_expansion_ne(Into, Term1, _, Options, Text) :-
 2629    nonvar(Term1),
 2630    Term1\='$sb'(_, _, _, _), % is not a read term, but a command
 2631    SPattern='$sb'(RefPos, _, _, Term, Pattern),
 2632    !,
 2633    print_expansion_ne(Into, Pattern, Term, RefPos, Options, Text).
 2634*/
 2635print_expansion_ne(Into, Term, RefPos, Options, Text) :-
 2636    ( \+ escape_term(Into),
 2637      print_expansion_pos(RefPos, Into, Term, Options, Text)
 2638    ->true
 2639    ; write_term(Into, Options)
 2640    ).
 2641
 2642print_expansion_arg(M, MInto, Options1, Text, From-To,
 2643                    v(N, RefPos, Into, Term), Freeze1, Freeze) :-
 2644    ( N = 0,
 2645      Into == Term
 2646    ->Freeze1 = true,
 2647      print_subtext(RefPos, Text),
 2648      freeze(Freeze, print_subtext(Text, From, To))
 2649    ; N = 1,
 2650      Into == '$RM',
 2651      Term \== '$RM'
 2652    ->Freeze1 = true
 2653    ; term_priority(MInto, M, N, Priority),
 2654      merge_options([priority(Priority)], Options1, Options),
 2655      print_expansion_elem(Options, Text, From-To, RefPos, Into, Term, Freeze1, Freeze)
 2656    ).
 2657
 2658print_expansion_elem(Options, Text, From-To, RefPos, Into, Term, Freeze1, Freeze) :-
 2659    ( Into == '$RM',
 2660      Term \== '$RM'
 2661    ->true
 2662    ; Freeze1 = true,
 2663      print_expansion(Into, Term, RefPos, Options, Text)
 2664    ),
 2665    freeze(Freeze, print_subtext(Text, From, To)).
 2666
 2667escape_term($@(_)).
 2668escape_term($$(_)).
 2669escape_term(\\(_)).
 2670escape_term(_@@_).
 2671escape_term(_$@_).
 2672% escape_term('$G'(_, _)).
 2673% escape_term('$C'(_, _)).
 2674escape_term('$NOOP'(_)).
 2675escape_term('$NODOT'(_)).
 2676escape_term('$LIST'(_)).
 2677escape_term('$LISTC'(_)).
 2678escape_term('$LIST,'(_)).
 2679escape_term('$LIST,_'(_)).
 2680escape_term('$LIST,NL'(_)).
 2681escape_term('$LIST,NL'(_, _)).
 2682escape_term('$NL'(_, _)).
 2683escape_term('$POS'(_, _)).
 2684escape_term('$SEEK'(_, _)).
 2685escape_term('$LISTC.NL'(_)).
 2686escape_term('$LISTB,NL'(_)).
 2687escape_term('$LISTB,NL'(_, _)).
 2688escape_term('$PRIORITY'(_, _)).
 2689escape_term('$TEXT'(_)).
 2690escape_term('$TEXT'(_, _)).
 2691escape_term('$TEXTQ'(_)).
 2692escape_term('$TEXTQ'(_, _)).
 2693escape_term('$PRETXT'(_, _)).
 2694escape_term('$POSTXT'(_, _)).
 2695escape_term('$CLAUSE'(_)).
 2696escape_term('$CLAUSE'(_, _)).
 2697escape_term('$BODY'(_, _)).
 2698escape_term('$BODY'(_)).
 2699escape_term('$BODYB'(_, _)).
 2700escape_term('$BODYB'(_)).
 2701
 2702special_term('$sb'(_, _)).
 2703special_term('$sb'(_, _, _, _, _)).
 2704
 2705valid_op_type_arity(xf,  1).
 2706valid_op_type_arity(yf,  1).
 2707valid_op_type_arity(xfx, 2).
 2708valid_op_type_arity(xfy, 2).
 2709valid_op_type_arity(yfx, 2).
 2710valid_op_type_arity(fy,  1).
 2711valid_op_type_arity(fx,  1).
 2712
 2713from_to_pairs([], _, To, To) --> [].
 2714from_to_pairs([To2-From2|PosL], From1, To1, To) -->
 2715    { (To2   = 0 -> To1  = From1 ; To1  = To2),
 2716      (From2 = 0 -> From = To1   ; From = From2)
 2717    },
 2718    [From-To3],
 2719    from_to_pairs(PosL, From, To3, To).
 2720
 2721normalize_pos(Pos, F-T) :-
 2722    arg(1, Pos, F),
 2723    arg(2, Pos, T).
 2724
 2725not_sub_term(Into, Term) :-
 2726    \+ ( sub_term(Sub, Into),
 2727         Sub =@= Term
 2728       ).
 2729
 2730print_expansion_pos(term_position(From, To, FFrom, FFTo, PosT), Into, Term, Options, Text) :-
 2731    compound(Into),
 2732    Into \= [_|_],
 2733    \+ ( Into = (CA, CB),
 2734         ( CA == '$RM'
 2735         ; CB == '$RM'
 2736         )
 2737       ),
 2738    nonvar(Term),
 2739    functor(Into, FT, A),
 2740    functor(Term, FP, A),
 2741    % It is akward to follow the layout of Term if it is part of Into:
 2742    not_sub_term(Into, Term),
 2743    option(module(M), Options),
 2744    ( option(priority(Priority), Options),
 2745      current_op(PrP, TypeOpP, M:FP),
 2746      valid_op_type_arity(TypeOpP, A),
 2747      current_op(PrT, TypeOpT, M:FT),
 2748      valid_op_type_arity(TypeOpT, A),
 2749      PrT =< Priority,
 2750      ( PrP =< PrT
 2751      ; forall(arg(AP, Into, Arg),
 2752               ( term_priority_gnd(Into, M, AP, PrA),
 2753                 \+ term_needs_braces(M:Arg, PrA)
 2754               ))
 2755      )
 2756    ; option(module(M), Options),
 2757      \+ current_op(_, _, M:FT),
 2758      \+ current_op(_, _, M:FP)
 2759    ),
 2760    ( FT == FP
 2761    ->NT = FT % preserve layout
 2762    ; NT = '$TEXTQ'(FT)
 2763    ),
 2764    !,
 2765    mapilist([Into, Term] +\ N^Pos^(PosK-v(N, Pos, Arg, TAr))^
 2766            ( arg(N, Into, Arg),
 2767              arg(N, Term, TAr),
 2768              normalize_pos(Pos, PosK)
 2769            ), 1, PosT, KPosValTU),
 2770    /* 0 is the functor, priority 1200 */
 2771    KPosValU = [(FFrom-FFTo)-v(0, FFrom-FFTo, NT, FP)|KPosValTU],
 2772    keysort(KPosValU, KPosValL),
 2773    pairs_keys_values(KPosValL, PosKL, ValL),
 2774    from_to_pairs(PosKL, From, To1, To2, FromToL, []),
 2775    succ(A, N),
 2776    nth1(N, PosKL, E),
 2777    arg(2, E, To2),
 2778    print_subtext(Text, From, To1),
 2779    foldl(print_expansion_arg(M, Into, Options, Text), FromToL, ValL, _, true),
 2780    print_subtext(Text, To2, To).
 2781print_expansion_pos(sub_list_position(BFrom, To, BTo, _, From, PosL, Tail), Into, Term, Options, Text) :-
 2782    print_subtext(Text, BFrom, BTo),
 2783    print_expansion_list(PosL, From, To, Tail, Into, Term, Options, Text, init).
 2784print_expansion_pos(list_position(From, To, PosL, Tail), Into, Term, Options, Text) :-
 2785    print_expansion_list(PosL, From, To, Tail, Into, Term, Options, Text, init).
 2786print_expansion_pos(brace_term_position(From, To, TermPos), {Into}, {Term}, Options1, Text) :-
 2787    arg(1, TermPos, AFrom),
 2788    arg(2, TermPos, ATo),
 2789    print_subtext(Text, From, AFrom),
 2790    merge_options([priority(1200)], Options1, Options),
 2791    print_expansion_elem(Options, Text, ATo-To, TermPos, Into, Term, _, true).
 2792print_expansion_pos(parentheses_term_position(From, To, TermPos), Into, Term, Options1, Text) :-
 2793    arg(1, TermPos, AFrom),
 2794    arg(2, TermPos, ATo),
 2795    print_subtext(Text, From, AFrom),
 2796    merge_options([priority(1200)], Options1, Options),
 2797    print_expansion_elem(Options, Text, ATo-To, TermPos, Into, Term, _, true).
 2798
 2799print_expansion_list(PosL, From, To, TPos, IntoL, TermL, Options1, Text, Cont) :-
 2800    ( ( IntoL = '$sb'(sub_list_position(_, To2, _, _, From2, PosL2, TPos2), _, RepL, Priority, Into),
 2801        PosL = [Pos|_],
 2802        arg(1, Pos, From1)
 2803      ->( Cont \= init_rm
 2804        ->print_subtext(Text, From, From1)
 2805        ; true
 2806        )
 2807      ; IntoL = '$sb'(list_position(From21, To2, PosL2, TPos2), _, RepL, Priority, Into),
 2808        ( Cont = cont,
 2809          PosL2 = [Pos2|_],
 2810          compound(Pos2),
 2811          arg(1, Pos2, From2)
 2812        ->write(', ')
 2813        ; From2 = From21
 2814        )
 2815      )
 2816    ->print_subtext_sb_2(Into, list_position(From2, To2, PosL2, TPos2), RepL, Priority, Text, Options1)
 2817    ; ( PosL = [Pos|PosT]
 2818      ->( normalize_pos(Pos, From1-To1),
 2819          IntoL = [Into|IT],
 2820          TermL = [Term|TT]
 2821        ->option(module(M), Options1),
 2822          term_priority([_|_], M, 1, Priority1),
 2823          select_option(priority(Priority), Options1, Options, Priority),
 2824          Options2=[priority(Priority1)|Options],
 2825          ( Into == '$RM',
 2826            Term \== '$RM'
 2827          ->( Cont = init
 2828            ->Cont2 = init_rm,
 2829              print_subtext(Text, From, From1)
 2830            ; Cont2 = Cont
 2831            )
 2832          ; ( Cont \= init_rm
 2833            ->print_subtext(Text, From, From1)
 2834            ; true
 2835            ),
 2836            print_expansion(Into, Term, Pos, Options2, Text),
 2837            Cont2 = cont
 2838          ),
 2839          print_expansion_list(PosT, To1, To, TPos, IT, TT, Options1, Text, Cont2)
 2840        ; memberchk(IntoL, [[], '$RM'])
 2841        ->arg(1, Pos, From1),
 2842          ( TPos = none
 2843          ->last(PosL, LPos),
 2844            arg(2, LPos, To1)
 2845          ; arg(2, TPos, To1)
 2846          ),
 2847          ( Cont = cont
 2848          ->true
 2849          ; print_subtext(Text, From, From1)
 2850          ),
 2851          print_subtext(Text, To1, To)
 2852        )
 2853      )
 2854    ->true
 2855    ; PosL = []
 2856    ->( TPos = none
 2857      ->( IntoL == []
 2858        ->true
 2859        ; ( Cont = cont
 2860          ->write('|')
 2861          ; true
 2862          ),
 2863          print_expansion(IntoL, TermL, From-From, Options1, Text)
 2864        ),
 2865        print_subtext(Text, From, To)
 2866      ; normalize_pos(TPos, From1-To1),
 2867        print_subtext(Text, From, From1),
 2868        print_expansion(IntoL, TermL, TPos, Options1, Text),
 2869        print_subtext(Text, To1, To)
 2870      )
 2871    ; write_term(IntoL, Options1)
 2872    ).
 2873
 2874replace_sep(S1, S2, From1, Comments, Text1, Text2) :-
 2875    sub_string(Text1, Before, _, After, S1),
 2876    \+ ( member(Pos-Comment, Comments),
 2877         stream_position_data(char_count, Pos, From2),
 2878         From is From2-From1,
 2879         string_length(Comment, Length),
 2880         To is From + Length,
 2881         Before > From,
 2882         Before < To
 2883       ),
 2884    !,
 2885    sub_string(Text1, 0, Before, _, L),
 2886    sub_string(Text1, _, After,  0, R),
 2887    atomics_to_string([L, S2, R], Text2).
 2888
 2889print_subtext(RefPos, Text) :-
 2890    get_subtext(RefPos, Text, SubText),
 2891    print_text(SubText).
 2892
 2893print_text(Text) :- format("~s", [Text]), write(''). % reset partial(true) logic
 2894
 2895print_subtext(Text, From, To) :-
 2896    get_subtext(Text, From, To, SubText),
 2897    print_text(SubText).
 2898
 2899get_subtext(RefPos, Text, SubText) :-
 2900    compound(RefPos),
 2901    arg(1, RefPos, From),
 2902    arg(2, RefPos, To),
 2903    get_subtext(Text, From, To, SubText).
 2904
 2905% get_subtext(Text1, Pos, From, To, Text) :-
 2906%     get_subtext(Text1, From-Pos, To-Pos, Text).
 2907
 2908get_subtext(Text1, From, To, Text) :-
 2909    arithexpression(From),
 2910    arithexpression(To),
 2911    LPaste is To-From,
 2912    From1 is max(0, From),
 2913    sub_string(Text1, From1, LPaste, _, Text).
 2914
 2915bin_op(Term, Op, Left, Right, A, B) :-
 2916    nonvar(Term),
 2917    functor(Term, Op, N),
 2918    N == 2,
 2919    prolog_listing:infix_op(Op, Left, Right),
 2920    arg(1, Term, A),
 2921    arg(2, Term, B).
 2922
 2923rportray_bodyb(B, Pos, OptL) :- write_b(B, OptL, Pos).
 2924
 2925rportray_body(B, Pos, OptL) :- write_b1(B, OptL, Pos).
 2926
 2927write_b(Term, OptL, Pos1) :-
 2928    ( option(priority(N), OptL),
 2929      option(module(M), OptL),
 2930      term_needs_braces(M:Term, N)
 2931    ->stream_property(current_output, position(S1)),
 2932      write_t('( ', OptL),
 2933      stream_property(current_output, position(S2)),
 2934      stream_position_data(char_count, S1, B1),
 2935      stream_position_data(char_count, S2, B2),
 2936      Pos is Pos1+B2-B1,
 2937      write_b1(Term, OptL, Pos),
 2938      nl,
 2939      line_pos(Pos - 2),
 2940      write_t(')', OptL)
 2941    ; write_b1(Term, OptL, Pos1)
 2942    ).
 2943
 2944and_layout(T) :- T = (_,_).
 2945
 2946write_b1(Term, OptL, Pos) :-
 2947    prolog_listing:or_layout(Term), !,
 2948    write_b_layout(Term, OptL, or,  Pos).
 2949write_b1(Term, OptL, Pos) :-
 2950    and_layout(Term), !,
 2951    write_b_layout(Term, OptL, and, Pos).
 2952write_b1(Term, OptL, _Pos) :-
 2953    option(module(M), OptL),
 2954    ( nonvar(Term),
 2955      has_meta(Term, M, 0, Spec)
 2956    ->body_meta_args(Term, Spec, TMeta)
 2957    ; TMeta = Term
 2958    ),
 2959    write_term(TMeta, OptL).
 2960
 2961has_meta(Term, _, _, _) :-
 2962    var(Term), !, fail.
 2963has_meta(M:Term, _, Meta, Spec) :- !,
 2964    has_meta(Term, M, Meta, Spec).
 2965has_meta(Term, M, Meta, Spec) :-
 2966    \+ memberchk(Term, ['$BODYB'(_),
 2967                        '$BODYB'(_, _)]),
 2968    predicate_property(M:Term, meta_predicate(Spec)),
 2969    ( findall(Arg,
 2970              ( arg(Idx, Spec, Meta),
 2971                arg(Idx, Term, Arg),
 2972                nonvar(Arg)
 2973              ), ArgL),
 2974      ( ArgL = [_, _, _|_]
 2975      ; member(Arg, ArgL),
 2976        has_meta(Arg, M, 0, _)
 2977      )
 2978    ->true
 2979    ; ctrl(Term)
 2980    ).
 2981
 2982body_meta_args(Term, Spec, Meta) :-
 2983    functor(Term, F, N),
 2984    functor(Meta, F, N),
 2985    mapnargs(body_meta_arg, Term, Spec, Meta).
 2986
 2987ctrl((_ ,   _)).
 2988ctrl((_ ;   _)).
 2989ctrl((_ ->  _)).
 2990ctrl((_ *-> _)).
 2991
 2992skip_format(_/_).
 2993skip_format(_//_).
 2994skip_format('$VAR'(_)).
 2995skip_format(_:_).
 2996
 2997compact_format(_-_).
 2998
 2999body_meta_arg(_, Term, Spec, Meta) :-
 3000    ( Spec = 0,
 3001      nonvar(Term)
 3002    ->Meta = '$BODYB'(Term)
 3003    ; Meta = Term
 3004    ).
 3005
 3006write_b_layout(Term, OptL1, Layout, Pos) :-
 3007    bin_op(Term, Op, Left, Right, A, B),
 3008    !,
 3009    merge_options([priority(Left)], OptL1, OptL2),
 3010    write_b(A, OptL2, Pos),
 3011    nl_indent(Layout, Op, Pos),
 3012    merge_options([priority(Right)], OptL1, OptL3),
 3013    write_b(B, OptL3, Pos).
 3014
 3015nl_indent(or, Op, LinePos) :-
 3016    nl,
 3017    line_pos(LinePos - 2),
 3018    format(atom(A), '~|~a~2+',[Op]),
 3019    % Kludge to reset logic of partial(true):
 3020    write(A).
 3021nl_indent(and, Op, LinePos) :-
 3022    writeln(Op),
 3023    line_pos(LinePos).
 3024
 3025line_pos(LinePos, Output) :-
 3026    ( setting(listing:tab_distance, N),
 3027      N =\= 0
 3028    ->Tabs is LinePos div N,
 3029      Spcs is Tabs + LinePos mod N
 3030    ; Tabs is 0,
 3031      Spcs is LinePos
 3032    ),
 3033    format(Output, "~`\tt~*|~` t~*|", [Tabs, Spcs]).
 3034
 3035line_pos(LinePos) :-
 3036    line_pos(LinePos, current_output),
 3037    fail.
 3038line_pos(_) :-
 3039    write('').
 3040
 3041write_t(Term, Options1) :-
 3042    write_qt(false, Term, Options1).
 3043
 3044write_q(Term, Options1) :-
 3045    write_qt(true, Term, Options1).
 3046
 3047write_qt(Quoted, Term, Options1) :-
 3048    merge_options([quoted(Quoted), priority(1200)], Options1, Options2),
 3049    select_option(portray_goal(PG), Options2, Options, PG),
 3050    write_term(Term, Options).
 3051
 3052rportray_string(String, Options1) :-
 3053    merge_options([quoted(true), character_escapes(true)], Options1, Options2),
 3054    select_option(portray_goal(PG), Options2, Options, PG),
 3055    atomics_to_string(Atoms, '\n', String),
 3056    maplist(fix_string(Options), Atoms, List),
 3057    atomics_to_string(List, '\n', String2),
 3058    write('"'),
 3059    write(String2),
 3060    write('"').
 3061
 3062fix_string(Options, Atom, Elem) :-
 3063    atom_string(Atom, Raw),
 3064    string_term(Raw, Options, String),
 3065    atomics_string(['\"', Elem, '\"'], String).
 3066
 3067with_output_to_string(Text, Goal) :- with_output_to_string(Text, _, _, true, Goal).
 3068with_output_to_string(Text, Prev, Goal) :- with_output_to_string(Text, _, _, Prev, Goal).
 3069
 3070with_output_to_string(Text, S1, S2, Prev, Goal) :-
 3071    with_output_to(string(OutputText),
 3072                   ( call(Prev),
 3073                     stream_property(current_output, position(S1)),
 3074                     call(Goal),
 3075                     stream_property(current_output, position(S2))
 3076                   )),
 3077    stream_position_data(char_count, S1, B1),
 3078    stream_position_data(char_count, S2, B2),
 3079    get_subtext(OutputText, B1, B2, Text).
 3080
 3081string_term(Term, Options, String) :-
 3082    with_output_to_string(String, write_term(Term, Options))