34
35:- module(swish_render,
36 [ use_rendering/1, 37 use_rendering/2, 38
39 register_renderer/2, 40 current_renderer/2 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(:, +).
86:- multifile user:file_search_path/2. 87
88user:file_search_path(render, swish('lib/render')).
98:- multifile system:term_expansion/2. 99
100use_rendering(Rendering) :-
101 use_rendering(Rendering, []).
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).
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).
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).
181is_new(State, M) :-
182 arg(1, State, Seen),
183 ( memberchk(M, Seen)
184 -> fail
185 ; nb_linkarg(1, State, [M|Seen])
186 ).
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 213
214:- multifile
215 renderer/3.
221current_renderer(Name, Comment) :-
222 renderer(Name, _Module, Comment).
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)
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 pluginrenderMulti
, defined inanswer.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.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).
*/