View source with raw comments or as raw
    1/*  Part of SWISH
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2014-2016, VU University 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(swish_render,
   36	  [ use_rendering/1,		% +Renderer
   37	    use_rendering/2,		% +Renderer, +Options
   38
   39	    register_renderer/2,	% Declare a rendering module
   40	    current_renderer/2		% Name, Comment
   41	  ]).   42:- use_module(library(pengines_io), []).   43:- use_module(library(http/html_write)).   44:- use_module(library(http/term_html)).   45:- use_module(library(option)).   46:- use_module(library(error)).   47
   48:- meta_predicate
   49	register_renderer(:, +),
   50	use_rendering(:),
   51	use_rendering(:, +).

SWISH term-rendering support

This module manages rendering answers using alternative vizualizations. The idea is that a specific context uses zero or more rendering modules. These rendering modules provide an alternative HTML representation for the target term. If multiple possible renderings are found, a <div class="render-multi"> element is generated that contains the alternative renderings. The jQuery plugin renderMulti, defined in answer.js adds the behaviour to change rendering to the generated div.

The user can import rendering schemes into the current context using the directive below. Spec is either an atom or string, making the system look for render(Spec), or it is a (single) file specification that can be used for use_module/1.

:- use_rendering(Spec).

A rendering module is a Prolog module that defines the non-terminal term_rendering//3, which will be called as below. Term is the (non-var) term that must be rendered, Vars is a list of variable names bound to this term and Options is a list of write options that would normally be passed to write_term/3. The grammar is executed by library(http/html_write) and must generate compatible tokens (which means it must call html//1 to generate HTML tokens).

phrase(Renderer:term_rendering(Term, Vars, Options), Tokens)

*/

   86:- multifile user:file_search_path/2.   87
   88user:file_search_path(render, swish('lib/render')).
 use_rendering(+FileOrID)
Register an answer renderer. Same as use_rendering(FileOrID, []).
See also
- use_rendering/2.
   98:- multifile system:term_expansion/2.   99
  100use_rendering(Rendering) :-
  101	use_rendering(Rendering, []).
 use_rendering(:ID, +Options)
Register an answer renderer with options. Options are merged with write-options and passed to the non-terminal term_rendering//3 defined in the rendering module.
  109use_rendering(Rendering, Options) :-
  110	Rendering = Into:Renderer,
  111	must_be(atom, Renderer),
  112	(   renderer(Renderer, _, _)
  113	->  true
  114	;   existence_error(renderer, Renderer)
  115	),
  116	retractall(Into:'swish renderer'(Renderer, _)),
  117	assertz(Into:'swish renderer'(Renderer, Options)).
  118
  119system:term_expansion((:- use_rendering(Renderer)), Expanded) :-
  120	expand_rendering(Renderer, [], Expanded).
  121system:term_expansion((:- use_rendering(Renderer, Options)), Expanded) :-
  122	expand_rendering(Renderer, Options, Expanded).
  123
  124expand_rendering(Module:Renderer, Options,
  125		 [ (:- discontiguous(Module:'swish renderer'/2)),
  126		   Module:'swish renderer'(Renderer, Options)
  127		 ]) :- !,
  128	must_be(atom, Module),
  129	must_be(atom, Renderer).
  130expand_rendering(Renderer, Options,
  131		 [ (:- discontiguous('swish renderer'/2)),
  132		   'swish renderer'(Renderer, Options)
  133		 ]) :-
  134	must_be(atom, Renderer).
 pengines_io:binding_term(+Term, +Vars, +Options) is semidet
Produce alternative renderings for Term, which is a binding for Vars.
  141:- multifile pengines_io:binding_term//3.  142
  143pengines_io:binding_term(Term, Vars, Options) -->
  144	{ option(module(Module), Options),
  145	  findall(Tokens,
  146		  call_term_rendering(Module, Term, Vars, Options, Tokens),
  147		  NestedTokens),
  148	  NestedTokens \== [], !
  149	},
  150	alt_renderer(NestedTokens, Term, Options).
 call_term_rendering(+Module, +Term, +Vars, +Options, -Tokens) is nondet
Call term_rendering//3 in all modules from which Module inherits.
  157call_term_rendering(Module, Term, Vars, Options, Tokens) :-
  158	State = state([]),
  159	default_module(Module, Target),
  160	current_predicate(Target:'swish renderer'/2),
  161	Target:'swish renderer'(Name, RenderOptions),
  162	atom(Name),
  163	is_new(State, Name),
  164	renderer(Name, RenderModule, _Comment),
  165	merge_options(RenderOptions, Options, AllOptions),
  166	catch(phrase(RenderModule:term_rendering(Term, Vars, AllOptions), Tokens),
  167	      E, rendering_error(E, Name, Tokens)).
  168
  169rendering_error(Error, Renderer, Tokens) :-
  170	message_to_string(Error, Msg),
  171	phrase(html(div(class('render-error'),
  172			[ 'Renderer ', span(Renderer),
  173			  ' error: ', span(class(error), Msg)
  174			])), Tokens).
 is_new(!State, +M) is semidet
Only succeeds once for each new ground value M.
  181is_new(State, M) :-
  182	arg(1, State, Seen),
  183	(   memberchk(M, Seen)
  184	->  fail
  185	;   nb_linkarg(1, State, [M|Seen])
  186	).
 alt_renderer(+Specialised, +Term, +Options)//
Create a rendering selection object after we have found at least one alternative rendering for Term.
  193alt_renderer(Specialised, Term, Options) -->
  194	html(div(class('render-multi'),
  195		 \specialised(Specialised, Term, Options))).
  196
  197specialised([], Term, Options) -->
  198	html(span([ class('render-as-prolog'),
  199		    'data-render'('Prolog term')
  200		  ],
  201		  \term(Term, Options))).
  202specialised([H|T], Term, Options) -->
  203	tokens(H),
  204	specialised(T, Term, Options).
  205
  206tokens([]) --> [].
  207tokens([H|T]) --> [H], tokens(T).
  208
  209
  210		 /*******************************
  211		 *	   REGISTRATION		*
  212		 *******************************/
  213
  214:- multifile
  215	renderer/3.
 current_renderer(Name, Comment) is nondet
True when renderer Name is declared with Comment.
  221current_renderer(Name, Comment) :-
  222	renderer(Name, _Module, Comment).
 register_renderer(:Name, +Comment)
Register a module as SWISH rendering component.
  228register_renderer(Name, Comment) :-
  229	throw(error(context_error(nodirective, register_renderer(Name, Comment)),
  230		    _)).
  231
  232system:term_expansion((:- register_renderer(Name, Comment)),
  233		    swish_render:renderer(Name, Module, Comment)) :-
  234	prolog_load_context(module, Module)