X-Git-Url: http://nitlanguage.org diff --git a/src/ni_nitdoc.nit b/src/ni_nitdoc.nit index 4548e0f..24887b4 100644 --- a/src/ni_nitdoc.nit +++ b/src/ni_nitdoc.nit @@ -28,6 +28,7 @@ class Nitdoc private var arguments: Array[String] private var destinationdir: nullable String private var sharedir: nullable String + private var source: nullable String private var opt_dir = new OptionString("Directory where doc is generated", "-d", "--dir") private var opt_source = new OptionString("What link for source (%f for filename, %l for first line, %L for last line)", "--source") @@ -38,10 +39,12 @@ class Nitdoc # We need a model to collect stufs self.toolcontext = toolcontext self.arguments = toolcontext.option_context.rest + toolcontext.option_context.options.clear toolcontext.option_context.add_option(opt_dir) toolcontext.option_context.add_option(opt_source) toolcontext.option_context.add_option(opt_sharedir) toolcontext.option_context.add_option(opt_nodot) + toolcontext.process_options process_options if arguments.length < 1 then @@ -86,6 +89,11 @@ class Nitdoc abort end end + if not opt_source.value is null then + source = "" + else + source = opt_source.value + end end fun start do @@ -97,11 +105,12 @@ class Nitdoc fullindex modules classes + quicksearch_list end end fun overview do - var overviewpage = new NitdocOverview.with(modelbuilder.nmodules, self.opt_nodot.value, destinationdir.to_s) + var overviewpage = new NitdocOverview.with(modelbuilder, self.opt_nodot.value, destinationdir.to_s) overviewpage.save("{destinationdir.to_s}/index.html") end @@ -120,24 +129,57 @@ class Nitdoc fun classes do for amodule in modelbuilder.nmodules do for mclass, aclassdef in amodule.mclass2nclassdef do - var classpage = new NitdocMClasses.with(mclass, aclassdef) + mclass.amodule(modelbuilder.mmodule2nmodule) + mclass.mmethod(aclassdef.mprop2npropdef) + var classpage = new NitdocMClasses.with(mclass, aclassdef, source) classpage.save("{destinationdir.to_s}/{mclass.name}.html") end end end + # Generate QuickSearch file + fun quicksearch_list do + var file = new OFStream.open("{destinationdir.to_s}/quicksearch-list.js") + var content = new Buffer + content.append("var entries = \{ ") + for prop in model.mproperties do + if not prop isa MMethod then continue + content.append("\"{prop.name}\": [") + for propdef in prop.mpropdefs do + content.append("\{txt: \"{propdef.mproperty.full_name}\", url:\"{propdef.mproperty.link_anchor}\" \}") + if not propdef is prop.mpropdefs.last then content.append(", ") + end + content.append("]") + content.append(", ") + end + + for mclass in model.mclasses do + content.append("\"{mclass.name}\": [") + for mclassdef in mclass.mclassdefs do + content.append("\{txt: \"{mclassdef.mclass.full_name}\", url:\"{mclass.link_anchor}\" \}") + if not mclassdef is mclass.mclassdefs.last then content.append(", ") + end + content.append("]") + if not mclass is model.mclasses.last then content.append(", ") + end + + content.append(" \};") + file.write(content.to_s) + file.close + end + end class NitdocOverview super NitdocPage - var amodules: Array[AModule] + var mbuilder: ModelBuilder # Init with Array[AModule] to get all ifnormations about each MModule containt in a program # opt_nodot to inform about the graph gen # destination: to know where will be saved dot files - init with(modules: Array[AModule], opt_nodot: Bool, destination: String) do - self.amodules = modules + init with(mbuilder: ModelBuilder, opt_nodot: Bool, destination: String) do + self.mbuilder = mbuilder self.opt_nodot = opt_nodot self.destinationdir = destination end @@ -220,32 +262,47 @@ class NitdocOverview end fun add_modules do - var ls = new List[nullable MModule] - for amodule in amodules do - var mmodule = amodule.mmodule.public_owner - if mmodule != null and not ls.has(mmodule) then - open("li") - add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ") - add_html(amodule.comment) - close("li") - ls.add(mmodule) - end + var mmodules = list_mmodules + var sorted = new Array[MModule].from(mmodules) + var sorter = new ComparableSorter[MModule] + sorter.sort(sorted) + for mmodule in sorted do + var amodule = mbuilder.mmodule2nmodule[mmodule] + open("li") + add("a").attr("href", "{mmodule.name}.html").text("{mmodule.to_s} ") + add_html(amodule.short_comment) + close("li") end end fun process_generate_dot do var op = new Buffer op.append("digraph dep \{ 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 amodule in amodules do - op.append("\"{amodule.mmodule.name}\"[URL=\"{amodule.mmodule.name}.html\"];\n") - for mmodule2 in amodule.mmodule.in_importation.direct_greaters do - op.append("\"{amodule.mmodule.name}\"->\"{mmodule2.name}\";\n") + for mmodule in list_mmodules do + op.append("\"{mmodule.name}\"[URL=\"{mmodule.name}.html\"];\n") + for imported in mmodule.in_importation.direct_greaters do + if imported.direct_owner == null then + op.append("\"{mmodule.name}\"->\"{imported.name}\";\n") + end end end op.append("\}\n") generate_dot(op.to_s, "dep", "Modules hierarchy") end + private fun list_mmodules: Set[MModule] do + var mmodules = new HashSet[MModule] + for mmodule in mbuilder.model.mmodules do + var owner = mmodule.public_owner + if owner != null then + mmodules.add(owner) + else + mmodules.add(mmodule) + end + end + return mmodules + end + end class NitdocFullindex @@ -336,10 +393,13 @@ class NitdocFullindex # Add to content modules column fun module_column do var ls = new List[nullable MModule] + var sorted = mmodules + var sorterp = new ComparableSorter[MModule] + sorterp.sort(sorted) open("article").add_class("modules filterable") add("h2").text("Modules") open("ul") - for mmodule in mmodules do + for mmodule in sorted do if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then ls.add(mmodule.public_owner) open("li") @@ -353,11 +413,14 @@ class NitdocFullindex # Add to content classes modules fun classes_column do + var sorted = mmodules.first.imported_mclasses.to_a + var sorterp = new ComparableSorter[MClass] + sorterp.sort(sorted) open("article").add_class("classes filterable") add("h2").text("Classes") open("ul") - for mclass in mmodules.first.imported_mclasses do + for mclass in sorted do open("li") add("a").attr("href", "{mclass.name}.html").text(mclass.name) close("li") @@ -372,8 +435,13 @@ class NitdocFullindex open("article").add_class("properties filterable") add("h2").text("Properties") open("ul") + var sorted_imported = mmodules.first.imported_methods.to_a + var sorted_redef = mmodules.first.redef_methods.to_a + var sorterp = new ComparableSorter[MProperty] + sorterp.sort(sorted_imported) + sorterp.sort(sorted_redef) - for method in mmodules.first.imported_methods do + for method in sorted_imported do if method.visibility is none_visibility or method.visibility is intrude_visibility then continue open("li").add_class("intro") add("span").attr("title", "introduction").text("I") @@ -382,7 +450,7 @@ class NitdocFullindex close("li") end - for method in mmodules.first.redef_methods do + for method in sorted_redef do if method.visibility is none_visibility or method.visibility is intrude_visibility then continue open("li").add_class("redef") add("span").attr("title", "redefinition").text("R") @@ -508,7 +576,10 @@ class NitdocModules add("h3").text("Module Hierarchy").attr("style","cursor: pointer;") if mmodule.in_importation.direct_greaters.length > 0 then add_html("
{stdclassdef.comment}CancelCommit") + close("section") + open("section").add_class("concerns") + add("h2").add_class("section-header").text("Concerns") + open("ul") + for owner in sorted do + var childs = mclass.concerns[owner] + open("li") + add_html("{owner.name}: {owner.amodule.short_comment}") + if not childs is null then + open("ul") + var sortedc = childs.to_a + var sorterpc = new ComparableSorter[MModule] + sorterpc.sort(sortedc) + for child in sortedc do + add_html("
{mmodule.name}: {mmodule.amodule.short_comment}
") + else + add_html("{mmodule.name}: {mmodule.amodule.short_comment}
") + end + end + var sortedc = mmethods.to_a + sorterprop.sort(sortedc) + for prop in sortedc do description(prop) + end + # Insert inherited methods + if mclass.inherited_methods.length > 0 then + var sortedc = new Array[MClass] + sortedc.add_all(mclass.inherited.keys) + sorterc.sort(sortedc) + add("h3").text("Inherited Methods") + for i_mclass in sortedc do + var sortedp = mclass.inherited[i_mclass].to_a + sorterprop.sort(sortedp) + open("p") + add_html("Defined in {i_mclass.name}: ") + for method in sortedp do + add_html("{method.name}") + if method != sortedp.last then add_html(", ") + end + close("p") + end + end + close("section") + end + + # Insert description tags for 'prop' + fun description(prop: MProperty) do + open("article").add_class("fun public {if prop.is_redef then "redef" else ""}").attr("id", "{prop.anchor}") + var sign = prop.name + if prop.apropdef != null then sign += prop.apropdef.signature + add_html("{prop.apropdef.comment}") + end + add_html("CancelCommit") + open("p") + if prop.local_class != mclass then add_html("inherited from {prop.local_class.intro_mmodule.name} ") + #TODO display show code if doc github + add_html("defined by the module {prop.intro_mclassdef.mmodule.name} {if prop.apropdef is null then "" else show_source(prop.apropdef.location)}.") + + for parent in mclass.parents do + if prop isa MMethod then if parent.constructors.has(prop) then add_html(" Previously defined by: {parent.intro_mmodule.name} for {parent.name}.") + end + close("p") + close("div") + + close("article") + end + end class NitdocPage @@ -743,6 +1014,7 @@ class NitdocPage var opt_nodot: Bool var destinationdir : String + var source: nullable String redef fun head do add("meta").attr("charset", "utf-8") @@ -770,6 +1042,23 @@ class NitdocPage fmap.close end + # Add a (source) link fo a given location + fun show_source(l: Location): String + do + if source == null then + return "({l.file.filename.simplify_path})" + else + # THIS IS JUST UGLY ! (but there is no replace yet) + var x = source.split_with("%f") + source = x.join(l.file.filename.simplify_path) + x = source.split_with("%l") + source = x.join(l.line_start.to_s) + x = source.split_with("%L") + source = x.join(l.line_end.to_s) + return " (show code)" + end + end + end redef class AModule @@ -797,6 +1086,10 @@ end redef class MModule + super Comparable + redef type OTHER: MModule + redef fun <(other: OTHER): Bool do return self.name < other.name + var amodule: nullable AModule # Get the list of all methods in a module @@ -824,6 +1117,10 @@ end redef class MProperty + super Comparable + redef type OTHER: MProperty + redef fun <(other: OTHER): Bool do return self.name < other.name + var is_redef: Bool var apropdef: nullable APropdef @@ -854,6 +1151,10 @@ end redef class MClass + super Comparable + redef type OTHER: MClass + redef fun <(other: OTHER): Bool do return self.name < other.name + # Associate all MMethods to each MModule concerns fun all_methods: HashMap[MModule, Set[MMethod]] do var hm = new HashMap[MModule, Set[MMethod]] @@ -893,11 +1194,197 @@ redef class MClass return hm end + fun public_owner: MModule do + var owner = intro_mmodule + if owner.public_owner is null then + return owner + else + return owner.public_owner.as(not null) + end + end + + # Associate Amodule to all MModule concern by 'self' + fun amodule(amodules: HashMap[MModule, AModule]) do + for owner, childs in concerns do + if childs != null then for child in childs do child.amodule = amodules[child] + owner.amodule = amodules[owner] + end + end + + # Associate MClass to all MMethod include in 'inherited_methods' + fun inherited: HashMap[MClass, Set[MMethod]] do + var hm = new HashMap[MClass, Set[MMethod]] + for method in inherited_methods do + var mclass = method.intro_mclassdef.mclass + if not hm.has_key(mclass) then hm[mclass] = new HashSet[MMethod] + hm[mclass].add(method) + end + return hm + end + + # Return true if MModule concern contain subMModule + fun has_mmodule(sub: MModule): Bool do + for mmodule, childs in concerns do + if childs is null then continue + if childs.has(sub) then return true + end + return false + end + + fun mmethod(mprop2npropdef: Map[MProperty, APropdef]) do + for const in constructors do + if mprop2npropdef.has_key(const)then + const.apropdef = mprop2npropdef[const].as(AMethPropdef) + end + end + + for intro in intro_methods do + if mprop2npropdef.has_key(intro)then + if mprop2npropdef[intro] isa AMethPropdef then intro.apropdef = mprop2npropdef[intro].as(AMethPropdef) + end + end + + for rd in redef_methods do + if mprop2npropdef.has_key(rd)then + if mprop2npropdef[rd] isa AMethPropdef then rd.apropdef = mprop2npropdef[rd].as(AMethPropdef) + end + end + end + + fun link_anchor: String do + return "{name}.html" + end + +end + +redef class AStdClassdef + private fun comment: String do + var ret = "" + if n_doc != null then + for t in n_doc.n_comment do + var txt = t.text.replace("# ", "") + txt = txt.replace("#", "") + ret += "{txt}" + end + end + return ret + end + + private fun short_comment: String do + var ret = "" + if n_doc != null then + var txt = n_doc.n_comment.first.text + txt = txt.replace("# ", "") + txt = txt.replace("\n", "") + ret += txt + end + return ret + end +end + +redef class ASignature + redef fun to_s do + #TODO closures + var ret = "" + if not n_params.is_empty then + ret = "{ret}({n_params.join(", ")})" + end + if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}" + return ret + end +end + +redef class AParam + redef fun to_s do + var ret = "{n_id.text}" + if n_type != null then + ret = "{ret}: {n_type.to_s}" + if n_dotdotdot != null then ret = "{ret}..." + end + return ret + end +end + +redef class AType + redef fun to_s do + var ret = "{n_id.text}" + if n_kwnullable != null then ret = "nullable {ret}" + if not n_types.is_empty then ret = "{ret}[{n_types.join(", ")}]" + return ret + end +end + +redef class APropdef + private fun short_comment: String is abstract + private fun signature: String is abstract + private fun comment: String is abstract +end + +redef class AAttrPropdef + redef fun short_comment do + var ret = "" + if n_doc != null then + var txt = n_doc.n_comment.first.text + txt = txt.replace("# ", "") + txt = txt.replace("\n", "") + ret += txt + end + return ret + end +end + +redef class AMethPropdef + redef fun short_comment do + var ret = "" + if n_doc != null then + var txt = n_doc.n_comment.first.text + txt = txt.replace("# ", "") + txt = txt.replace("\n", "") + ret += txt + end + return ret + end + + redef fun signature: String do + var sign = "" + if n_signature != null then sign = " {n_signature.to_s}" + return sign + end + + redef private fun comment: String do + var ret = "" + if n_doc != null then + for t in n_doc.n_comment do + var txt = t.text.replace("# ", "") + txt = txt.replace("#", "") + ret += "{txt}" + end + end + return ret + end +end + +redef class MClassDef + private fun namespace(mclass: MClass): String do + + if mmodule.public_owner is null then + return "{mmodule.full_name}::{mclass.name}" + else if mclass is self.mclass then + return "{mmodule.public_owner.name}::{mclass.name}" + else + return "{mmodule.public_owner.name}::{mclass.name}" + end + end +end + +redef class Set[E] + fun last: E do + return to_a[length-1] + end end # Create a tool context to handle options and paths var toolcontext = new ToolContext -toolcontext.process_options # Here we launch the nit index var nitdoc = new Nitdoc(toolcontext)