View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2009-2011, University of Amsterdam
    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(portray_text,
   36          [ portray_text/1,             % +Bool
   37            set_portray_text/2          % +Name, +Value
   38          ]).   39:- use_module(library(error)).

Portray text

A Prolog string is a list of character-codes: (small) integers, which results in output like this:

?- writeln("hello").
[104, 101, 108, 108, 111]

Unless you know the Unicode tables by heart, this is pretty unpleasant for debugging. Loading this library makes the toplevel and debugger print strings with at least 3 characters as "text ...". Of course, this is an ambigious operation because nobody can know whether [65,66] should be written as "AB" or a list: to Prolog they are the same. Therefore it is imported that the user is aware of the fact that this heuristic conversion is enabled. This is why this library must be loaded explicitely to enable this conversion.

To be done
- Allow setting the character-codes we try to convert */
   63:- dynamic
   64    do_portray_text/1,
   65    portray_text_option/2.   66
   67do_portray_text(true).
   68
   69portray_text_option(min_length, 3).
   70portray_text_option(ellipsis,  30).
 portray_text(+Boolean) is det
If true, write lists of character codes as "..." to simplify debugging.
   77portray_text(OnOff) :-
   78    must_be(boolean, OnOff),
   79    retractall(do_portray_text(_)),
   80    assert(do_portray_text(OnOff)).
 set_portray_text(+Name, +Value) is det
Set options for writing lists as strings. Options are
min_length
Only consider lists that are at least this long
ellipsis
Write strings that are longer as "start...end"
   91set_portray_text(min_length, N) :-
   92    must_be(nonneg, N),
   93    retractall(portray_text_option(min_length, _)),
   94    assert(portray_text_option(min_length, N)).
   95set_portray_text(ellipsis, N) :-
   96    must_be(nonneg, N),
   97    retractall(portray_text_option(ellipsis, _)),
   98    assert(portray_text_option(ellipsis, N)).
   99
  100
  101:- multifile
  102    user:portray/1.  103:- dynamic
  104    user:portray/1.  105
  106user:portray(Codes) :-
  107    do_portray_text(true),
  108    '$skip_list'(Length, Codes, Tail),
  109    portray_text_option(min_length, MinLen),
  110    Length >= MinLen,
  111    all_ascii(Codes),
  112    portray_text_option(ellipsis, IfLonger),
  113    put_char('"'),
  114    (   Length > IfLonger
  115    ->  First is IfLonger - 5,
  116        Skip is Length - 5,
  117        skip_first(Skip, Codes, Rest),
  118        put_n_codes(First, Codes),
  119        format('...', [])
  120    ;   Rest = Codes
  121    ),
  122    (   var_or_numbered(Tail)
  123    ->  put_var_codes(Rest)
  124    ;   format('~s', [Rest])
  125    ),
  126    put_char('"').
  127
  128put_n_codes(N, [H|T]) :-
  129    N > 0,
  130    !,
  131    emit_code(H),
  132    N2 is N - 1,
  133    put_n_codes(N2, T).
  134put_n_codes(_, _).
  135
  136skip_first(N, [_|T0], T) :-
  137    succ(N2, N),
  138    !,
  139    skip_first(N2, T0, T).
  140skip_first(_, L, L).
  141
  142put_var_codes(Var) :-
  143    var_or_numbered(Var),
  144    !,
  145    format('|~p', [Var]).
  146put_var_codes([]).
  147put_var_codes([H|T]) :-
  148    emit_code(H),
  149    put_var_codes(T).
  150
  151emit_code(0'\b) :- !, format('\\b').
  152emit_code(0'\r) :- !, format('\\r').
  153emit_code(0'\n) :- !, format('\\n').
  154emit_code(0'\t) :- !, format('\\t').
  155emit_code(C) :- put_code(C).
  156
  157all_ascii(Var) :-
  158    var_or_numbered(Var),
  159    !.
  160all_ascii([]).
  161all_ascii([H|T]) :-
  162    isascii(H),
  163    all_ascii(T).
  164
  165isascii(Term) :-
  166    integer(Term),
  167    ascii_code(Term),
  168    !.
  169
  170ascii_code(9).
  171ascii_code(10).
  172ascii_code(13).                         % ok ...
  173ascii_code(C) :-
  174    between(32, 126, C).
  175
  176var_or_numbered(Var) :-
  177    var(Var),
  178    !.
  179var_or_numbered('$VAR'(_))