| Did you know ... | Search Documentation: |
| Printing messages |
The predicate print_message/2 is used to print a message term in a human-readable format. The other predicates from this section allow the user to refine and extend the message system. A common usage of print_message/2 is to print error messages from exceptions. The code below prints errors encountered during the execution of Goal, without further propagating the exception and without starting the debugger.
...,
catch(Goal, E,
( print_message(error, E),
fail
)),
...
Another common use is to define message_hook/3 for printing messages that are normally silent, suppressing messages, redirecting messages or make something happen in addition to printing the message.
user_error allows displaying the message
appropriate to the application (terminal, logfile, graphics), acting on
messages based on their content instead of a string (see message_hook/3)
and creating language specific versions of the messages. See also
section 4.11.1. The
following message kinds are known:
silent.error(Formal, Context). See
section introduction (section
4.11). An error message causes the process to halt with status 1 if
the Prolog flag on_error
is set to
halt and the message is not intercepted by message_hook/3.
Not intercepted error messages increment the errors key for
statistics/2.silent.halt and the message is not intercepted by message_hook/3.
Not intercepted warning messages increment the warnings key
for statistics/2.
The predicate print_message/2
first translates the Term into a list of ‘message lines’
(see print_message_lines/3
for details). Next, it calls the hook message_hook/3
to allow the user to intercept the message. If message_hook/3
fails it prints the message unless Kind is silent.
The print_message/2
predicate and its rules are in the file
<plhome>/boot/messages.pl, which may be
inspected for more information on the error messages and related error
terms. If you need to write messages from your own predicates, it is
recommended to reuse the existing message terms if applicable. If no
existing message term is applicable, invent a fairly unique term that
represents the event and define a rule for the multifile predicate
prolog:message//1. See
section 4.11.1 for a
deeper discussion and examples.
See also message_to_string/2.
at_same_line to complete the line.~N).nl, for example because it is ended using ~N
in a Format element. Resetting matters because a terminal
that scrolls while a background colour is in effect paints the newly
exposed line with it, which would colour the empty line that follows the
message. Without a background colour this element produces no output.library(ansi_term) implements this hook to
achieve coloured output. If it is not intercepted it invokes format(Stream,
Format, Args).File:Line:Column, File:Line or File.
When using library library(ansi_term), this is translated
into a hyperlink for modern terminals.url(Location) above. When using
library library(ansi_term), this is translated into a
hyperlink for modern terminals. Label is one of
-Args,
which is handed to format/3.ansi(Class, Format, Args), which prints the
label using the attributes of Class as well as making it a
hyperlink. This is how a predicate reference in a message is both
coloured using the
code class and linked to its definition.begin(Class, Context) and
ended by end(Context). This feature is used by, e.g.,
library library(ansi_term) to colour entire messages.
Class is normally the message kind. The interactive
top level uses answer(Parity) for the messages of kind query
that show bindings, which
stripes the answers of a non-deterministic query. See
section 2.5.format(Stream, Format,[]). Deprecated because it is
ambiguous if Format collides with one of the atomic commands.
Context above is a variable that is bound by the handler
for
begin(Class, Context) and is passed to the elements that
follow it. It allows this handler to restore the decoration of the
message as a whole after an element that installs a decoration of its
own, and to paint the remainder of a line. Its value is opaque: only the
code that implements prolog:message_line_element/2
for begin(Class, Context) may interpret it. If this hook is
not defined, or the output is not a terminal, Context is left
unbound.
To make Context available to the elements that need it,
print_message_lines/3
rewrites the elements nl, flush,
eol and ansi(Attributes, Format, Args) of Lines
into nl(Context), flush(Context), eol(Context)
and
ansi(Attributes, Format, Args, Context) before passing them
to
prolog:message_line_element/2.
A message that is created using prolog:message//1 always uses the short
forms.
See also print_message/2 and message_hook/3.
user to
intercept messages from print_message/2. Term
and Kind are the same as passed to print_message/2. Lines
is a list of format statements as described with print_message_lines/3.
See also
message_to_string/2.
If calling this hook succeeds, the message is considered printed and no further action is taken. Version 9.3.34 introduced prolog:message_action/2 to allow modules to act on certain actions. Before prolog:message_action/2 was introduced a program could associate an action with a message by adding a clause for message_hook/3 that realises the desired action and then fails. The problem with this approach for actions is that the order of clauses for a multi-file predicate is poorly defined. If the application defines a hook that succeeds, this hook may cause intended actions not to take place.
This predicate must be defined dynamic and multifile to allow other modules defining clauses for it too.
library(broadcast).
forall(prolog:message_action(Term, Kind), true).
:- multifile user:message_property/2. user:message_property(help, color([fg(blue)])).
'~N'. For example, messages of kind
warning use '~NWarning: '.prefix property for error and
warning messages.
location_prefix(File:Line,
'~NERROR: ~w:~d:'-[File,Line], '~N\t')).
user_error.library(ansi_term) to colour messages on ANSI-capable
terminals. If it fails, print_message_lines/3
prints Term itself, ignoring any decoration. Note that the
elements that carry the context established by begin(Class,
Context) are passed to this hook in their long form, e.g., nl(Context)
rather than nl. See
print_message_lines/3
for the details.
Libraries should not use format/3
or other output predicates directly. Libraries that print informational
output directly to the console are hard to use from code that depend on
your textual output, such as a CGI script. The predicates in section
4.11 define the API for dealing with messages. The idea behind this
is that a library that wants to provide information about its status,
progress, events or problems calls print_message/2.
The first argument is the
level. The supported levels are described with print_message/2.
Libraries typically use informational and warning,
while libraries should use exceptions for errors (see throw/1, type_error/2,
etc.).
The second argument is an arbitrary Prolog term that carries the information of the message, but not the precise text. The text is defined by the grammar rule prolog:message//1. This distinction is made to allow for translations and to allow hooks processing the information in a different way (e.g., to translate progress messages into a progress bar).
For example, suppose we have a library that must download data from the Internet (e.g., based on http_open/3). The library wants to print the progress after each downloaded file. The code below is a good skeleton:
download_urls(List) :-
length(List, Total),
forall(nth1(I, List, URL),
( download_url(URL),
print_message(informational,
download_url(URL, I, Total)))).
The programmer can now specify the default textual output using the rule below. Note that this rule may be in the same file or anywhere else. Notably, the application may come with several rule sets for different languages. This, and the user-hook example below are the reason to represent the message as a compound term rather than a string. This is similar to using message numbers in non-symbolic languages. The documentation of print_message_lines/3 describes the elements that may appear in the output list.
:- multifile
prolog:message//1.
prolog:message(download_url(URL, I, Total)) -->
{ Perc is round(I*100/Total) },
[ 'Downloaded ~w; ~D from ~D (~d%)'-[URL, I, Total, Perc] ].
A user of the library may define rules for message_hook/3. The rule below acts on the message content. Other applications can act on the message level and, for example, popup a message box for warnings and errors.
:- multifile user:message_hook/3.
message_hook(download_url(URL, I, Total), _Kind, _Lines) :-
<send this information to a GUI component>
In addition, using the command line option -q, the user can disable all informational messages.
Many messages refer to a predicate. Rather than formatting the
predicate indicator yourself, use the grammar rules below. They are
defined in the system module $messages and are declared
public, i.e., they must be called with an explicit module
qualification. Using them makes the reference consistent with the
messages of the system: the predicate indicator is written using the
code style class and, if the source location of the
predicate is known, it becomes a hyperlink to its definition on
terminals that support this (see section
2.5 and the Prolog flag
hyperlink_term). This works for predicates defined in C as well,
provided the system can resolve the address of the implementing
function.
prolog:message(no_such_predicate(PI)) -->
[ 'There is no ' ],
'$messages':predicate_reference(PI).
////// notation. Options:
auto (default), hide or show.
Using
auto, the module qualification is removed if it is user,
system or a system internal module.false, do not create a hyperlink. Default is true.code.true, add a tag that indicates the kind of the
predicate. Default is false. This is intended for messages
that list candidate predicates, one per line.//iso, built_in, foreign,
library(Name), module(Module), user
or
undefined. This is the classification used by the
tag(true) option above. Fails if Spec does not
denote a predicate.