X-Git-Url: http://nitlanguage.org diff --git a/src/ni_nitdoc.nit b/src/ni_nitdoc.nit index 30e4c28..339a77f 100644 --- a/src/ni_nitdoc.nit +++ b/src/ni_nitdoc.nit @@ -1,7 +1,5 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2008 Jean Privat -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -14,1185 +12,1831 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Documentation generator for the nit language. +# Generate API documentation in HTML format from nit source code. module ni_nitdoc import model_utils -import abstract_compiler -import html +import modelize_property +import markdown + +# The NitdocContext contains all the knowledge used for doc generation +class NitdocContext -class Nitdoc - private var toolcontext: ToolContext + private var toolcontext = new ToolContext private var model: Model - private var modelbuilder: ModelBuilder + private var mbuilder: ModelBuilder private var mainmodule: MModule + private var class_hierarchy: POSet[MClass] private var arguments: Array[String] - private var destinationdir: nullable String - private var sharedir: nullable String + private var output_dir: nullable String + private var dot_dir: nullable String + private var share_dir: nullable String + private var source: nullable String + private var min_visibility: MVisibility 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") private var opt_sharedir = new OptionString("Directory containing the nitdoc files", "--sharedir") private var opt_nodot = new OptionBool("Do not generate graphes with graphiviz", "--no-dot") + private var opt_private: OptionBool = new OptionBool("Generate the private API", "--private") - init(toolcontext: ToolContext) do - # We need a model to collect stufs - self.toolcontext = toolcontext - self.arguments = toolcontext.option_context.rest + private var opt_custom_title: OptionString = new OptionString("Title displayed in the top of the Overview page and as suffix of all page names", "--custom-title") + private var opt_custom_menu_items: OptionString = new OptionString("Items displayed in menu before the 'Overview' item (Each item must be enclosed in 'li' tags)", "--custom-menu-items") + private var opt_custom_overview_text: OptionString = new OptionString("Text displayed as introduction of Overview page before the modules list", "--custom-overview-text") + private var opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text") + + private var opt_github_base: OptionString = new OptionString("The branch (or git ref) edited commits will be pulled into (ex: octocat:master)", "--github-base") + private var opt_github_head: OptionString = new OptionString("The reference branch name used to create pull requests (ex: master)", "--github-head") + + init do 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) - process_options + toolcontext.option_context.add_option(opt_private) + toolcontext.option_context.add_option(opt_custom_title) + toolcontext.option_context.add_option(opt_custom_footer_text) + toolcontext.option_context.add_option(opt_custom_overview_text) + toolcontext.option_context.add_option(opt_custom_menu_items) + toolcontext.option_context.add_option(opt_github_base) + toolcontext.option_context.add_option(opt_github_head) + toolcontext.process_options + self.arguments = toolcontext.option_context.rest if arguments.length < 1 then + print "usage: nitdoc [options] file..." toolcontext.option_context.usage exit(1) end model = new Model - modelbuilder = new ModelBuilder(model, toolcontext) - - # Here we load an process std modules - var mmodules = modelbuilder.parse_and_build([arguments.first]) + mbuilder = new ModelBuilder(model, toolcontext) + # Here we load an process all modules passed on the command line + var mmodules = mbuilder.parse(arguments) if mmodules.is_empty then return - modelbuilder.full_propdef_semantic_analysis - assert mmodules.length == 1 - self.mainmodule = mmodules.first + mbuilder.run_phases + + if mmodules.length == 1 then + mainmodule = mmodules.first + else + # We need a main module, so we build it by importing all modules + mainmodule = new MModule(model, null, "
", new Location(null, 0, 0, 0, 0)) + mainmodule.set_imported_mmodules(mmodules) + end + self.class_hierarchy = mainmodule.flatten_mclass_hierarchy + self.process_options end private fun process_options do if not opt_dir.value is null then - destinationdir = opt_dir.value + output_dir = opt_dir.value else - destinationdir = "nitdoc_directory" + output_dir = "doc" end if not opt_sharedir.value is null then - sharedir = opt_sharedir.value + share_dir = opt_sharedir.value else var dir = "NIT_DIR".environ if dir.is_empty then - dir = "{sys.program_name.dirname}/../share/nitdoc" + dir = "{sys.program_name.dirname}/../share/ni_nitdoc" else - dir = "{dir}/share/nitdoc" + dir = "{dir}/share/ni_nitdoc" end - sharedir = dir - if sharedir is null then + share_dir = dir + if share_dir is null then print "Error: Cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR" abort end - dir = "{sharedir.to_s}/scripts/js-facilities.js" - if sharedir is null then + dir = "{share_dir.to_s}/scripts/js-facilities.js" + if share_dir is null then print "Error: Invalid nitdoc share files. Check --sharedir or envvar NIT_DIR" abort end + + if opt_private.value then + min_visibility = none_visibility + else + min_visibility = protected_visibility + end end + source = opt_source.value + end + + fun generate_nitdoc do + # Create destination dir if it's necessary + if not output_dir.file_exists then output_dir.mkdir + sys.system("cp -r {share_dir.to_s}/* {output_dir.to_s}/") + self.dot_dir = null + if not opt_nodot.value then self.dot_dir = output_dir.to_s + overview + search + modules + classes + quicksearch_list end - fun start do - if arguments.length == 1 then - # Create destination dir if it's necessary - if not destinationdir.file_exists then destinationdir.mkdir - sys.system("cp -r {sharedir.to_s}/* {destinationdir.to_s}/") - overview - fullindex - modules - classes - end + private fun overview do + var overviewpage = new NitdocOverview(self, dot_dir) + overviewpage.save("{output_dir.to_s}/index.html") end - fun overview do - var overviewpage = new NitdocOverview.with(modelbuilder.nmodules, self.opt_nodot.value, destinationdir.to_s) - overviewpage.save("{destinationdir.to_s}/index.html") + private fun search do + var searchpage = new NitdocSearch(self) + searchpage.save("{output_dir.to_s}/search.html") end - fun fullindex do - var fullindex = new NitdocFullindex.with(model.mmodules) - fullindex.save("{destinationdir.to_s}/full-index.html") + private fun modules do + for mmodule in model.mmodules do + if mmodule.name == "
" then continue + var modulepage = new NitdocModule(mmodule, self, dot_dir) + modulepage.save("{output_dir.to_s}/{mmodule.url}") + end end - fun modules do - for mod in modelbuilder.nmodules do - var modulepage = new NitdocModules.with(mod) - modulepage.save("{destinationdir.to_s}/{mod.mmodule.name}.html") + private fun classes do + for mclass in mbuilder.model.mclasses do + var classpage = new NitdocClass(mclass, self, dot_dir, source) + classpage.save("{output_dir.to_s}/{mclass.url}") end end - fun classes do - for amodule in modelbuilder.nmodules do - for mclass, aclassdef in amodule.mclass2nclassdef do - mclass.amodule(modelbuilder.mmodule2nmodule) - mclass.mmethod(aclassdef.mprop2npropdef) - var classpage = new NitdocMClasses.with(mclass, aclassdef) - classpage.save("{destinationdir.to_s}/{mclass.name}.html") + private fun quicksearch_list do + var file = new OFStream.open("{output_dir.to_s}/quicksearch-list.js") + file.write("var entries = \{ ") + for mmodule in model.mmodules do + file.write("\"{mmodule.name}\": [") + file.write("\{txt: \"{mmodule.full_name}\", url:\"{mmodule.url}\" \},") + file.write("],") + end + for mclass in model.mclasses do + if mclass.visibility < min_visibility then continue + file.write("\"{mclass.name}\": [") + file.write("\{txt: \"{mclass.full_name}\", url:\"{mclass.url}\" \},") + file.write("],") + end + var name2mprops = new HashMap[String, Set[MPropDef]] + for mproperty in model.mproperties do + if mproperty.visibility < min_visibility then continue + if mproperty isa MAttribute then continue + if not name2mprops.has_key(mproperty.name) then name2mprops[mproperty.name] = new HashSet[MPropDef] + name2mprops[mproperty.name].add_all(mproperty.mpropdefs) + end + for mproperty, mpropdefs in name2mprops do + file.write("\"{mproperty}\": [") + for mpropdef in mpropdefs do + file.write("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},") end + file.write("],") end + file.write(" \};") + file.close end end +# Nitdoc base page +abstract class NitdocPage + + var dot_dir: nullable String + var source: nullable String + var ctx: NitdocContext + + init(ctx: NitdocContext) do + self.ctx = ctx + end + + protected fun head do + append("") + append("") + append("") + append("") + append("") + append("") + append("") + append("") + append("") + append("") + var title = "" + if ctx.opt_custom_title.value != null then + title = " | {ctx.opt_custom_title.value.to_s}" + end + append("{self.title}{title}") + end + + protected fun menu do + if ctx.opt_custom_menu_items.value != null then + append(ctx.opt_custom_menu_items.value.to_s) + end + end + + protected fun title: String is abstract + + protected fun header do + append("
") + append("") + append("
") + end + + protected fun content is abstract + + protected fun footer do + if ctx.opt_custom_footer_text.value != null then + append("
{ctx.opt_custom_footer_text.value.to_s}
") + end + end + + # Generate a clickable graphviz image using a dot content + protected fun generate_dot(dot: String, name: String, alt: String) do + var output_dir = dot_dir + if output_dir == null then return + var file = new OFStream.open("{output_dir}/{name}.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 ; \}") + append("
") + append("{alt}") + append("
") + var fmap = new IFStream.open("{output_dir}/{name}.map") + append(fmap.read_all) + fmap.close + end + + # Add a (source) link for a given location + protected 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 " (source)" + end + end + + # Render the page as a html string + protected fun render do + append("") + append("") + head + append("") + append("") + header + append("
") + content + append("
") + footer + append("") + end + + # Append a string to the page + fun append(s: String) do out.write(s) + + # Save html page in the specified file + fun save(file: String) do + self.out = new OFStream.open(file) + render + self.out.close + end + private var out: nullable OFStream +end + +# The overview page class NitdocOverview super NitdocPage + private var mbuilder: ModelBuilder + private var mmodules = new Array[MModule] + + init(ctx: NitdocContext, dot_dir: nullable String) do + super(ctx) + self.mbuilder = ctx.mbuilder + self.dot_dir = dot_dir + # get modules + var mmodules = new HashSet[MModule] + for mmodule in mbuilder.model.mmodules do + if mmodule.name == "
" then continue + var owner = mmodule.public_owner + if owner != null then + mmodules.add(owner) + else + mmodules.add(mmodule) + end + end + # sort modules + var sorter = new MModuleNameSorter + self.mmodules.add_all(mmodules) + sorter.sort(self.mmodules) + end - var amodules: Array[AModule] + redef fun title do return "Overview" - # 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 - self.opt_nodot = opt_nodot - self.destinationdir = destination + redef fun menu do + super + append("
  • Overview
  • ") + append("
  • Search
  • ") end - redef fun head do - super - add("title").text("Overview | Nit Standard Library") - end - - redef fun header do - open("header") - open("nav").add_class("main") - open("ul") - add("li").add_class("current").text("Overview") - open("li") - add_html("Full Index") - close("li") - open("li").attr("id", "liGitHub") - open("a").add_class("btn").attr("id", "logGitHub") - add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png") - close("a") - open("div").add_class("popover bottom") - add("div").add_class("arrow").text(" ") - open("div").add_class("githubTitle") - add("h3").text("Github Sign In") - close("div") - open("div") - add("label").attr("id", "lbloginGit").text("Username") - add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text") - open("label").attr("id", "logginMessage").text("Hello ") - open("a").attr("id", "githubAccount") - add("strong").attr("id", "nickName").text(" ") - close("a") - close("label") - close("div") - open("div") - add("label").attr("id", "lbpasswordGit").text("Password") - add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password") - open("div").attr("id", "listBranches") - add("label").attr("id", "lbBranches").text("Branch") - add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ") - close("div") - close("div") - open("div") - add("label").attr("id", "lbrepositoryGit").text("Repository") - add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text") - close("div") - open("div") - add("label").attr("id", "lbbranchGit").text("Branch") - add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text") - close("div") - open("div") - add("a").attr("id", "signIn").text("Sign In") - close("div") - close("div") - close("li") - close("ul") - close("nav") - close("header") - end - - redef fun body do - super - open("div").add_class("page") - open("div").add_class("content fullpage") - add("h1").text("Nit Standard Library") - open("article").add_class("overview") - add_html("

    Documentation for the standard library of Nit
    Version jenkins-component=stdlib-19
    Date: TODAY

    ") - close("article") - open("article").add_class("overview") - add("h2").text("Modules") - open("ul") - add_modules - close("ul") - process_generate_dot - close("article") - close("div") - close("div") - add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.") - 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) + redef fun content do + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
    ") + var title = "Overview" + if ctx.opt_custom_title.value != null then + title = ctx.opt_custom_title.value.to_s + end + append("

    {title}

    ") + var text = "" + if ctx.opt_custom_overview_text.value != null then + text = ctx.opt_custom_overview_text.value.to_s + end + append("
    {text}
    ") + append("
    ") + # module list + append("

    Modules

    ") + append("
      ") + for mmodule in mmodules do + if mbuilder.mmodule2nmodule.has_key(mmodule) then + var amodule = mbuilder.mmodule2nmodule[mmodule] + append("
    • ") + mmodule.html_link(self) + append(" {amodule.short_comment}
    • ") end end + append("
    ") + # module graph + process_generate_dot + append("
    ") + append("
    ") end - fun process_generate_dot do + private fun process_generate_dot do + # build poset with public owners + var poset = new POSet[MModule] + for mmodule in mmodules do + poset.add_node(mmodule) + for omodule in mmodules do + if mmodule == omodule then continue + if mmodule.in_importation < omodule then + poset.add_node(omodule) + poset.add_edge(mmodule, omodule) + end + end + end + # build graph 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 poset do + op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n") + for omodule in poset[mmodule].direct_greaters do + op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n") end end op.append("\}\n") generate_dot(op.to_s, "dep", "Modules hierarchy") end - end -class NitdocFullindex +# The search page +class NitdocSearch super NitdocPage - var mmodules: Array[MModule] - - init with(mmodules: Array[MModule]) do - self.mmodules = mmodules - opt_nodot = false - destinationdir = "" + init(ctx: NitdocContext) do + super(ctx) + self.dot_dir = null end - redef fun head do - super - add("title").text("Full Index | Nit Standard Library") - end - - redef fun header do - open("header") - open("nav").add_class("main") - open("ul") - open("li") - add_html("Overview") - close("li") - add("li").add_class("current").text("Full Index") - open("li").attr("id", "liGitHub") - open("a").add_class("btn").attr("id", "logGitHub") - add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png") - close("a") - open("div").add_class("popover bottom") - add("div").add_class("arrow").text(" ") - open("div").add_class("githubTitle") - add("h3").text("Github Sign In") - close("div") - open("div") - add("label").attr("id", "lbloginGit").text("Username") - add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text") - open("label").attr("id", "logginMessage").text("Hello ") - open("a").attr("id", "githubAccount") - add("strong").attr("id", "nickName").text(" ") - close("a") - close("label") - close("div") - open("div") - add("label").attr("id", "lbpasswordGit").text("Password") - add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password") - open("div").attr("id", "listBranches") - add("label").attr("id", "lbBranches").text("Branch") - add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ") - close("div") - close("div") - open("div") - add("label").attr("id", "lbrepositoryGit").text("Repository") - add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text") - close("div") - open("div") - add("label").attr("id", "lbbranchGit").text("Branch") - add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text") - close("div") - open("div") - add("a").attr("id", "signIn").text("Sign In") - close("div") - close("div") - close("li") - close("ul") - close("nav") - close("header") - end - - redef fun body do + redef fun title do return "Search" + + redef fun menu do super - open("div").add_class("page") - open("div").add_class("content fullpage") - add("h1").text("Full Index") - add_content - close("div") - close("div") - add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.") + append("
  • Overview
  • ") + append("
  • Search
  • ") end - fun add_content do + redef fun content do + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
    ") + append("

    {title}

    ") module_column classes_column properties_column + append("
    ") end # Add to content modules column - fun module_column do - var ls = new List[nullable MModule] - open("article").add_class("modules filterable") - add("h2").text("Modules") - open("ul") - for mmodule in mmodules do - if mmodule.public_owner != null and not ls.has(mmodule.public_owner) then - ls.add(mmodule.public_owner) - open("li") - add("a").attr("href", "{mmodule.public_owner.name}.html").text(mmodule.public_owner.name) - close("li") - end + private fun module_column do + var sorted = ctx.mbuilder.model.mmodule_importation_hierarchy.to_a + var sorter = new MModuleNameSorter + sorter.sort(sorted) + append("
    ") + append("

    Modules

    ") + append("
      ") + for mmodule in sorted do + append("
    • ") + mmodule.html_link(self) + append("
    • ") end - close("ul") - close("article") + append("
    ") + append("
    ") end # Add to content classes modules - fun classes_column do - open("article").add_class("classes filterable") - add("h2").text("Classes") - open("ul") - - for mclass in mmodules.first.imported_mclasses do - open("li") - add("a").attr("href", "{mclass.name}.html").text(mclass.name) - close("li") + private fun classes_column do + var sorted = ctx.mbuilder.model.mclasses + var sorter = new MClassNameSorter + sorter.sort(sorted) + append("
    ") + append("

    Classes

    ") + append("
      ") + for mclass in sorted do + if mclass.visibility < ctx.min_visibility then continue + append("
    • ") + mclass.html_link(self) + append("
    • ") end - - close("ul") - close("article") + append("
    ") + append("
    ") end # Insert the properties column of fullindex page - fun properties_column do - open("article").add_class("properties filterable") - add("h2").text("Properties") - open("ul") - - for method in mmodules.first.imported_methods 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") - add_html(" ") - add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})") - close("li") + private fun properties_column do + var sorted = ctx.mbuilder.model.mproperties + var sorter = new MPropertyNameSorter + sorter.sort(sorted) + append("
    ") + append("

    Properties

    ") + append("
      ") + for mproperty in sorted do + if mproperty.visibility < ctx.min_visibility then continue + if mproperty isa MAttribute then continue + append("
    • ") + mproperty.intro.html_link(self) + append(" (") + mproperty.intro.mclassdef.mclass.html_link(self) + append(")
    • ") end - - for method in mmodules.first.redef_methods 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") - add_html(" ") - add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})") - close("li") - end - - close("ul") - close("article") + append("
    ") + append("
    ") end end -class NitdocModules +# A module page +class NitdocModule super NitdocPage - var amodule: AModule - var modulename: String - init with(amodule: AModule) do - self.amodule = amodule - self.modulename = self.amodule.mmodule.name - opt_nodot = false - destinationdir = "" + private var mmodule: MModule + private var mbuilder: ModelBuilder + private var local_mclasses = new HashSet[MClass] + private var intro_mclasses = new HashSet[MClass] + private var redef_mclasses = new HashSet[MClass] + private var inherited_mclasses = new HashSet[MClass] + + init(mmodule: MModule, ctx: NitdocContext, dot_dir: nullable String) do + super(ctx) + self.mmodule = mmodule + self.mbuilder = ctx.mbuilder + self.dot_dir = dot_dir + # get local mclasses + for m in mmodule.in_nesting.greaters do + for mclassdef in m.mclassdefs do + if mclassdef.mclass.visibility < ctx.min_visibility then continue + if mclassdef.is_intro then + intro_mclasses.add(mclassdef.mclass) + else + redef_mclasses.add(mclassdef.mclass) + end + local_mclasses.add(mclassdef.mclass) + end + end + # get inherited mclasses + for m in mmodule.in_importation.greaters do + if m == mmodule then continue + for mclassdef in m.mclassdefs do + if mclassdef.mclass.visibility < ctx.min_visibility then continue + if local_mclasses.has(mclassdef.mclass) then continue + inherited_mclasses.add(mclassdef.mclass) + end + end end - redef fun head do - super - add("title").text("{modulename} module | {amodule.short_comment}") - end - - redef fun header do - open("header") - open("nav").add_class("main") - open("ul") - open("li") - add_html("Overview") - close("li") - add("li").add_class("current").text(modulename) - open("li") - add_html("Full Index") - close("li") - open("li").attr("id", "liGitHub") - open("a").add_class("btn").attr("id", "logGitHub") - add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png") - close("a") - open("div").add_class("popover bottom") - add("div").add_class("arrow").text(" ") - open("div").add_class("githubTitle") - add("h3").text("Github Sign In") - close("div") - open("div") - add("label").attr("id", "lbloginGit").text("Username") - add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text") - open("label").attr("id", "logginMessage").text("Hello ") - open("a").attr("id", "githubAccount") - add("strong").attr("id", "nickName").text(" ") - close("a") - close("label") - close("div") - open("div") - add("label").attr("id", "lbpasswordGit").text("Password") - add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password") - open("div").attr("id", "listBranches") - add("label").attr("id", "lbBranches").text("Branch") - add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ") - close("div") - close("div") - open("div") - add("label").attr("id", "lbrepositoryGit").text("Repository") - add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text") - close("div") - open("div") - add("label").attr("id", "lbbranchGit").text("Branch") - add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text") - close("div") - open("div") - add("a").attr("id", "signIn").text("Sign In") - close("div") - close("div") - close("li") - close("ul") - close("nav") - close("header") - end - - redef fun body do + redef fun title do + if mbuilder.mmodule2nmodule.has_key(mmodule) and not mbuilder.mmodule2nmodule[mmodule].short_comment.is_empty then + var nmodule = mbuilder.mmodule2nmodule[mmodule] + return "{mmodule.html_name} module | {nmodule.short_comment}" + else + return "{mmodule.html_name} module" + end + end + + redef fun menu do super - open("div").add_class("page") - menu - add_content - close("div") - add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.") + append("
  • Overview
  • ") + append("
  • {mmodule.html_name}
  • ") + append("
  • Search
  • ") end - # Insert all tags in content part - fun add_content do - open("div").add_class("content") - add("h1").text(modulename) - add("div").add_class("subtitle").text("module {modulename}") - module_comment - classes - properties - close("div") - end - - # Insert module comment in the content - fun module_comment do - var doc = amodule.comment - open("div").attr("id", "description") - add("pre").add_class("text_label").text(doc) - add("textarea").add_class("edit").attr("rows", "1").attr("cols", "76").attr("id", "fileContent").text(" ") - add("a").attr("id", "cancelBtn").text("Cancel") - add("a").attr("id", "commitBtn").text("Commit") - add("pre").add_class("text_label").attr("id", "preSave").attr("type", "2") - close("div") - end - - fun menu do - var mmodule = amodule.mmodule - open("div").add_class("menu") - open("nav") - add("h3").text("Module Hierarchy").attr("style","cursor: pointer;") - if mmodule.in_importation.direct_greaters.length > 0 then - add_html("

    All dependencies

      ") - for m in mmodule.in_importation.direct_greaters do - if m == mmodule or mmodule == m.public_owner then continue - open("li") - add("a").attr("href", "{m.name}.html").text(m.name) - close("li") - end - add_html("
    ") - end - if mmodule.in_importation.greaters.length > 0 then - add_html("

    All clients

      ") - for m in mmodule.in_importation.greaters do - if m == mmodule then continue - open("li") - add("a").attr("href", "{m.name}.html").text(m.name) - close("li") - end - add_html("
    ") + redef fun content do + append("") + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
    ") + module_doc + append("
    ") + end + + private fun classes_column do + var sorter = new MClassNameSorter + var sorted = new Array[MClass] + sorted.add_all(local_mclasses) + sorter.sort(sorted) + if not sorted.is_empty then + append("") + end + end + + private fun importation_column do + append("") + end + + private fun display_module_list(list: Array[MModule]) do + append("
      ") + var sorter = new MModuleNameSorter + sorter.sort(list) + for m in list do + append("
    • ") + m.html_link(self) + append("
    • ") + end + append("
    ") + end + + private fun module_doc do + # title + append("

    {mmodule.html_name}

    ") + append("
    ") + mmodule.html_signature(self) + append("
    ") + # comment + mmodule.html_comment(self) + # classes + var class_sorter = new MClassNameSorter + # intro + if not intro_mclasses.is_empty then + var sorted = new Array[MClass] + sorted.add_all(intro_mclasses) + class_sorter.sort(sorted) + append("
    ") + append("

    Introduced classes

    ") + for mclass in sorted do mclass.html_full_desc(self) + append("
    ") + end + # redefs + var redefs = new Array[MClass] + for mclass in redef_mclasses do if not intro_mclasses.has(mclass) then redefs.add(mclass) + class_sorter.sort(redefs) + if not redefs.is_empty then + append("
    ") + append("

    Refined classes

    ") + for mclass in redefs do mclass.html_full_desc(self) + append("
    ") + end + # inherited properties + var inherited = new Array[MClass] + inherited.add_all(inherited_mclasses) + if inherited_mclasses.length > 0 then + var modules2classes = new ArrayMap[MModule, Array[MClass]] + for mclass in inherited_mclasses do + if not modules2classes.has_key(mclass.intro_mmodule) then modules2classes[mclass.intro_mmodule] = new Array[MClass] + modules2classes[mclass.intro_mmodule].add(mclass) end - close("ul") - - close("nav") - end - close("div") - end - - fun classes do - open("div").add_class("module") - open("article").add_class("classes filterable") - add("h2").text("Classes") - open("ul") - for c, state in amodule.mmodule.mclasses do - var name = c.name - if state == c_is_intro or state == c_is_imported then - open("li").add_class("intro") - add("span").attr("title", "introduced in this module").text("I ") - else - open("li").add_class("redef") - add("span").attr("title", "refined in this module").text("R ") + append("
    ") + append("

    Inherited Classes

    ") + var mmodules = new Array[MModule] + mmodules.add_all(modules2classes.keys) + var msorter = new MModuleNameSorter + msorter.sort(mmodules) + for m in mmodules do + var mclasses = modules2classes[m] + class_sorter.sort(mclasses) + append("

    Defined in ") + m.html_link(self) + append(": ") + for i in [0..mclasses.length[ do + var mclass = mclasses[i] + mclass.html_link(self) + if i <= mclasses.length - 1 then append(", ") + end + append("

    ") end - add("a").attr("href", "{name}.html").text(name) - close("li") + append("
    ") end - close("ul") - close("article") - close("div") end - fun properties do - open("article").add_class("properties filterable") - add_html("

    Properties

    ") - open("ul") - for method in amodule.mmodule.imported_methods 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") - add_html(" ") - add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})") - close("li") + private fun process_generate_dot do + # build poset with public owners + var poset = new POSet[MModule] + for mmodule in self.mmodule.in_importation.poset do + if mmodule.name == "
    " then continue + if mmodule.public_owner != null then continue + if not mmodule.in_importation < self.mmodule and not self.mmodule.in_importation < mmodule and mmodule != self.mmodule then continue + poset.add_node(mmodule) + for omodule in mmodule.in_importation.poset do + if mmodule == omodule then continue + if omodule.name == "
    " then continue + if omodule.public_owner != null then continue + if mmodule.in_importation < omodule then + poset.add_node(omodule) + poset.add_edge(mmodule, omodule) + end + end end - - for method in amodule.mmodule.redef_methods 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") - add_html(" ") - add("a").attr("href", "{method.local_class.name}.html").attr("title", "").text("{method.name} ({method.local_class.name})") - close("li") + # build graph + var op = new Buffer + 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") + for mmodule in poset do + if mmodule == self.mmodule then + op.append("\"{mmodule.name}\"[shape=box,margin=0.03];\n") + else + op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n") + end + for omodule in poset[mmodule].direct_greaters do + op.append("\"{mmodule.name}\"->\"{omodule.name}\";\n") + end end - - close("ul") - close("article") + op.append("\}\n") + generate_dot(op.to_s, name, "Dependency graph for module {mmodule.name}") end - end -# Nit Standard Library -class NitdocMClasses +# A class page +class NitdocClass super NitdocPage - var mclass: MClass - var aclassdef: AClassdef - var stdclassdef: nullable AStdClassdef - var public_owner: nullable MModule + private var mclass: MClass + private var vtypes = new HashSet[MVirtualTypeDef] + private var consts = new HashSet[MMethodDef] + private var meths = new HashSet[MMethodDef] + private var inherited = new HashSet[MPropDef] - init with(mclass: MClass, aclassdef: AClassdef) do + init(mclass: MClass, ctx: NitdocContext, dot_dir: nullable String, source: nullable String) do + super(ctx) self.mclass = mclass - self.aclassdef = aclassdef - if aclassdef isa AStdClassdef then self.stdclassdef = aclassdef - self.public_owner = mclass.intro_mmodule.public_owner - opt_nodot = false - destinationdir = "" + self.dot_dir = dot_dir + self.source = source + # load properties + var locals = new HashSet[MProperty] + for mclassdef in mclass.mclassdefs do + for mpropdef in mclassdef.mpropdefs do + if mpropdef.mproperty.visibility < ctx.min_visibility then continue + if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef) + if mpropdef isa MMethodDef then + if mpropdef.mproperty.is_init then + consts.add(mpropdef) + else + meths.add(mpropdef) + end + end + locals.add(mpropdef.mproperty) + end + end + # get inherited properties + for pclass in mclass.in_hierarchy(ctx.mainmodule).greaters do + if pclass == mclass then continue + for pclassdef in pclass.mclassdefs do + for mprop in pclassdef.intro_mproperties do + var mpropdef = mprop.intro + if mprop.visibility < ctx.min_visibility then continue + if locals.has(mprop) then continue + if mpropdef isa MVirtualTypeDef then vtypes.add(mpropdef) + if mpropdef isa MMethodDef then + if mpropdef.mproperty.is_init then + consts.add(mpropdef) + else + meths.add(mpropdef) + end + end + inherited.add(mpropdef) + end + end + end end - redef fun head do - super - add("title").text("{self.mclass.name} class | Nit Standard Library") + redef fun title do + var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro] + if nclass isa AStdClassdef then + return "{mclass.html_name} class | {nclass.short_comment}" + else + return "{mclass.html_name} class" + end end - redef fun header do - open("header") - open("nav").add_class("main") - open("ul") - open("li") - add_html("Overview") - close("li") - open("li") + redef fun menu do + super + append("
  • Overview
  • ") + var public_owner = mclass.public_owner if public_owner is null then - add_html("{mclass.intro_mmodule.name}") + append("
  • ") + mclass.intro_mmodule.html_link(self) + append("
  • ") else - add_html("{public_owner.name}") - end - close("li") - add("li").add_class("current").text(mclass.name) - open("li") - add_html("Full Index") - close("li") - open("li").attr("id", "liGitHub") - open("a").add_class("btn").attr("id", "logGitHub") - add("img").attr("id", "imgGitHub").attr("src", "resources/icons/github-icon.png") - close("a") - open("div").add_class("popover bottom") - add("div").add_class("arrow").text(" ") - open("div").add_class("githubTitle") - add("h3").text("Github Sign In") - close("div") - open("div") - add("label").attr("id", "lbloginGit").text("Username") - add("input").attr("id", "loginGit").attr("name", "login").attr("type", "text") - open("label").attr("id", "logginMessage").text("Hello ") - open("a").attr("id", "githubAccount") - add("strong").attr("id", "nickName").text(" ") - close("a") - close("label") - close("div") - open("div") - add("label").attr("id", "lbpasswordGit").text("Password") - add("input").attr("id", "passwordGit").attr("name", "password").attr("type", "password") - open("div").attr("id", "listBranches") - add("label").attr("id", "lbBranches").text("Branch") - add("select").add_class("dropdown").attr("id", "dropBranches").attr("name", "dropBranches").attr("tabindex", "1").text(" ") - close("div") - close("div") - open("div") - add("label").attr("id", "lbrepositoryGit").text("Repository") - add("input").attr("id", "repositoryGit").attr("name", "repository").attr("type", "text") - close("div") - open("div") - add("label").attr("id", "lbbranchGit").text("Branch") - add("input").attr("id", "branchGit").attr("name", "branch").attr("type", "text") - close("div") - open("div") - add("a").attr("id", "signIn").text("Sign In") - close("div") - close("div") - close("li") - close("ul") - close("nav") - close("header") - end - - redef fun body do - super - open("div").add_class("page") - add_content - close("div") - add("footer").text("Nit standard library. Version jenkins-component=stdlib-19.") + append("
  • ") + public_owner.html_link(self) + append("
  • ") + end + append("
  • {mclass.html_name}
  • ") + append("
  • Search
  • ") end - # Insert all tags in content part - fun add_content do - open("div").add_class("menu") + redef fun content do + append("") + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
    ") + class_doc + append("
    ") + end + + private fun properties_column do + var sorter = new MPropDefNameSorter + append("") + end + + private fun inheritance_column do + var sorted = new Array[MClass] + var sorterp = new MClassNameSorter + append("") + end + + private fun class_doc do + # title + append("

    {mclass.html_name}{mclass.html_short_signature}

    ") + append("
    ") + if mclass.visibility < public_visibility then append("{mclass.visibility.to_s} ") + append("{mclass.kind.to_s} ") + mclass.html_namespace(self) + append("{mclass.html_short_signature}
    ") + # comment + mclass.html_comment(self) + process_generate_dot + # concerns + var concern2meths = new ArrayMap[MModule, Array[MMethodDef]] + var sorted_meths = new Array[MMethodDef] + var sorted = new Array[MModule] + sorted_meths.add_all(meths) + ctx.mainmodule.linearize_mpropdefs(sorted_meths) + for meth in meths do + if inherited.has(meth) then continue + var mmodule = meth.mclassdef.mmodule + if not concern2meths.has_key(mmodule) then + sorted.add(mmodule) + concern2meths[mmodule] = new Array[MMethodDef] + end + concern2meths[mmodule].add(meth) + end + var sections = new ArrayMap[MModule, Array[MModule]] + for mmodule in concern2meths.keys do + var owner = mmodule.public_owner + if owner == null then owner = mmodule + if not sections.has_key(owner) then sections[owner] = new Array[MModule] + if owner != mmodule then sections[owner].add(mmodule) + end + append("
    ") + append("

    Concerns

    ") + append("
      ") + for owner, mmodules in sections do + var nowner = ctx.mbuilder.mmodule2nmodule[owner] + append("
    • ") + if nowner.short_comment.is_empty then + append("{owner.html_name}") + else + append("{owner.html_name}: {nowner.short_comment}") + end + if not mmodules.is_empty then + append("
        ") + for mmodule in mmodules do + var nmodule = ctx.mbuilder.mmodule2nmodule[mmodule] + if nmodule.short_comment.is_empty then + append("
      • {mmodule.html_name}
      • ") + else + append("
      • {mmodule.html_name}: {nmodule.short_comment}
      • ") + end + end + append("
      ") + end + append("
    • ") + end + append("
    ") + append("
    ") + # properties + var prop_sorter = new MPropDefNameSorter var lmmodule = new List[MModule] - # Insert the subtitle part - add("h1").text(mclass.name) - open("div").add_class("subtitle") - if mclass.visibility is none_visibility then subtitle += "private " - subtitle += "{mclass.kind} {mclass.public_owner.name}::{mclass.name}" - add_html(subtitle) - close("div") - add_html("
    ") - # We add the class description - open("section").add_class("description") - if not stdclassdef is null and not stdclassdef.comment.is_empty 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, childs in mclass.concerns do
    -			open("li")
    -			add_html("{owner.name}: {owner.amodule.short_comment}")
    -			if not childs is null then
    -				open("ul")
    -				for child in childs.as(not null) do add_html("
  • {child.name}: {child.amodule.short_comment}
  • ") - close("ul") + var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro] + # virtual and formal types + var local_vtypes = new Array[MVirtualTypeDef] + for vt in vtypes do if not inherited.has(vt) then local_vtypes.add(vt) + if local_vtypes.length > 0 or mclass.arity > 0 then + append("
    ") + append("

    Formal and Virtual Types

    ") + # formal types + if mclass.arity > 0 and nclass isa AStdClassdef then + for ft, bound in mclass.parameter_types do + append("
    ") + append("

    {ft}: ") + bound.html_link(self) + append("

    ") + append("
    formal generic type
    ") + append("
    ") + end end - close("li") - end - close("ul") - close("section") - # Insert virtual types if there is almost one - if mclass.virtual_types.length > 0 or (stdclassdef != null and stdclassdef.n_formaldefs.length > 0) then - open("section").add_class("types") - add("h2").text("Formal and Virtual Types") - if mclass.virtual_types.length > 0 then for prop in mclass.virtual_types do description(prop) - if stdclassdef.n_formaldefs.length > 0 then - for prop in stdclassdef.n_formaldefs do - open("article").attr("id", "FT_Object_{prop.collect_text}") - open("h3").add_class("signature").text("{prop.collect_text}: nullable ") - add_html("Object") - close("h3") - add_html("
    formal generic type
    ") - close("article") + # virtual types + prop_sorter.sort(local_vtypes) + for prop in local_vtypes do prop.html_full_desc(self, self.mclass) + append("
    ") + end + # constructors + var local_consts = new Array[MMethodDef] + for const in consts do if not inherited.has(const) then local_consts.add(const) + prop_sorter.sort(local_consts) + if local_consts.length > 0 then + append("
    ") + append("

    Constructors

    ") + for prop in local_consts do prop.html_full_desc(self, self.mclass) + append("
    ") + end + # methods + if not concern2meths.is_empty then + append("
    ") + append("

    Methods

    ") + for owner, mmodules in sections do + append("") + if owner != mclass.intro_mmodule and owner != mclass.public_owner then + var nowner = ctx.mbuilder.mmodule2nmodule[owner] + append("

    Methods refined in ") + owner.html_link(self) + append("

    ") + append("

    ") + owner.html_link(self) + if not nowner.short_comment.is_empty then + append(": {nowner.short_comment}") + end + append("

    ") + end + if concern2meths.has_key(owner) then + var mmethods = concern2meths[owner] + prop_sorter.sort(mmethods) + for prop in mmethods do prop.html_full_desc(self, self.mclass) + end + for mmodule in mmodules do + append("") + var nmodule = ctx.mbuilder.mmodule2nmodule[mmodule] + if mmodule != mclass.intro_mmodule and mmodule != mclass.public_owner then + append("

    ") + mmodule.html_link(self) + if not nmodule.short_comment.is_empty then + append(": {nmodule.short_comment}") + end + append("

    ") + end + var mmethods = concern2meths[mmodule] + prop_sorter.sort(mmethods) + for prop in mmethods do prop.html_full_desc(self, self.mclass) end end - close("section") + append("
    ") end - # Insert constructors if there is almost one - if mclass.constructors.length > 0 then - open("section").add_class("constructors") - add("h2").add_class("section-header").text("Constructors") - for prop in mclass.constructors do description(prop) - close("section") + # inherited properties + if inherited.length > 0 then + var sorted_inherited = new Array[MPropDef] + sorted_inherited.add_all(inherited) + ctx.mainmodule.linearize_mpropdefs(sorted_inherited) + var classes = new ArrayMap[MClass, Array[MPropDef]] + for mmethod in sorted_inherited.reversed do + var mclass = mmethod.mclassdef.mclass + if not classes.has_key(mclass) then classes[mclass] = new Array[MPropDef] + classes[mclass].add(mmethod) + end + append("
    ") + append("

    Inherited Properties

    ") + for c, mmethods in classes do + prop_sorter.sort(mmethods) + append("

    Defined in ") + c.html_link(self) + append(": ") + for i in [0..mmethods.length[ do + var mmethod = mmethods[i] + mmethod.html_link(self) + if i <= mmethods.length - 1 then append(", ") + end + append("

    ") + end + append("
    ") end 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("

    {sign}

    ") - add_html("
    {if prop.is_redef then "redef" else ""} fun {prop.intro_mclassdef.namespace(mclass)}::{prop.name}
    ") - - open("div").add_class("description") - if prop.apropdef is null or prop.apropdef.comment == "" then - add_html("New Comment") - else - add_html("
    {prop.apropdef.comment}
    ") + private fun process_generate_dot do + var pe = ctx.class_hierarchy[mclass] + var cla = new HashSet[MClass] + var sm = new HashSet[MClass] + var sm2 = new HashSet[MClass] + sm.add(mclass) + while cla.length + sm.length < 10 and sm.length > 0 do + cla.add_all(sm) + sm2.clear + for x in sm do + sm2.add_all(pe.poset[x].direct_smallers) + end + var t = sm + sm = sm2 + sm2 = t 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} (show code).")
    +		cla.add_all(pe.greaters)
     
    -		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}.")
    +		var op = new Buffer
    +		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 cla do
    +			if c == mclass then
    +				op.append("\"{c.name}\"[shape=box,margin=0.03];\n")
    +			else
    +				op.append("\"{c.name}\"[URL=\"{c.url}\"];\n")
    +			end
    +			for c2 in pe.poset[c].direct_greaters do
    +				if not cla.has(c2) then continue
    +				op.append("\"{c.name}\"->\"{c2.name}\";\n")
    +			end
    +			if not pe.poset[c].direct_smallers.is_empty then
    +				var others = true
    +				for c2 in pe.poset[c].direct_smallers do
    +					if cla.has(c2) then others = false
    +				end
    +				if others then
    +					op.append("\"{c.name}...\"[label=\"\"];\n")
    +					op.append("\"{c.name}...\"->\"{c.name}\"[style=dotted];\n")
    +				end
    +			end
     		end
    -		close("p")
    -		close("div")
    -
    -		close("article")
    +		op.append("\}\n")
    +		generate_dot(op.to_s, name, "Dependency graph for class {mclass.name}")
     	end
    +end
     
    -end	
    -
    -class NitdocPage
    -	super HTMLPage
    -	
    -	var opt_nodot: Bool
    -	var destinationdir : String
    +#
    +# Model redefs
    +#
     
    -	redef fun head do
    -		add("meta").attr("charset", "utf-8")
    -		add("script").attr("type", "text/javascript").attr("src", "scripts/jquery-1.7.1.min.js")
    -		add("script").attr("type", "text/javascript").attr("src", "quicksearch-list.js")
    -		add("script").attr("type", "text/javascript").attr("src", "scripts/js-facilities.js")
    -		add("link").attr("rel", "stylesheet").attr("href", "styles/main.css").attr("type", "text/css").attr("media", "screen")
    +redef class MModule
    +	# Return the HTML escaped name of the module
    +	private fun html_name: String do return name.html_escape
    +
    +	# URL to nitdoc page
    +	#	module_owner_name.html
    +	private fun url: String do
    +		if url_cache == null then
    +			var res = new Buffer
    +			res.append("module_")
    +			var mowner = public_owner
    +			if mowner != null then
    +				res.append("{public_owner.name}_")
    +			end
    +			res.append("{self.name}.html")
    +			url_cache = res.to_s
    +		end
    +		return url_cache.as(not null)
    +	end
    +	private var url_cache: nullable String
    +
    +	# html anchor id for the module in a nitdoc page
    +	#	MOD_owner_name
    +	private fun anchor: String do
    +		if anchor_cache == null then
    +			var res = new Buffer
    +			res.append("MOD_")
    +			var mowner = public_owner
    +			if mowner != null then
    +				res.append("{public_owner.name}_")
    +			end
    +			res.append(self.name)
    +			anchor_cache = res.to_s
    +		end
    +		return anchor_cache.as(not null)
     	end
    +	private var anchor_cache: nullable String
     
    -	redef fun body do header
    -	fun header do end
    -
    -	# Generate a clickable graphviz image using a dot content
    -	fun generate_dot(dot: String, name: String, alt: String) do
    -		if opt_nodot then return
    -		var file = new OFStream.open("{self.destinationdir}/{name}.dot")
    -		file.write(dot)
    -		file.close
    -		sys.system("\{ test -f {self.destinationdir}/{name}.png && test -f {self.destinationdir}/{name}.s.dot && diff {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot >/dev/null 2>&1 ; \} || \{ cp {self.destinationdir}/{name}.dot {self.destinationdir}/{name}.s.dot && dot -Tpng -o{self.destinationdir}/{name}.png -Tcmapx -o{self.destinationdir}/{name}.map {self.destinationdir}/{name}.s.dot ; \}")
    -		open("article").add_class("graph")
    -		add("img").attr("src", "{name}.png").attr("usemap", "#{name}").attr("style", "margin:auto").attr("alt", "{alt}")
    -		close("article")
    -		var fmap = new IFStream.open("{self.destinationdir}/{name}.map")
    -		add_html(fmap.read_all)
    -		fmap.close
    +	# Return a link (html a tag) to the nitdoc module page
    +	#	html_name
    +	private fun html_link(page: NitdocPage) do
    +		if html_link_cache == null then
    +			var res = new Buffer
    +			if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
    +				res.append("{html_name}")
    +			else
    +				res.append("{html_name}")
    +			end
    +			html_link_cache = res.to_s
    +		end
    +		page.append(html_link_cache.as(not null))
    +	end
    +	private var html_link_cache: nullable String
    +
    +	# Return the module signature decorated with html
    +	#	module html_full_namespace
    +	private fun html_signature(page: NitdocPage) do
    +		page.append("module ")
    +		html_full_namespace(page)
    +		page.append("")
    +	end
    +
    +	# Return the module full namespace decorated with html
    +	#	public_owner.html_namespace::html_link
    +	private fun html_full_namespace(page: NitdocPage) do
    +		page.append("")
    +		var mowner = public_owner
    +		if mowner != null then
    +			public_owner.html_namespace(page)
    +			page.append("::")
    +		end
    +		html_link(page)
    +		page.append("")
     	end
     
    -end
    +	# Return the module full namespace decorated with html
    +	#	public_owner.html_namespace
    +	private fun html_namespace(page: NitdocPage) do
    +		page.append("")
    +		var mowner = public_owner
    +		if mowner != null then
    +			public_owner.html_namespace(page)
    +		else
    +			html_link(page)
    +		end
    +		page.append("")
    +	end
    +
    +	# Return the full comment of the module decorated with html
    +	private fun html_comment(page: NitdocPage) do
    +		page.append("
    ") + if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then + var nmodule = page.ctx.mbuilder.mmodule2nmodule[self] + page.append("") + if nmodule.full_comment == "" then + page.append("

    ") + page.append("no comment for ") + else + page.append("

    {nmodule.full_markdown}
    ") + page.append("

    ") + end + page.append("definition in ") + self.html_full_namespace(page) + page.append(" {page.show_source(nmodule.location)}

    ") + end + page.append("
    ") + end -redef class AModule - private fun comment: String do - var ret = "" - if n_moduledecl is null or n_moduledecl.n_doc is null then ret - if n_moduledecl.n_doc is null then return "" - for t in n_moduledecl.n_doc.n_comment do - ret += "{t.text.replace("# ", "")}" + private fun has_mclassdef_for(mclass: MClass): Bool do + for mmodule in self.in_nesting.greaters do + for mclassdef in mmodule.mclassdefs do + if mclassdef.mclass == mclass then return true + end end - return ret + return false end - private fun short_comment: String do - var ret = "" - if n_moduledecl != null and n_moduledecl.n_doc != null then - var txt = n_moduledecl.n_doc.n_comment.first.text - txt = txt.replace("# ", "") - txt = txt.replace("\n", "") - ret += txt + private fun has_mclassdef(mclassdef: MClassDef): Bool do + for mmodule in self.in_nesting.greaters do + for oclassdef in mmodule.mclassdefs do + if mclassdef == oclassdef then return true + end end - return ret + return false end end -redef class MModule +redef class MClass + # Return the HTML escaped name of the module + private fun html_name: String do return name.html_escape - var amodule: nullable AModule + # URL to nitdoc page + # class_owner_name.html + private fun url: String do + return "class_{public_owner}_{name}.html" + end - # Get the list of all methods in a module - fun imported_methods: Set[MMethod] do - var methods = new HashSet[MMethod] - for mclass in imported_mclasses do - for method in mclass.intro_methods do - methods.add(method) + # html anchor id for the class in a nitdoc page + # MOD_owner_name + private fun anchor: String do + if anchor_cache == null then + anchor_cache = "CLASS_{public_owner.name}_{name}" + end + return anchor_cache.as(not null) + end + private var anchor_cache: nullable String + + # Return a link (with signature) to the nitdoc class page + # html_name(signature) + private fun html_link(page: NitdocPage) do + if html_link_cache == null then + var res = new Buffer + res.append("{html_name}{html_short_signature}") + html_link_cache = res.to_s + end + page.append(html_link_cache.as(not null)) + end + private var html_link_cache: nullable String + + # Return a short link (without signature) to the nitdoc class page + # html_name + private fun html_short_link(page: NitdocPage) do + if html_short_link_cache == null then + var res = new Buffer + res.append("{html_name}") + html_short_link_cache = res.to_s + end + page.append(html_short_link_cache.as(not null)) + end + private var html_short_link_cache: nullable String + + # Return a link (with signature) to the class anchor + # html_name + private fun html_link_anchor(page: NitdocPage) do + if html_link_anchor_cache == null then + var res = new Buffer + res.append("{html_name}{html_short_signature}") + html_link_anchor_cache = res.to_s + end + page.append(html_link_anchor_cache.as(not null)) + end + private var html_link_anchor_cache: nullable String + + # Return the generic signature of the class with bounds + # [E: MType, F: MType] + private fun html_signature(page: NitdocPage) do + if arity > 0 then + page.append("[") + for i in [0..intro.parameter_names.length[ do + page.append("{intro.parameter_names[i]}: ") + intro.bound_mtype.arguments[i].html_link(page) + if i < intro.parameter_names.length - 1 then page.append(", ") + end + page.append("]") + end + end + + # Return the generic signature of the class without bounds + # [E, F] + private fun html_short_signature: String do + if arity > 0 then + return "[{intro.parameter_names.join(", ")}]" + else + return "" end - return methods end - # Get the list aof all refined methods in a module - fun redef_methods: Set[MMethod] do - var methods = new HashSet[MMethod] - for mclass in redef_mclasses do - for method in mclass.intro_methods do - methods.add(method) + # Return the class namespace decorated with html + # intro_module::html_short_link + private fun html_namespace(page: NitdocPage) do + intro_mmodule.html_namespace(page) + page.append("::") + html_short_link(page) + page.append("") + end + + # Return a list item for the mclass + #
  • html_link
  • + private fun html_sidebar_item(page: NitdocModule) do + if page.mmodule.in_nesting.greaters.has(intro.mmodule) then + page.append("
  • ") + page.append("I") + html_link_anchor(page) + else if page.mmodule.has_mclassdef_for(self) then + page.append("
  • ") + page.append("R") + html_link_anchor(page) + else + page.append("
  • ") + page.append("H") + html_link(page) + end + page.append("
  • ") + end + + private fun html_full_desc(page: NitdocModule) do + var classes = new Array[String] + classes.add(kind.to_s) + if not page.mmodule.in_nesting.greaters.has(intro.mmodule) then classes.add("redef") + classes.add(visibility.to_s) + page.append("
    ") + page.append("

    ") + page.append("") + html_short_link(page) + html_signature(page) + page.append("

    ") + html_info(page) + html_comment(page) + html_redefs(page) + page.append("
    ") + end + + private fun html_info(page: NitdocModule) do + page.append("
    ") + if visibility < public_visibility then page.append("{visibility.to_s} ") + if not page.mmodule.in_nesting.greaters.has(intro.mmodule) then page.append("redef ") + page.append("{kind} ") + html_namespace(page) + page.append("{html_short_signature}
    ") + end + + private fun html_comment(page: NitdocPage) do + page.append("
    ") + if page isa NitdocModule then + page.mmodule.linearize_mclassdefs(mclassdefs) + # comments for each mclassdef contained in current mmodule + for mclassdef in mclassdefs do + if not mclassdef.is_intro and not page.mmodule.mclassdefs.has(mclassdef) then continue + if page.ctx.mbuilder.mclassdef2nclassdef.has_key(mclassdef) then + var nclass = page.ctx.mbuilder.mclassdef2nclassdef[mclassdef] + if nclass isa AStdClassdef then + page.append("") + if nclass.full_comment == "" then + page.append("

    ") + page.append("no comment for ") + else + page.append("

    {nclass.full_markdown}
    ") + page.append("

    ") + end + if mclassdef.is_intro then + page.append("introduction in ") + else + page.append("refinement in ") + end + mclassdef.mmodule.html_full_namespace(page) + page.append(" {page.show_source(nclass.location)}

    ") + end + end + end + else + # comments for intro + if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then + var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro] + if nclass isa AStdClassdef then + page.append("") + if nclass.full_comment == "" then + page.append("

    ") + page.append("no comment for ") + else + page.append("

    {nclass.full_markdown}
    ") + page.append("

    ") + end + page.append("introduction in ") + intro.mmodule.html_full_namespace(page) + page.append(" {page.show_source(nclass.location)}

    ") + end end end - return methods + page.append("
    ") + end + + private fun html_redefs(page: NitdocModule) do + page.mmodule.linearize_mclassdefs(mclassdefs) + page.append("
    ") + # comments for each mclassdef contained in current mmodule + for mclassdef in mclassdefs do + if not page.mmodule.mclassdefs.has(mclassdef) then continue + if mclassdef.is_intro then continue + for mpropdef in mclassdef.mpropdefs do + if mpropdef isa MAttributeDef then continue + mpropdef.html_full_desc(page, self) + end + end + page.append("
    ") end end redef class MProperty + # Escape name for html output + private fun html_name: String do return name.html_escape + + # Return the property namespace decorated with html + # intro_module::intro_class::html_link + private fun html_namespace(page: NitdocPage) do + intro_mclassdef.mclass.html_namespace(page) + page.append(intro_mclassdef.mclass.html_short_signature) + page.append("::") + intro.html_link(page) + page.append("") + end +end - var is_redef: Bool - var apropdef: nullable APropdef +redef class MType + # Link to the type definition in the nitdoc page + private fun html_link(page: NitdocPage) is abstract +end - redef init(intro_mclassdef: MClassDef, name: String, visibility: MVisibility) - do - super - is_redef = false - end +redef class MClassType + redef fun html_link(page) do mclass.html_link(page) +end - fun local_class: MClass do - var classdef = self.intro_mclassdef - return classdef.mclass +redef class MNullableType + redef fun html_link(page) do + page.append("nullable ") + mtype.html_link(page) end +end - fun class_text: String do - return local_class.name +redef class MGenericType + redef fun html_link(page) do + page.append("{mclass.html_name}[") + for i in [0..arguments.length[ do + arguments[i].html_link(page) + if i < arguments.length - 1 then page.append(", ") + end + page.append("]") end +end - fun link_anchor: String do - return "{class_text}.html#{anchor}" +redef class MParameterType + redef fun html_link(page) do + var name = mclass.intro.parameter_names[rank] + page.append("{name}") end +end - fun anchor: String do - return "PROP_{c_name}" - end +redef class MVirtualType + redef fun html_link(page) do mproperty.intro.html_link(page) +end +redef class MClassDef + # Return the classdef namespace decorated with html + private fun html_namespace(page: NitdocPage) do + mmodule.html_full_namespace(page) + page.append("::") + mclass.html_link(page) + page.append("") + end end -redef class MClass +redef class MPropDef + # Return the full qualified name of the mpropdef + # module::classdef::name + private fun full_name: String do + return "{mclassdef.mclass.public_owner.name}::{mclassdef.mclass.name}::{mproperty.name}" + end - # Associate all MMethods to each MModule concerns - fun all_methods: HashMap[MModule, Set[MMethod]] do - var hm = new HashMap[MModule, Set[MMethod]] - for mmodule, childs in concerns do - if not hm.has_key(mmodule) then hm[mmodule] = new HashSet[MMethod] - for prop in intro_methods do - if mmodule == prop.intro_mclassdef.mmodule then - prop.is_redef = false - hm[mmodule].add(prop) - end + # URL into the nitdoc page + # class_owner_name.html#anchor + private fun url: String do + if url_cache == null then + url_cache = "{mclassdef.mclass.url}#{anchor}" + end + return url_cache.as(not null) + end + private var url_cache: nullable String + + # html anchor id for the property in a nitdoc class page + # PROP_mclass_propertyname + private fun anchor: String do + if anchor_cache == null then + anchor_cache = "PROP_{mclassdef.mclass.public_owner.name}_{mproperty.name.replace(" ", "_")}" + end + return anchor_cache.as(not null) + end + private var anchor_cache: nullable String + + # Return a link to property into the nitdoc class page + # html_name + private fun html_link(page: NitdocPage) do + if html_link_cache == null then + var res = new Buffer + if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then + var nprop = page.ctx.mbuilder.mpropdef2npropdef[self] + res.append("{mproperty.html_name}") + else + res.append("{mproperty.html_name}") end - for prop in redef_methods do - if mmodule == prop.intro_mclassdef.mmodule then - prop.is_redef = true - hm[mmodule].add(prop) + html_link_cache = res.to_s + end + page.append(html_link_cache.as(not null)) + end + private var html_link_cache: nullable String + + # Return a list item for the mpropdef + #
  • html_link
  • + private fun html_sidebar_item(page: NitdocClass) do + if is_intro and mclassdef.mclass == page.mclass then + page.append("
  • ") + page.append("I") + else if is_intro and mclassdef.mclass != page.mclass then + page.append("
  • ") + page.append("H") + else + page.append("
  • ") + page.append("R") + end + html_link(page) + page.append("
  • ") + end + + private fun html_full_desc(page: NitdocPage, ctx: MClass) is abstract + private fun html_info(page: NitdocPage, ctx: MClass) is abstract + + private fun html_comment(page: NitdocPage) do + page.append("
    ") + if not is_intro then + if page.ctx.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then + var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro] + page.append("") + if intro_nprop.full_comment.is_empty then + page.append("

    ") + page.append("no comment for ") + else + page.append("

    {intro_nprop.full_markdown}
    ") + page.append("

    ") end + page.append("introduction in ") + mproperty.intro.mclassdef.html_namespace(page) + page.append(" {page.show_source(intro_nprop.location)}

    ") end - - if childs != null then - for child in childs do - if not hm.has_key(child) then hm[child] = new HashSet[MMethod] - for prop in intro_methods do - if child == prop.intro_mclassdef.mmodule then - prop.is_redef = false - hm[child].add(prop) - end - end - for prop in redef_methods do - if child == prop.intro_mclassdef.mmodule then - prop.is_redef = true - hm[child].add(prop) - end - end - end + end + if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then + var nprop = page.ctx.mbuilder.mpropdef2npropdef[self] + page.append("") + if nprop.full_comment == "" then + page.append("

    ") + page.append("no comment for ") + else + page.append("

    {nprop.full_markdown}
    ") + page.append("

    ") end + if is_intro then + page.append("introduction in ") + else + page.append("redefinition in ") + end + mclassdef.html_namespace(page) + page.append(" {page.show_source(nprop.location)}

    ") end - return hm + page.append("
    ") end +end - fun public_owner: MModule do - var owner = intro_mmodule - if owner.public_owner is null then - return owner +redef class MMethodDef + redef fun html_full_desc(page, ctx) do + var classes = new Array[String] + var is_redef = mproperty.intro_mclassdef.mclass != ctx + if mproperty.is_init then + classes.add("init") else - return owner.public_owner.as(not null) + classes.add("fun") 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] + if is_redef then classes.add("redef") + classes.add(mproperty.visibility.to_s) + page.append("
    ") + if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then + page.append("

    ") + page.append("{mproperty.html_name}") + msignature.html_signature(page) + page.append("

    ") + else + page.append("

    ") + page.append("init") + msignature.html_signature(page) + page.append("

    ") end + html_info(page, ctx) + html_comment(page) + page.append("
    ") 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) + redef fun html_info(page, ctx) do + page.append("
    ") + if mproperty.visibility < public_visibility then page.append("{mproperty.visibility.to_s} ") + if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ") + if mproperty.is_init then + page.append("init ") + else + page.append("fun ") end - return hm + mproperty.html_namespace(page) + page.append("
    ") end +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 +redef class MVirtualTypeDef + redef fun html_full_desc(page, ctx) do + var is_redef = mproperty.intro_mclassdef.mclass != ctx + var classes = new Array[String] + classes.add("type") + if is_redef then classes.add("redef") + classes.add(mproperty.visibility.to_s) + page.append("
    ") + page.append("

    {mproperty.html_name}: ") + bound.html_link(page) + page.append("

    ") + html_info(page, ctx) + html_comment(page) + page.append("
    ") + end + + redef fun html_info(page, ctx) do + page.append("
    ") + if mproperty.intro_mclassdef.mclass != ctx then page.append("redef ") + page.append("type ") + mproperty.html_namespace(page) + page.append("
    ") end +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) +redef class MSignature + private fun html_signature(page: NitdocPage) do + if not mparameters.is_empty then + page.append("(") + for i in [0..mparameters.length[ do + mparameters[i].html_link(page) + if i < mparameters.length - 1 then page.append(", ") end + page.append(")") 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 + if return_mtype != null then + page.append(": ") + return_mtype.html_link(page) 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) + private fun untyped_signature(page: NitdocPage): String do + var res = new Buffer + if not mparameters.is_empty then + res.append("(") + for i in [0..mparameters.length[ do + res.append(mparameters[i].name) + if i < mparameters.length - 1 then res.append(", ") end + res.append(")") end + return res.to_s 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 +redef class MParameter + private fun html_link(page: NitdocPage) do + page.append("{name}: ") + mtype.html_link(page) + if is_vararg then page.append("...") end +end +# +# Nodes redefs +# + +redef class ADoc 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 + return n_comment.first.text.substring_from(2).replace("\n", "").html_escape 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(", ")})" + private fun full_comment: String do + var res = new Buffer + for t in n_comment do + var text = t.text + text = text.substring_from(1) + if text.first == ' ' then text = text.substring_from(1) + res.append(text.html_escape) end - if n_type != null and n_type.to_s != "" then ret += " {n_type.to_s}" - return ret + return res.to_s 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}..." +redef class AModule + private fun short_comment: String do + if n_moduledecl != null and n_moduledecl.n_doc != null then + return n_moduledecl.n_doc.short_comment end - return ret + return "" 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 + private fun full_comment: String do + if n_moduledecl != null and n_moduledecl.n_doc != null then + return n_moduledecl.n_doc.full_comment + end + return "" 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 + private fun full_markdown: String do + if n_moduledecl != null and n_moduledecl.n_doc != null then + return n_moduledecl.n_doc.full_markdown.html + end + return "" + 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 + private fun doc_location: Location do + if n_moduledecl != null and n_moduledecl.n_doc != null then + return n_moduledecl.n_doc.location end - return ret + return location 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 +redef class AStdClassdef + private fun short_comment: String do + if n_doc != null then return n_doc.short_comment + return "" end - redef fun signature: String do - var sign = "" - if n_signature != null then sign = " {n_signature.to_s}" - return sign + private fun full_comment: String do + if n_doc != null then return n_doc.full_comment + return "" 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 + private fun full_markdown: String do + if n_doc != null then return n_doc.full_markdown.html + return "" + end + + private fun doc_location: Location do + if n_doc != null then return n_doc.location + return location end end -redef class MClassDef - private fun namespace(mclass: MClass): String do +redef class APropdef + private fun short_comment: String do + if n_doc != null then return n_doc.short_comment + return "" + end - 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 + private fun full_comment: String do + if n_doc != null then return n_doc.full_comment + return "" + end + + private fun full_markdown: String do + if n_doc != null then return n_doc.full_markdown.html + return "" + end + + private fun doc_location: Location do + if n_doc != null then return n_doc.location + return location 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) -nitdoc.start +var nitdoc = new NitdocContext +nitdoc.generate_nitdoc