diff --git a/src/www/gfse/editor.css b/src/www/gfse/editor.css index eab702d99..346a77128 100644 --- a/src/www/gfse/editor.css +++ b/src/www/gfse/editor.css @@ -64,7 +64,7 @@ table.tabs { border-width: 0; border-spacing: 0; empty-cells: show; } -table.tabs td { text-align: center; border: 2px solid #009; padding: 2px; } +table.tabs td { text-align: center; border: 2px solid #009; padding: 2px; white-space: nowrap; } table.tabs td.active { background: white; border-bottom-width: 0; } table.tabs td.inactive { background: #cef; diff --git a/src/www/gfse/editor.js b/src/www/gfse/editor.js index 96501c77e..b94f2c2c5 100644 --- a/src/www/gfse/editor.js +++ b/src/www/gfse/editor.js @@ -1,6 +1,7 @@ var editor=element("editor"); +var compiler_output=element("compiler_output") /* -------------------------------------------------------------------------- */ @@ -43,8 +44,7 @@ function draw_grammar_list() { return node("tr",{"class":"extensible deletable"}, [td(delete_button(del(i),"Delete this grammar")), td(link), - td(more(grammar,clone(i),"Clone this grammar")), - td(more(grammar,new_extension(i),"Create an extension of this grammar"))]) + td(more(grammar,clone(i),"Clone this grammar"))]) } if(local.get("count",null)==null) home.appendChild(text("You have not created any grammars yet.")); @@ -108,8 +108,9 @@ function delete_grammar(i) { function clone_grammar(i) { var old=local.get(i); - var g={basename:old.basename,abstract:old.abstract,concretes:old.concretes} - save_grammar(g); + var g={basename:old.basename,extends:old.extends || [], + abstract:old.abstract,concretes:old.concretes} + save_grammar(g); // we rely on the serialization to eliminate sharing draw_grammar_list(); } @@ -121,7 +122,7 @@ function open_grammar(i) { } function close_grammar(g) { - var o=element("compiler_output"); + var o=compiler_output; if(o) o.innerHTML=""; save_grammar(g); draw_grammar_list(); @@ -182,7 +183,7 @@ function draw_plainbutton(g,files) { } function show_compile_error(res) { - var dst=element("compiler_output") + var dst=compiler_output if(dst) { dst.innerHTML=""; var minibarlink=a(res.minibar_url,[text("Minibar")]) @@ -198,7 +199,11 @@ function show_compile_error(res) { } function compile_button(g) { - var b=button("Compile",function(){upload(g,show_compile_error);}); + function compile() { + if(compiler_output) compiler_output.innerHTML="

Compiling...

"; + upload(g,show_compile_error); + } + var b=button("Compile",compile); b.title="Upload the grammar to the server to check it in GF for errors"; return b; } @@ -231,7 +236,11 @@ function minibar_button(g,files) { } } } - var b=button("Minibar",function(){upload(g,goto_minibar);}); + function compile() { + if(compiler_output) compiler_output.innerHTML="

Compiling...

"; + upload(g,goto_minibar); + } + var b=button("Minibar",compile); b.title="Upload the grammar and test it in the minibar"; return b; } @@ -372,14 +381,53 @@ function draw_startcat(g) { return indent([kw("flags startcat"),sep(" = "),m]); } -function draw_extends(exts) { +function draw_conc_extends(g,conc) { var kw_extends=kw("extends ") kw_extends.title="This grammar is an extension of the grammars listed here." - return exts && exts.length>0 + var exts=(g.extends || []).map(conc_extends(conc)) + return exts.length>0 ? indent([kw_extends,ident(exts.join(", "))]) : text("") } +function draw_extends(g) { + var kw_extends=kw("extends ") + var exts= g.extends || []; + kw_extends.title="This grammar is an extension of the grammars listed here." + var m1=more(g,add_extends,"Inherit from other grammars"); + var m2=more(g,add_extends,"Inherit from more grammars"); + return exts.length>0 + ? indent([extensible([kw_extends,ident(exts.join(", ")),m2])]) + : indent([extensible([span_class("more",kw_extends),m1])]) +} + +function add_extends(g,el) { + var file=element("file"); + file.innerHTML=""; + var gs=cached_grammar_array_byname(); + var list=[] + for(var i in gs) { + if(gs[i].basename!=g.basename + && !elem(gs[i].basename,g.extends || []) + && !elem(g.basename,gs[i].extends || []) + // also exclude indirectly inherited grammars!! + ) + list.push(li([a(jsurl("add_extends2("+g.index+","+gs[i].index+")"), + [text(gs[i].basename)])])); + } + file.appendChild(p(text("Pick a grammar to inherit:"))); + file.appendChild(node("ul",{"class":"grammars"},list)); +} + +function add_extends2(gix,igix) { + var g=local.get(gix); + var ig=local.get(igix); + if(!g.extends) g.extends=[]; + g.extends.push(ig.basename); + //timestamp(g) + reload_grammar(g); +} + function draw_abstract(g) { var kw_cat = kw("cat"); kw_cat.title = "The categories (nonterminals) of the grammar are enumerated here. [C.3.2]"; @@ -397,7 +445,7 @@ function draw_abstract(g) { return div_id("file", [kw("abstract "),ident(g.basename),sep(" = "), draw_timestamp(g.abstract), - draw_extends(g.extends), + draw_extends(g), flags, indent([extensible([kw_cat, indent(draw_cats(g))]), @@ -542,6 +590,7 @@ function draw_fun(g,fun,dc,df) { function draw_type(t,dc) { var el=empty("span"); function check(t,el) { + if(dc[t]) el.title=dc[t]+"."+t; return ifError(!dc[t],"Undefined category",el); } for(var i in t) { @@ -593,7 +642,7 @@ function draw_concrete(g,i) { edit_langcode,"Change language"), kw(" of "),ident(g.basename),sep(" = "), draw_timestamp(conc), - draw_extends((g.extends || []).map(conc_extends(conc))), + draw_conc_extends(g,conc), indent([extensible([kw("open "),draw_opens(g,i)])]), indent([kw_lincat,draw_lincats(g,i)]), indent([kw_lin,draw_lins(g,i)]), @@ -956,18 +1005,35 @@ function inherited_cats(g) {return all_inherited_cats(inherited_grammars(g),{})} function inherited_funs(g) {return all_inherited_funs(inherited_grammars(g),{})} function inherited_grammars(g) { + // Load the available grammars once var grammar_byname=cached_grammar_byname(); - return (g.extends || []).map(grammar_byname) + var visited={}; + // Then traverse the dependencies to collect all inherited grammars + function ihgs(g) { + if(visited[g.basename]) return []; // avoid cycles and diamonds + else { + visited[g.basename]=true; + var igs=(g.extends || []).map(grammar_byname) + var igss=igs.map(ihgs) + for(var i in igss) igs.concat(igss[i]); + return igs; + } + } + return ihgs(g) } function cached_grammar_byname() { + var gix=cached_grammar_array_byname() + function grammar_byname(name) { return gix[name]; } + return grammar_byname; +} +function cached_grammar_array_byname() { var gix={}; for(var i=0;i