X-Git-Url: http://nitlanguage.org diff --git a/src/doc/doc_pages.nit b/src/doc/doc_pages.nit index 9c38d44..139952f 100644 --- a/src/doc/doc_pages.nit +++ b/src/doc/doc_pages.nit @@ -17,6 +17,7 @@ module doc_pages import toolcontext import doc_model +private import json::static redef class ToolContext private var opt_dir = new OptionString("output directory", "-d", "--dir") @@ -86,15 +87,9 @@ end # The Nitdoc class explores the model and generate pages for each mentities found class Nitdoc + var ctx: ToolContext var model: Model var mainmodule: MModule - var ctx: ToolContext - - init(ctx: ToolContext, model: Model, mainmodule: MModule) do - self.ctx = ctx - self.model = model - self.mainmodule = mainmodule - end fun generate do init_output_dir @@ -115,11 +110,7 @@ class Nitdoc var sharedir = ctx.opt_sharedir.value if sharedir == null then var dir = ctx.nit_dir - if dir == null then - print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR" - abort - end - sharedir = "{dir}/share/nitdoc" + sharedir = dir/"share/nitdoc" if not sharedir.file_exists then print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR" abort @@ -127,9 +118,9 @@ class Nitdoc end # copy shared files if ctx.opt_shareurl.value == null then - sys.system("cp -r {sharedir.to_s}/* {output_dir.to_s}/") + sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/") else - sys.system("cp -r {sharedir.to_s}/resources/ {output_dir.to_s}/resources/") + sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/") end end @@ -163,6 +154,7 @@ class Nitdoc private fun classes do for mclass in model.mclasses do + if mclass.visibility <= ctx.min_visibility then continue var page = new NitdocClass(ctx, model, mainmodule, mclass) page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}") end @@ -170,6 +162,9 @@ class Nitdoc private fun properties do for mproperty in model.mproperties do + if mproperty.visibility <= ctx.min_visibility then continue + if mproperty isa MInnerClass then continue + if mproperty isa MAttribute then continue var page = new NitdocProperty(ctx, model, mainmodule, mproperty) page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}") end @@ -190,56 +185,80 @@ end # All entities are grouped by name to make the research easier. class QuickSearch - private var mmodules = new HashSet[MModule] - private var mclasses = new HashSet[MClass] - private var mpropdefs = new HashMap[String, Set[MPropDef]] + private var table = new QuickSearchTable - init(ctx: ToolContext, model: Model) do + var ctx: ToolContext + var model: Model + + init do for mmodule in model.mmodules do if mmodule.is_fictive then continue - mmodules.add mmodule + add_result_for(mmodule.name, mmodule.full_name, mmodule.nitdoc_url) end for mclass in model.mclasses do if mclass.visibility < ctx.min_visibility then continue - mclasses.add mclass + add_result_for(mclass.name, mclass.full_name, mclass.nitdoc_url) end for mproperty in model.mproperties do if mproperty.visibility < ctx.min_visibility then continue if mproperty isa MAttribute then continue - if not mpropdefs.has_key(mproperty.name) then - mpropdefs[mproperty.name] = new HashSet[MPropDef] + for mpropdef in mproperty.mpropdefs do + var full_name = mpropdef.mclassdef.mclass.full_name + var cls_url = mpropdef.mclassdef.mclass.nitdoc_url + var def_url = "{cls_url}#{mpropdef.mproperty.nitdoc_id}" + add_result_for(mproperty.name, full_name, def_url) end - mpropdefs[mproperty.name].add_all(mproperty.mpropdefs) end end + private fun add_result_for(query: String, txt: String, url: String) do + table[query].add new QuickSearchResult(txt, url) + end + fun render: Template do var tpl = new Template - tpl.add "var nitdocQuickSearchRawList=\{ " - for mmodule in mmodules do - tpl.add "\"{mmodule.name}\":[" - tpl.add "\{txt:\"{mmodule.full_name}\",url:\"{mmodule.nitdoc_url}\"\}," - tpl.add "]," - end - for mclass in mclasses do - var full_name = mclass.intro.mmodule.full_name - tpl.add "\"{mclass.name}\":[" - tpl.add "\{txt:\"{full_name}\",url:\"{mclass.nitdoc_url}\"\}," - tpl.add "]," - end - for mproperty, mprops in mpropdefs do - tpl.add "\"{mproperty}\":[" - for mpropdef in mprops do - var full_name = mpropdef.mclassdef.mclass.full_name - tpl.add "\{txt:\"{full_name}\",url:\"{mpropdef.nitdoc_url}\"\}," - end - tpl.add "]," - end - tpl.add " \};" + var buffer = new RopeBuffer + tpl.add buffer + buffer.append "var nitdocQuickSearchRawList=" + table.append_json buffer + buffer.append ";" return tpl end end +# The result map for QuickSearch. +private class QuickSearchTable + super JsonMapRead[String, QuickSearchResultList] + super HashMap[String, QuickSearchResultList] + + redef fun provide_default_value(key) do + var v = new QuickSearchResultList + self[key] = v + return v + end +end + +# A QuickSearch result list. +private class QuickSearchResultList + super JsonSequenceRead[QuickSearchResult] + super Array[QuickSearchResult] +end + +# A QuickSearch result. +private class QuickSearchResult + super Jsonable + + # The text of the link. + var txt: String + + # The destination of the link. + var url: String + + redef fun to_json do + return "\{\"txt\":{txt.to_json},\"url\":{url.to_json}\}" + end +end + # Nitdoc base page # Define page structure and properties abstract class NitdocPage @@ -249,12 +268,6 @@ abstract class NitdocPage private var mainmodule: MModule private var name_sorter = new MEntityNameSorter - init(ctx: ToolContext, model: Model, mainmodule: MModule) do - self.ctx = ctx - self.model = model - self.mainmodule = mainmodule - end - # Render the page as a html template fun render: Template do var shareurl = "." @@ -320,14 +333,16 @@ abstract class NitdocPage # Clickable graphviz image using dot format # return null if no graph for this page - fun tpl_graph(dot: FlatBuffer, name: String, title: nullable String): nullable TplArticle do + fun tpl_graph(dot: Buffer, name: String, title: nullable String): nullable TplArticle do if ctx.opt_nodot.value then return null var output_dir = ctx.output_dir - var file = new OFStream.open("{output_dir}/{name}.dot") + var path = output_dir / name + var path_sh = path.escape_to_sh + var file = new OFStream.open("{path}.dot") file.write(dot) file.close - sys.system("\{ test -f {output_dir}/{name}.png && test -f {output_dir}/{name}.s.dot && diff {output_dir}/{name}.dot {output_dir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {output_dir}/{name}.dot {output_dir}/{name}.s.dot && dot -Tpng -o{output_dir}/{name}.png -Tcmapx -o{output_dir}/{name}.map {output_dir}/{name}.s.dot ; \}") - var fmap = new IFStream.open("{output_dir}/{name}.map") + sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}") + var fmap = new IFStream.open("{path}.map") var map = fmap.read_all fmap.close @@ -335,11 +350,12 @@ abstract class NitdocPage var alt = "" if title != null then article.title = title - alt = "alt='{title}'" + alt = "alt='{title.html_escape}'" end article.css_classes.add "text-center" var content = new Template - content.add "" + var name_html = name.html_escape + content.add "" content.add map article.content = content return article @@ -350,7 +366,10 @@ abstract class NitdocPage do if location == null then return null var source = ctx.opt_source.value - if source == null then return location.file.filename.simplify_path + if source == null then + var url = location.file.filename.simplify_path + return "View Source" + end # THIS IS JUST UGLY ! (but there is no replace yet) var x = source.split_with("%f") source = x.join(location.file.filename.simplify_path) @@ -463,28 +482,72 @@ abstract class NitdocPage end # MProp description template - fun tpl_mprop_article(mproperty: MProperty, mpropdefs: Array[MPropDef]): TplArticle do - var article = mproperty.tpl_article - if not mpropdefs.has(mproperty.intro) then - # add intro synopsys - var intro_article = mproperty.intro.tpl_short_article - intro_article.source_link = tpl_showsource(mproperty.intro.location) - article.add_child intro_article + # + # `main_mpropdef`: The most important mpropdef to display + # `local_mpropdefs`: List of other locally defined mpropdefs to display + # `lin`: full linearization from local_mpropdefs to intro (displayed in redef tree) + fun tpl_mprop_article(main_mpropdef: MPropDef, local_mpropdefs: Array[MPropDef], + lin: Array[MPropDef]): TplArticle do + var mprop = main_mpropdef.mproperty + var article = new TplArticle(mprop.nitdoc_id) + var title = new Template + title.add mprop.tpl_icon + title.add "" + if main_mpropdef.is_intro then + title.add mprop.tpl_link + title.add mprop.intro.tpl_signature + else + var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url + var def_url = "{cls_url}#{mprop.nitdoc_id}" + var lnk = new TplLink.with_title(def_url, mprop.name, "Go to introduction") + title.add "redef " + title.add lnk + end + article.title = title + article.title_classes.add "signature" + article.summary_title = "{mprop.nitdoc_name}" + article.subtitle = main_mpropdef.tpl_namespace + if main_mpropdef.mdoc != null then + article.content = main_mpropdef.mdoc.tpl_comment + end + var subarticle = new TplArticle("{main_mpropdef.nitdoc_id}_redefs") + # Add redef in same `MClass` + if local_mpropdefs.length > 1 then + for mpropdef in local_mpropdefs do + if mpropdef == main_mpropdef then continue + var redef_article = new TplArticle("{mpropdef.nitdoc_id}") + var redef_title = new Template + redef_title.add "also redef in " + redef_title.add mpropdef.tpl_namespace + redef_article.title = redef_title + redef_article.title_classes.add "signature info" + redef_article.css_classes.add "nospace" + var redef_content = new Template + if mpropdef.mdoc != null then + redef_content.add mpropdef.mdoc.tpl_comment + end + redef_article.content = redef_content + subarticle.add_child redef_article + end end - mainmodule.linearize_mpropdefs(mpropdefs) - for mpropdef in mpropdefs do - # add mpropdef description - var redef_article = mpropdef.tpl_article - redef_article.source_link = tpl_showsource(mpropdef.location) - article.add_child redef_article + # Add linearization + if lin.length > 1 then + var lin_article = new TplArticle("{main_mpropdef.nitdoc_id}_lin") + lin_article.title = "Inheritance" + var lst = new TplList.with_classes(["list-unstyled", "list-labeled"]) + for mpropdef in lin do + lst.add_li mpropdef.tpl_inheritance_item + end + lin_article.content = lst + subarticle.add_child lin_article end + article.add_child subarticle return article end # MProperty description template fun tpl_mpropdef_article(mpropdef: MPropDef): TplArticle do var article = mpropdef.tpl_article - if mpropdef.is_intro then article.content = null article.source_link = tpl_showsource(mpropdef.location) return article end @@ -622,13 +685,11 @@ class NitdocGroup private var mgroup: MGroup - private var concerns: ConcernsTree - private var intros: Set[MClass] - private var redefs: Set[MClass] + private var concerns: ConcernsTree is noinit + private var intros: Set[MClass] is noinit + private var redefs: Set[MClass] is noinit - init(ctx: ToolContext, model: Model, mainmodule: MModule, mgroup: MGroup) do - super - self.mgroup = mgroup + init do self.concerns = model.concerns_tree(mgroup.collect_mmodules) self.concerns.sort_with(new MConcernRankSorter) self.intros = mgroup.in_nesting_intro_mclasses(ctx.min_visibility) @@ -749,14 +810,12 @@ class NitdocModule super NitdocPage private var mmodule: MModule - private var concerns: ConcernsTree - private var mclasses2mdefs: Map[MClass, Set[MClassDef]] - private var mmodules2mclasses: Map[MModule, Set[MClass]] + private var concerns: ConcernsTree is noinit + private var mclasses2mdefs: Map[MClass, Set[MClassDef]] is noinit + private var mmodules2mclasses: Map[MModule, Set[MClass]] is noinit - init(ctx: ToolContext, model: Model, mainmodule: MModule, mmodule: MModule) do - super - self.mmodule = mmodule + init do var mclassdefs = new HashSet[MClassDef] mclassdefs.add_all mmodule.intro_mclassdefs(ctx.min_visibility) mclassdefs.add_all mmodule.redef_mclassdefs(ctx.min_visibility) @@ -958,17 +1017,17 @@ class NitdocModule end end # build graph - var op = new FlatBuffer - var name = "dep_{mmodule.name}" - op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n") + var op = new RopeBuffer + var name = "dep_module_{mmodule.nitdoc_id}" + op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n") for mmodule in poset do if mmodule == self.mmodule then - op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n") + op.append("\"{mmodule.name.escape_to_dot}\"[shape=box,margin=0.03];\n") else - op.append("\"{mmodule.name}\"[URL=\"{mmodule.nitdoc_url}\"];\n") + op.append("\"{mmodule.name.escape_to_dot}\"[URL=\"{mmodule.nitdoc_url.escape_to_dot}\"];\n") end for omodule in poset[mmodule].direct_greaters do - op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n") + op.append("\"{mmodule.name.escape_to_dot}\"->\"{omodule.name.escape_to_dot}\";\n") end end op.append("\}\n") @@ -992,13 +1051,11 @@ class NitdocClass super NitdocPage private var mclass: MClass - private var concerns: ConcernsTree - private var mprops2mdefs: Map[MProperty, Set[MPropDef]] - private var mmodules2mprops: Map[MModule, Set[MProperty]] + private var concerns: ConcernsTree is noinit + private var mprops2mdefs: Map[MProperty, Set[MPropDef]] is noinit + private var mmodules2mprops: Map[MModule, Set[MProperty]] is noinit - init(ctx: ToolContext, model: Model, mainmodule: MModule, mclass: MClass) do - super - self.mclass = mclass + init do var mpropdefs = new HashSet[MPropDef] mpropdefs.add_all mclass.intro_mpropdefs(ctx.min_visibility) mpropdefs.add_all mclass.redef_mpropdefs(ctx.min_visibility) @@ -1052,10 +1109,14 @@ class NitdocClass var classes = mprop.intro.tpl_css_classes.to_a if not mprops2mdefs.has_key(mprop) then classes.add "inherit" - var lnk = new Template - lnk.add new TplLabel.with_classes(classes) - lnk.add mprop.intro.tpl_link - return new TplListItem.with_content(lnk) + var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url + var def_url = "{cls_url}#{mprop.nitdoc_id}" + var lnk = new TplLink(def_url, mprop.name) + if mprop.intro.mdoc != null then lnk.title = mprop.intro.mdoc.short_comment + var item = new Template + item.add new TplLabel.with_classes(classes) + item.add lnk + return new TplListItem.with_content(item) end var defs = mprops2mdefs[mprop] if defs.has(mprop.intro) then @@ -1065,7 +1126,7 @@ class NitdocClass end var lnk = new Template lnk.add new TplLabel.with_classes(classes) - lnk.add mprop.intro.tpl_anchor + lnk.add mprop.tpl_anchor return new TplListItem.with_content(lnk) end @@ -1131,8 +1192,8 @@ class NitdocClass var mclasses = new HashSet[MClass] mclasses.add_all hancestors mclasses.add_all hparents - if hchildren.length < 10 then mclasses.add_all hchildren - if hdescendants.length < 10 then mclasses.add_all hdescendants + mclasses.add_all hchildren + mclasses.add_all hdescendants mclasses.add mclass var graph = tpl_dot(mclasses) if graph != null then section.add_child graph @@ -1152,14 +1213,14 @@ class NitdocClass end # children - if not hchildren.is_empty and hchildren.length < 15 then + if not hchildren.is_empty then var lst = hchildren.to_a name_sorter.sort lst section.add_child tpl_list("children", "Children", lst) end # descendants - if not hdescendants.is_empty and hchildren.length < 15 then + if not hdescendants.is_empty then var lst = hdescendants.to_a name_sorter.sort lst section.add_child tpl_list("descendants", "Descendants", lst) @@ -1170,9 +1231,18 @@ class NitdocClass private fun tpl_list(id: String, title: String, elts: Array[MClass]): TplArticle do var article = new TplArticle.with_title(id, title) - var list = new TplList.with_classes(["list-unstyled", "list-definition"]) - for elt in elts do list.elts.add elt.tpl_list_item - article.content = list + if elts.length > 20 then + var tpl = new Template + for e in elts do + tpl.add e.tpl_link + if e != elts.last then tpl.add ", " + end + article.content = tpl + else + var list = new TplList.with_classes(["list-unstyled", "list-definition"]) + for elt in elts do list.elts.add elt.tpl_list_item + article.content = list + end return article end @@ -1196,33 +1266,48 @@ class NitdocClass var kind_map = sort_by_kind(mprops) # virtual types - var elts = kind_map["type"].to_a - name_sorter.sort(elts) - for elt in elts do - var defs = mprops2mdefs[elt].to_a - section.add_child tpl_mprop_article(elt, defs) + for article in tpl_mproperty_articles(kind_map, "type") do + section.add_child article end - # constructors - elts = kind_map["init"].to_a - name_sorter.sort(elts) - for elt in elts do - var defs = mprops2mdefs[elt].to_a - section.add_child tpl_mprop_article(elt, defs) + for article in tpl_mproperty_articles(kind_map, "init") do + section.add_child article end - # methods - elts = kind_map["fun"].to_a - name_sorter.sort(elts) - for elt in elts do - var defs = mprops2mdefs[elt].to_a - section.add_child tpl_mprop_article(elt, defs) + for article in tpl_mproperty_articles(kind_map, "fun") do + section.add_child article end parent.add_child section end end end + private fun tpl_mproperty_articles(kind_map: Map[String, Set[MProperty]], + kind_name: String): Sequence[TplArticle] do + var articles = new List[TplArticle] + var elts = kind_map[kind_name].to_a + name_sorter.sort(elts) + for elt in elts do + var local_defs = mprops2mdefs[elt] + # var all_defs = elt.mpropdefs + var all_defs = new HashSet[MPropDef] + for local_def in local_defs do + all_defs.add local_def + var mpropdef = local_def + while not mpropdef.is_intro do + mpropdef = mpropdef.lookup_next_definition(mainmodule, mpropdef.mclassdef.bound_mtype) + all_defs.add mpropdef + end + end + var loc_lin = local_defs.to_a + mainmodule.linearize_mpropdefs(loc_lin) + var all_lin = all_defs.to_a + mainmodule.linearize_mpropdefs(all_lin) + articles.add tpl_mprop_article(loc_lin.first, loc_lin, all_lin) + end + return articles + end + redef fun tpl_content do tpl_sidebar_properties var top = tpl_intro @@ -1305,6 +1390,7 @@ class NitdocClass for mclass in mclasses do poset.add_node mclass for oclass in mclasses do + if mclass == oclass then continue poset.add_node oclass if mclass.in_hierarchy(mainmodule) < oclass then poset.add_edge(mclass, oclass) @@ -1312,17 +1398,31 @@ class NitdocClass end end - var op = new FlatBuffer - var name = "dep_{mclass.name}" - op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n") - for c in poset do + var op = new RopeBuffer + var name = "dep_class_{mclass.nitdoc_id}" + op.append("digraph \"{name.escape_to_dot}\" \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n") + var classes = poset.to_a + var todo = new Array[MClass] + var done = new HashSet[MClass] + mainmodule.linearize_mclasses(classes) + if not classes.is_empty then todo.add classes.first + while not todo.is_empty do + var c = todo.shift + if done.has(c) then continue + done.add c if c == mclass then - op.append("\"{c.name}\"[shape=box,margin=0.03];\n") + op.append("\"{c.name.escape_to_dot}\"[shape=box,margin=0.03];\n") else - op.append("\"{c.name}\"[URL=\"{c.nitdoc_url}\"];\n") + op.append("\"{c.name.escape_to_dot}\"[URL=\"{c.nitdoc_url.escape_to_dot}\"];\n") end - for c2 in poset[c].direct_greaters do - op.append("\"{c.name}\"->\"{c2.name}\";\n") + var smallers = poset[c].direct_smallers + if smallers.length < 10 then + for c2 in smallers do + op.append("\"{c2.name.escape_to_dot}\"->\"{c.name.escape_to_dot}\";\n") + end + todo.add_all smallers + else + op.append("\"...\"->\"{c.name.escape_to_dot}\";\n") end end op.append("\}\n") @@ -1335,11 +1435,10 @@ class NitdocProperty super NitdocPage private var mproperty: MProperty - private var concerns: ConcernsTree - private var mmodules2mdefs: Map[MModule, Set[MPropDef]] + private var concerns: ConcernsTree is noinit + private var mmodules2mdefs: Map[MModule, Set[MPropDef]] is noinit - init(ctx: ToolContext, model: Model, mainmodule: MModule, mproperty: MProperty) do - super + init do self.mproperty = mproperty self.mmodules2mdefs = sort_by_mmodule(collect_mpropdefs) self.concerns = model.concerns_tree(mmodules2mdefs.keys) @@ -1378,13 +1477,12 @@ class NitdocProperty end private fun tpl_intro: TplSection do - var section = new TplSection.with_title("top", tpl_title) - section.subtitle = mproperty.tpl_declaration - var article = new TplArticle("comment") - if mproperty.intro.mdoc != null then - article.content = mproperty.intro.mdoc.tpl_comment - end - section.add_child article + var title = new Template + title.add mproperty.nitdoc_name + title.add mproperty.intro.tpl_signature + var section = new TplSection.with_title("top", title) + section.subtitle = mproperty.tpl_namespace + section.summary_title = mproperty.nitdoc_name return section end