swish/commit
New upstream versions
author | Jan Wielemaker |
---|---|
Wed Sep 23 14:46:50 2015 +0200 | |
committer | Jan Wielemaker |
Wed Sep 23 14:46:50 2015 +0200 | |
commit | 89c2ffa40d8013b961d66a456fd76105c6bceff3 |
tree | 9dfb376fa317b0ab36eb1ec0c23e978ded56960f |
parent | c161b04591ffe11def51b0315af6171346d26bdd |
Diff style: patch stat
diff --git a/lib/swish/page.pl b/lib/swish/page.pl index f67d04d..75a3a19 100644 --- a/lib/swish/page.pl +++ b/lib/swish/page.pl @@ -112,22 +112,26 @@ swish_reply(SwishOptions, Request) :- background(_, [optional(true)]), examples(_, [optional(true)]), q(_, [optional(true)]), - format(_, [oneof([swish,raw]), default(swish)]) + format(_, [oneof([swish,raw,json]), default(swish)]) ], http_parameters(Request, Params), params_options(Params, Options0), merge_options(Options0, SwishOptions, Options1), source_option(Request, Options1, Options2), - swish_reply1(Options2). + option(format(Format), Options2), + swish_reply2(Format, Options2). -swish_reply1(Options) :- - option(code(Code), Options), - option(format(raw), Options), !, +swish_reply2(raw, Options) :- + option(code(Code), Options), !, format('Content-type: text/x-prolog~n~n'), format('~s', [Code]). -swish_reply1(Options) :- +swish_reply2(json, Options) :- + option(code(Code), Options), !, + option(meta(Meta), Options, _{}), + reply_json_dict(json{data:Code, meta:Meta}). +swish_reply2(_, Options) :- swish_config:reply_page(Options), !. -swish_reply1(Options) :- +swish_reply2(_, Options) :- reply_html_page( swish(main), [ title('SWISH -- SWI-Prolog for SHaring'), @@ -207,14 +211,46 @@ path_info_file(PathInfo, Path, Options) :- confirm_access(Path, AliasOptions), !, option(alias(Alias), Options, _). -source_data(Path, Code, [title(Title), type(Ext)]) :- +source_data(Path, Code, [title(Title), type(Ext), meta(Meta)]) :- setup_call_cleanup( open(Path, read, In, [encoding(utf8)]), read_string(In, _, Code), close(In)), + source_metadata(Path, Code, Meta), file_base_name(Path, File), file_name_extension(Title, Ext, File). +%% source_metadata(+Path, +Code, -Meta:dict) is det. +% +% Obtain meta information about a local source file. Defined meta +% info is: +% +% - last_modified:Time +% Last modified stamp of the file. Always present. +% - loaded:true +% Present of the file is a loaded source file +% - modified_since_loaded:true +% Present if the file loaded, has been edited, but not +% yet reloaded. + +source_metadata(Path, Code, Meta) :- + findall(Name-Value, source_metadata(Path, Code, Name, Value), Pairs), + dict_pairs(Meta, meta, Pairs). + +source_metadata(Path, _Code, path, Path). +source_metadata(Path, _Code, last_modified, Modified) :- + time_file(Path, Modified). +source_metadata(Path, _Code, loaded, true) :- + source_file(Path). +source_metadata(Path, _Code, modified_since_loaded, true) :- + source_file_property(Path, modified(ModifiedWhenLoaded)), + time_file(Path, Modified), + ModifiedWhenLoaded \== Modified. +source_metadata(Path, _Code, module, Module) :- + file_name_extension(_, Ext, Path), + prolog_file_type(Ext, prolog), + xref_public_list(Path, _, [module(Module)]). + confirm_access(Path, Options) :- option(if(Condition), Options), !, must_be(oneof([loaded]), Condition), @@ -359,16 +395,19 @@ swish_config_hash --> % - file(+File) % If present and code(String) is present, also associate the % editor with the given file. See storage.pl. +% - url(+URL) +% as file(File), but used if the data is loaded from an +% alias/file path. +% - title(+Title) +% Defines the title used for the tab. source(pl, Options) --> { option(code(Spec), Options), !, download_source(Spec, Source, Options), - phrase(source_data_attrs(Options), Extra), - source_meta_data(MetaAttrs, Options) + phrase(source_data_attrs(Options), Extra) }, html(div([ class(['prolog-editor']), 'data-label'('Program') - | MetaAttrs ], [ textarea([ class([source,prolog]), style('display:none') @@ -381,7 +420,8 @@ source(_, _) --> []. source_data_attrs(Options) --> (source_file_data(Options) -> [] ; []), (source_url_data(Options) -> [] ; []), - (source_title_data(Options) -> [] ; []). + (source_title_data(Options) -> [] ; []), + (source_meta_data(Options) -> [] ; []). source_file_data(Options) --> { option(file(File), Options) }, @@ -392,18 +432,17 @@ source_url_data(Options) --> source_title_data(Options) --> { option(title(File), Options) }, ['data-title'(File)]. +source_meta_data(Options) --> + { option(meta(Meta), Options), !, + atom_json_dict(Text, Meta, []) + }, + ['data-meta'(Text)]. - -%% source_meta_data(-Extra, +Options) +%% background(+Options)// % -% Dump the meta-data of the provided file into swish.meta_data. -% @tbd: serialize and add - -source_meta_data(['data-meta'(Text)], Options) :- - option(file(_), Options), - option(meta(Meta), Options), !, - atom_json_dict(Text, Meta, []). -source_meta_data([], _). +% Associate the background program (if any). The background +% program is not displayed in the editor, but is sent to the +% pengine for execution. background(Options) --> { option(background(Spec), Options), !, @@ -443,12 +482,10 @@ query(_) --> []. notebooks(swinb, Options) --> { option(code(Spec), Options), download_source(Spec, NoteBookText, Options), - phrase(source_data_attrs(Options), Extra), - source_meta_data(MetaAttrs, Options) + phrase(source_data_attrs(Options), Extra) }, html(div([ class('notebook'), 'data-label'('Notebook') % Use file? - | MetaAttrs ], [ pre([ class('notebook-data'), style('display:none') diff --git a/lib/swish/render/graphviz.pl b/lib/swish/render/graphviz.pl index 6d5e5df..4b77e4d 100644 --- a/lib/swish/render/graphviz.pl +++ b/lib/swish/render/graphviz.pl @@ -31,6 +31,7 @@ [ term_rendering//3 % +Term, +Vars, +Options ]). :- use_module(library(http/html_write)). +:- use_module(library(http/js_write)). :- use_module(library(http/http_dispatch)). :- use_module(library(http/http_parameters)). :- use_module(library(http/http_path)). @@ -142,7 +143,55 @@ render_dot(DOTString, Program, _Options) --> % <svg> rendering )) }, ( { Error == "" } - -> html(\[SVG]) + -> html(div([ class(['render-graphviz', 'reactive-size']), + 'data-render'('As Graphviz graph') + ], + [ \[SVG], + \js_script({|javascript|| +(function() { + if ( $.ajaxScript ) { + var div = $.ajaxScript.parent(); + var svg = div.find("svg"); + var data = { w0: svg.width(), + h0: svg.height() + }; + var pan; + + function updateSize() { + console.log("updateSize"); + var w = svg.closest("div.answer").innerWidth(); + + function reactive() { + if ( !data.reactive ) { + data.reactive = true; + div.on("reactive-resize", updateSize); + } + } + + w = Math.max(w*0.85, 100); + if ( w < data.w0 ) { + svg.width(w); + svg.height(w = Math.max(w*data.h0/data.w0, w/4)); + reactive(); + if ( pan ) { + pan.resize(); + pan.fit(); + pan.center(); + } + } + } + + require(["svg-pan-zoom"], function(svgPanZoom) { + updateSize() + pan = svgPanZoom(svg[0], { + // controlIconsEnabled: true + maxZoom: 50 + }); + }); + } + })(); + |}) + ])) ; html(div(style('color:red;'), [ '~w'-[Program], ': ', Error])) ). diff --git a/lib/swish/search.pl b/lib/swish/search.pl index f6fc4c7..5e2236a 100644 --- a/lib/swish/search.pl +++ b/lib/swish/search.pl @@ -28,7 +28,8 @@ */ :- module(swish_search, - [ search_box//1 % +Options + [ search_box//1, % +Options + match/3 % +Line, +Query, +Options ]). :- use_module(library(lists)). :- use_module(library(http/html_write)). @@ -42,7 +43,7 @@ :- use_module(config). :- multifile - typeahead/3. % +Set, +Query, -Match + typeahead/4. % +Set, +Query, -Match, +Options /** <module> SWISH search from the navigation bar @@ -89,13 +90,14 @@ search_box(_Options) --> typeahead(Request) :- http_parameters(Request, - [ q(Query, [default('')]), - set(Set, [default(predicates)]) + [ q(Query, [default('')]), + set(Set, [default(predicates)]), + match(Match, [default(sow)]) ]), - findall(Match, typeahead(Set, Query, Match), Matches), - reply_json_dict(Matches). + findall(Result, typeahead(Set, Query, Result, _{match:Match}), Results), + reply_json_dict(Results). -%% typeahead(+Type, +Query, -Match) is nondet. +%% typeahead(+Type, +Query, -Match, +Options:dict) is nondet. % % Find typeahead suggestions for a specific search category % (Type). This oredicate is a multifile predicate, which allows @@ -112,23 +114,29 @@ typeahead(Request) :- :- multifile swish_config:source_alias/2. -typeahead(predicates, Query, Template) :- +typeahead(predicates, Query, Template, _) :- swish_config(templates, Templates), member(Template, Templates), _{name:Name, arity:_} :< Template, sub_atom(Name, 0, _, _, Query). -typeahead(sources, Query, hit{alias:Alias, file:File, ext:Ext, - query:Query, line:LineNo, text:Line}) :- +typeahead(sources, Query, Hit, Options) :- source_file(Path), - file_name_on_path(Path, Symbolic), - file_name_extension(_, Ext, Path), - Symbolic =.. [Alias,File], - once(swish_config:source_alias(Alias, _)), - limit(5, search_file(Path, Query, LineNo, Line)). + ( file_alias_path(Alias, Dir), + once(swish_config:source_alias(Alias, _)), + atom_concat(Dir, File, Path) + -> true + ), + file_name_extension(Base, Ext, File), + ( sub_atom(File, 0, _, _, Query) + -> Hit = hit{alias:Alias, file:Base, ext:Ext, query:Query} + ; Hit = hit{alias:Alias, file:Base, ext:Ext, + query:Query, line:LineNo, text:Line}, + limit(5, search_file(Path, Query, LineNo, Line, Options)) + ). typeahead(sources, Query, hit{alias:Alias, file:Base, ext:Ext, - query:Query, line:LineNo, text:Line}) :- - swish_config:source_alias(Alias, Options), - option(search(Pattern), Options), + query:Query, line:LineNo, text:Line}, Options) :- + swish_config:source_alias(Alias, AliasOptions), + option(search(Pattern), AliasOptions), DirSpec =.. [Alias,.], absolute_file_name(DirSpec, Dir, [ access(read), @@ -143,16 +151,59 @@ typeahead(sources, Query, hit{alias:Alias, file:Base, ext:Ext, \+ source_file(Path), % already did this one above atom_concat(DirSlash, File, Path), file_name_extension(Base, Ext, File), - limit(5, search_file(Path, Query, LineNo, Line)). + limit(5, search_file(Path, Query, LineNo, Line, Options)). -search_file(Path, Query, LineNo, Line) :- +search_file(Path, Query, LineNo, Line, Options) :- + debug(swish(search), 'Searching ~q for ~q (~q)', [Path, Query, Options]), setup_call_cleanup( open(Path, read, In), read_string(In, _, String), close(In)), split_string(String, "\n", "\r", Lines), nth1(LineNo, Lines, Line), - once(sub_string(Line, _, _, _, Query)). + match(Line, Query, Options). + +%% match(+Line:string, +Query:string, +Options:dict) is semidet. +% +% True if Line matches Query, respecting Options. + +match(Text, Query, Options) :- + sub_string(Text, Start, _, _, Query), + ( Options.get(match) == sow + -> sow(Text, Start), ! + ; Options.get(match) == sol + -> !, Start == 0 + ; ! + ). + +sow(_, 0) :- !. +sow(Text, Offset) :- + Pre is Offset-1, + sub_atom(Text, Pre, 1, _, Before), + sub_atom(Text, Offset, 1, _, Start), + char_class(Start, Class), + \+ char_class(Before, Class). + +char_class(C, Class) :- + var(Class), !, + ( target_class(Class), + char_type(C, Class) + -> true + ; Class = other + ). +char_class(C, Class) :- + ( target_class(Class) + -> char_type(C, Class) + ; \+ ( target_class(T), + char_type(C, T) + ) + ). + +target_class(lower). +target_class(upper). +target_class(digit). +target_class(space). +target_class(punct). %% search(+Request) % diff --git a/lib/swish/storage.pl b/lib/swish/storage.pl index 1968e43..136dd56 100644 --- a/lib/swish/storage.pl +++ b/lib/swish/storage.pl @@ -47,6 +47,7 @@ :- use_module(page). :- use_module(gitty). :- use_module(config). +:- use_module(search). /** <module> Store files on behalve of web clients @@ -58,7 +59,7 @@ their own version. :- setting(directory, atom, storage, 'The directory for storing files.'). -:- http_handler(swish(p), web_storage, [ id(web_storage), prefix ]). +:- http_handler(swish('p/'), web_storage, [ id(web_storage), prefix ]). %% web_storage(+Request) is det. % @@ -154,8 +155,7 @@ storage(delete, Request) :- reply_json_dict(true). request_file(Request, Dir, File) :- - option(path_info(PathInfo), Request), - atom_concat(/, File, PathInfo), + option(path_info(File), Request), ( gitty_file(Dir, File, _Hash) -> true ; http_404([], Request) @@ -256,8 +256,7 @@ storage_get(diff(RelTo), Dir, _, File, _Request) :- reply_json_dict(Diff). request_file_or_hash(Request, Dir, FileOrHash, Type) :- - option(path_info(PathInfo), Request), - atom_concat(/, FileOrHash, PathInfo), + option(path_info(FileOrHash), Request), ( gitty_file(Dir, FileOrHash, _Hash) -> Type = file ; is_sha1(FileOrHash) @@ -340,7 +339,7 @@ storage_file(File, Data, Meta) :- *******************************/ :- multifile - swish_search:typeahead/3. % +Set, +Query, -Match + swish_search:typeahead/4. % +Set, +Query, -Match, +Options %% swish_search:typeahead(+Set, +Query, -Match) is nondet. % @@ -355,7 +354,7 @@ storage_file(File, Data, Meta) :- % @tbd caching? % @tbd We should only demand public on public servers. -swish_search:typeahead(file, Query, FileInfo) :- +swish_search:typeahead(file, Query, FileInfo, _Options) :- setting(directory, Dir), gitty_file(Dir, File, Head), gitty_commit(Dir, Head, Meta), @@ -382,20 +381,20 @@ meta_match_query(Query, Meta) :- \+ char_type(C, csym) ). -swish_search:typeahead(store_content, Query, FileInfo) :- - limit(25, search_store_content(Query, FileInfo)). +swish_search:typeahead(store_content, Query, FileInfo, Options) :- + limit(25, search_store_content(Query, FileInfo, Options)). -search_store_content(Query, FileInfo) :- +search_store_content(Query, FileInfo, Options) :- setting(directory, Dir), gitty_file(Dir, File, Head), gitty_data(Dir, Head, Data, Meta), Meta.get(public) == true, - limit(5, search_file(File, Meta, Data, Query, FileInfo)). + limit(5, search_file(File, Meta, Data, Query, FileInfo, Options)). -search_file(File, Meta, Data, Query, FileInfo) :- +search_file(File, Meta, Data, Query, FileInfo, Options) :- split_string(Data, "\n", "\r", Lines), nth1(LineNo, Lines, Line), - once(sub_string(Line, _, _, _, Query)), + match(Line, Query, Options), FileInfo = Meta.put(_{type:"store", file:File, line:LineNo, text:Line, query:Query }). diff --git a/lib/swish/template_hint.pl b/lib/swish/template_hint.pl index 25fdbf9..eba917e 100644 --- a/lib/swish/template_hint.pl +++ b/lib/swish/template_hint.pl @@ -251,7 +251,7 @@ man_predicate_info(PI, Name-Value) :- ( atom_string(PName, PString), Name-Value = name-PString ; Name-Value = arity-Arity - ; Name-Value = mode-ModeLine + ; Name-Value = (mode)-ModeLine ; once(catch(predicate(PName, Arity, Summary, _, _), _, fail)), Name-Value = summary-Summary ; predicate_property(system:PHead, iso), @@ -285,7 +285,7 @@ pldoc_predicate_info(PI, Name-Value) :- ( atom_string(PName, PString), Name-Value = name-PString ; Name-Value = arity-Arity - ; Name-Value = mode-ModeLine + ; Name-Value = (mode)-ModeLine ; Name-Value = summary-Summary ; Det \== unknown, Name-Value = determinism-Det