38
39:- module(swish_examples, []). 40:- use_module(library(http/http_dispatch)). 41:- use_module(library(http/http_json)). 42:- use_module(library(http/json)). 43:- use_module(library(http/http_path)). 44:- use_module(library(filesex)). 45:- use_module(library(apply)). 46:- use_module(library(option)). 47:- use_module(library(lists)). 48:- if(exists_source(library(atom))). 49:- use_module(library(atom)). 50:- endif. 51
52:- use_module(storage). 53:- use_module(md_eval). 54
69
70:- multifile
71 user:file_search_path/2,
72 swish_config:config/2,
73 swish_config:source_alias/2. 74
76user:file_search_path(example, swish(examples)).
77user:file_search_path(example, swish(examples/trill)).
78
79user:file_search_path(e, swish(examples)).
80user:file_search_path(e, swish(examples/trill)).
82swish_config:source_alias(example, [access(read), search('*.{pl,swinb}')]).
83swish_config:source_alias(e, [access(read), search('*.{pl,swinb}')]).
84
85:- http_handler(swish(list_examples),
86 list_examples, [id(swish_examples)]). 87
88
93
94list_examples(_Request) :-
95 examples(AllExamples, [community(true)]),
96 example_menu(AllExamples, Menu),
97 reply_json(Menu).
98
(AllExamples, Menu) :-
100 include(pos_ranked, AllExamples, ForMenu),
101 insert_group_dividers(ForMenu, Menu).
102
103pos_ranked(Ex) :-
104 Rank = Ex.get(grank),
105 Rank > 0.
106
107insert_group_dividers([], []).
108insert_group_dividers([H1,H2|T], List) :-
109 !,
110 ( H1.grank // 10000 =\= H2.grank // 10000
111 -> List = [H1, json{type:divider}|Rest]
112 ; List = [H1|Rest]
113 ),
114 insert_group_dividers([H2|T], Rest).
115insert_group_dividers([H], [H]).
116
117
128
129examples(AllExamples, Options) :-
130 swish_examples(SWISHExamples),
131 ( option(community(true), Options)
132 -> community_examples(CommunityEx)
133 ; CommunityEx = json{}
134 ),
135 join_examples([CommunityEx|SWISHExamples], AllExamples).
136
137:- dynamic
138 swish_example_cache/2. 139
140swish_examples(SWISHExamples) :-
141 swish_example_cache(SWISHExamples, Time),
142 get_time(Now),
143 Now - Time < 60,
144 !.
145swish_examples(SWISHExamples) :-
146 swish_examples_no_cache(SWISHExamples),
147 get_time(Now),
148 retractall(swish_example_cache(_,_)),
149 assertz(swish_example_cache(SWISHExamples, Now)).
150
151swish_examples_no_cache(SWISHExamples) :-
152 http_absolute_location(swish(example), HREF, []),
153 findall(Index,
154 absolute_file_name(example(.), Index,
155 [ access(read),
156 file_type(directory),
157 file_errors(fail),
158 solutions(all)
159 ]),
160 ExDirs),
161 maplist(index_json(HREF), ExDirs, SWISHExamples).
162
163
164join_examples(PerDir, Files) :-
165 menu_groups(PerDir, Groups),
166 maplist(get_or(files, []), PerDir, FilesPerDir),
167 append(FilesPerDir, Files0),
168 maplist(add_grank(Groups), Files0, Files1),
169 sort(grank, =<, Files1, Files).
170
171add_grank(Groups, File0, File) :-
172 get_or(rank, 500, File0, FRank),
173 GroupName = File0.get(group),
174 member(Group, Groups),
175 Group.get(group) == GroupName,
176 GRank is FRank + Group.get(rank), !,
177 File = File0.put(grank, GRank).
178add_grank(_, File0, File) :-
179 File = File0.put(grank, -1).
180
(PerDir, Groups) :-
182 maplist(get_or(menu, []), PerDir, GroupsPerDir),
183 append(GroupsPerDir, Groups0),
184 sort(group, @>, Groups0, Groups1),
185 sort(rank, =<, Groups1, Groups).
186
187get_or(Key, Default, Dict, Value) :-
188 ( is_dict(Dict),
189 Value = Dict.get(Key)
190 -> true
191 ; Value = Default
192 ).
193
201
202index_json(HREF, Dir, JSON) :-
203 directory_file_path(Dir, 'index.json', File),
204 access_file(File, read), !,
205 read_file_to_json(File, JSON0),
206 add_examples_href(HREF, JSON0, JSON1),
207 add_other_files(HREF, Dir, JSON1, JSON).
208index_json(HREF, Dir, json{menu:[json{group:examples, rank:10000}],
209 files:Files}) :-
210 example_files(HREF, Dir, Files0),
211 maplist(add_group(examples), Files0, Files).
212
213example_files(HREF, Dir, JSON) :-
214 string_concat(Dir, "/*.{pl,swinb}", Pattern),
215 expand_file_name(Pattern, Files),
216 maplist(ex_file_json(HREF), Files, JSON).
217
218read_file_to_json(File, JSON) :-
219 setup_call_cleanup(
220 open(File, read, In, [encoding(utf8)]),
221 json_read_dict(In, JSON, [default_tag(json)]),
222 close(In)).
223
228
229add_examples_href(HREF, JSON0, JSON) :-
230 Files0 = JSON0.get(files), !,
231 convlist(add_href(HREF), Files0, Files),
232 JSON = JSON0.put(files, Files).
233add_examples_href(_, JSON, JSON).
234
235
236add_href(HREF0, Dict, Dict2) :-
237 is_dict(Dict),
238 directory_file_path(HREF0, Dict.get(file), HREF),
239 Dict2 = Dict.put(href, HREF).
240
241add_group(Group, Dict0, Dict) :-
242 is_dict(Dict0), !,
243 Dict = Dict0.put(group, Group).
244add_group(_, Dict, Dict).
245
246add_other_files(HREF, Dir, JSON0, JSON) :-
247 example_files(HREF, Dir, Files),
248 get_or(files, [], JSON0, Files0),
249 exclude(in_ex_list(Files0), Files, New),
250 append(Files0, New, AllFiles),
251 JSON = JSON0.put(files, AllFiles).
252
253in_ex_list(Examples, Ex) :-
254 File = Ex.file,
255 member(Ex2, Examples),
256 is_dict(Ex2),
257 File = Ex2.get(file),
258 !.
259
263
264ex_file_json(HREF0, Path, json{file:File, href:HREF, title:Title}) :-
265 file_base_name(Path, File),
266 file_name_extension(Base, _, File),
267 file_name_to_title(Base, Title),
268 directory_file_path(HREF0, File, HREF).
269
270:- if(current_predicate(restyle_identifier/3)). 271file_name_to_title(Base, Title) :-
272 restyle_identifier(style(true,false,' '), Base, Title).
273:- else. 274file_name_to_title(Base, Base).
275:- endif. 276
277
288
289:- multifile
290 md_eval:provides/1. 291
292md_eval:provides(example(Name, Group, Example)) :-
293 examples(Examples, []),
294 ( var(Name)
295 -> member(Example0, Examples),
296 atom_string(Name, Example0.get(file))
297 ; member(Example0, Examples),
298 atom_string(Name, Example0.get(file))
299 -> true
300 ),
301 atom_string(Group, Example0.get(group)),
302 active_example(Example0, Example).
303
304active_example(Example0, Example) :-
305 term_string(Cond, Example0.get(requires)),
306 \+ swish_provides(Cond),
307 ( cond_reason(Cond, Fmt, Args)
308 -> format(string(Reason), Fmt, Args)
309 ; format(string(Reason), 'missing requirement: ~q', [Cond])
310 ),
311 Example = Example0.put(blocked, Reason).
312active_example(Example, Example).
313
314cond_reason(plugin(Name), 'missing plugin: ~w', [Name]).
315
316
317
318 321
325
(json{menu:[json{group:community, rank:50000}],
327 files:Files}) :-
328 swish_config:config(community_examples, true),
329 !,
330 findall(Ex, community_example(Ex), Files).
331community_examples(json{}).
332
(json{title:Title, file:File, group:community, type:store}) :-
334 storage_file_extension_head(File, _Type, Head),
335 storage_commit(Head, Meta),
336 Meta.get(example) == true,
337 ( Title = Meta.get(title), Title \== ""
338 -> true
339 ; file_name_extension(Base, _, File),
340 file_name_to_title(Base, Title)
341 )