module ni_nitdoc
import model_utils
-import abstract_compiler
+import modelize_property
# The NitdocContext contains all the knowledge used for doc generation
class NitdocContext
- super ToolContext
+ private var toolcontext = new ToolContext
private var model: Model
private var mbuilder: ModelBuilder
private var mainmodule: MModule
private var opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text")
init do
- super
- self.arguments = option_context.rest
- option_context.options.clear
- option_context.add_option(opt_dir)
- option_context.add_option(opt_source)
- option_context.add_option(opt_sharedir)
- option_context.add_option(opt_nodot)
- option_context.add_option(opt_private)
- option_context.add_option(opt_custom_title)
- option_context.add_option(opt_custom_footer_text)
- option_context.add_option(opt_custom_overview_text)
- option_context.add_option(opt_custom_menu_items)
- process_options
+ 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.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.process_options
if arguments.length < 1 then
- option_context.usage
+ toolcontext.option_context.usage
exit(1)
end
model = new Model
- mbuilder = new ModelBuilder(model, self)
+ mbuilder = new ModelBuilder(model, toolcontext)
# Here we load an process all modules passed on the command line
- var mmodules = mbuilder.parse_and_build(arguments)
- mbuilder.full_propdef_semantic_analysis
+ var mmodules = mbuilder.parse(arguments)
if mmodules.is_empty then return
+ mbuilder.run_phases
if mmodules.length == 1 then
mainmodule = mmodules.first
mainmodule.set_imported_mmodules(mmodules)
end
self.class_hierarchy = mainmodule.flatten_mclass_hierarchy
+ self.process_options
end
- redef fun process_options do
- super
+ private fun process_options do
if not opt_dir.value is null then
output_dir = opt_dir.value
else
private fun quicksearch_list do
var file = new OFStream.open("{output_dir.to_s}/quicksearch-list.js")
- var content = new Buffer
- content.append("var entries = \{ ")
-
+ file.write("var entries = \{ ")
for mmodule in model.mmodules do
- content.append("\"{mmodule.name}\": [")
- content.append("\{txt: \"{mmodule.name}\", url:\"{mmodule.url}\" \},")
- content.append("],")
+ file.write("\"{mmodule.name}\": [")
+ file.write("\{txt: \"{mmodule.name}\", url:\"{mmodule.url}\" \},")
+ file.write("],")
end
for mclass in model.mclasses do
if mclass.visibility < min_visibility then continue
- content.append("\"{mclass.name}\": [")
- content.append("\{txt: \"{mclass.name}\", url:\"{mclass.url}\" \},")
- content.append("],")
+ file.write("\"{mclass.name}\": [")
+ file.write("\{txt: \"{mclass.name}\", url:\"{mclass.url}\" \},")
+ file.write("],")
end
var name2mprops = new HashMap[String, Set[MPropDef]]
for mproperty in model.mproperties do
name2mprops[mproperty.name].add_all(mproperty.mpropdefs)
end
for mproperty, mpropdefs in name2mprops do
- content.append("\"{mproperty}\": [")
+ file.write("\"{mproperty}\": [")
for mpropdef in mpropdefs do
- content.append("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
+ file.write("\{txt: \"{mpropdef.full_name}\", url:\"{mpropdef.url}\" \},")
end
- content.append("],")
+ file.write("],")
end
-
- content.append(" \};")
- file.write(content.to_s)
+ file.write(" \};")
file.close
end
# Nitdoc base page
abstract class NitdocPage
- super Buffer
var dot_dir: nullable String
var source: nullable String
var ctx: NitdocContext
init(ctx: NitdocContext) do
- super
self.ctx = ctx
end
append("<meta charset='utf-8'/>")
append("<script type='text/javascript' src='scripts/jquery-1.7.1.min.js'></script>")
append("<script type='text/javascript' src='quicksearch-list.js'></script>")
+ append("<script type='text/javascript' src='scripts/base64.js'></script>")
+ append("<script type='text/javascript' src='scripts/github.js'></script>")
append("<script type='text/javascript' src='scripts/js-facilities.js'></script>")
append("<link rel='stylesheet' href='styles/main.css' type='text/css' media='screen'/>")
var title = ""
append("<nav class='main'>")
append("<ul>")
menu
- append("<li id='liGitHub'>")
- append("<a class='btn' id='logGitHub'>")
- append("<img id='imgGitHub' src='resources/icons/github-icon.png' alt='GitHub'/>")
- append("</a>")
- append("<div class='popover bottom'>")
- append("<div class='arrow'> </div>")
- append("<div class='githubTitle'>")
- append("<h3>Github Sign In</h3>")
- append("</div>")
- append("<div>")
- append("<label id='lbloginGit'>Username</label>")
- append("<input id='loginGit' name='login' type='text'/>")
- append("<label id='logginMessage'>Hello ")
- append("<a id='githubAccount'><strong id='nickName'></strong></a>")
- append("</label>")
- append("</div>")
- append("<div>")
- append("<label id='lbpasswordGit'>Password</label>")
- append("<input id='passwordGit' name='password' type='password'/>")
- append("<div id='listBranches'>")
- append("<label id='lbBranches'>Branch</label>")
- append("<select class='dropdown' id='dropBranches' name='dropBranches' tabindex='1'></select>")
- append("</div>")
- append("</div>")
- append("<div>")
- append("<label id='lbrepositoryGit'>Repository</label>")
- append("<input id='repositoryGit' name='repository' type='text'/>")
- append("</div>")
- append("<div>")
- append("<label id='lbbranchGit'>Branch</label>")
- append("<input id='branchGit' name='branch' type='text'/>")
- append("</div>")
- append("<div>")
- append("<a id='signIn'>Sign In</a>")
- append("</div>")
- append("</div>")
- append("</li>")
append("</ul>")
append("</nav>")
append("</header>")
end
# Render the page as a html string
- fun render: String do
+ protected fun render do
append("<!DOCTYPE html>")
append("<head>")
head
append("</div>")
footer
append("</body>")
- return to_s
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
- var out = new OFStream.open(file)
- out.write(render)
- out.close
+ self.out = new OFStream.open(file)
+ render
+ self.out.close
end
+ private var out: nullable OFStream
end
# The overview page
end
end
# sort modules
- var sorter = new ComparableSorter[MModule]
+ var sorter = new MModuleNameSorter
self.mmodules.add_all(mmodules)
sorter.sort(self.mmodules)
end
end
redef fun content do
- append("<div class='content fullpage'>")
+ var footed = ""
+ if ctx.opt_custom_footer_text.value != null then footed = "footed"
+ append("<div class='content fullpage {footed}'>")
var title = "Overview"
if ctx.opt_custom_title.value != null then
title = ctx.opt_custom_title.value.to_s
end
redef fun content do
- append("<div class='content fullpage'>")
+ var footed = ""
+ if ctx.opt_custom_footer_text.value != null then footed = "footed"
+ append("<div class='content fullpage {footed}'>")
append("<h1>Full Index</h1>")
module_column
classes_column
# Add to content modules column
private fun module_column do
var sorted = ctx.mbuilder.model.mmodule_importation_hierarchy.to_a
- var sorter = new ComparableSorter[MModule]
+ var sorter = new MModuleNameSorter
sorter.sort(sorted)
append("<article class='modules filterable'>")
append("<h2>Modules</h2>")
# Add to content classes modules
private fun classes_column do
var sorted = ctx.mbuilder.model.mclasses
- var sorter = new ComparableSorter[MClass]
+ var sorter = new MClassNameSorter
sorter.sort(sorted)
append("<article class='modules filterable'>")
append("<h2>Classes</h2>")
# Insert the properties column of fullindex page
private fun properties_column do
var sorted = ctx.mbuilder.model.mproperties
- var sorter = new ComparableSorter[MProperty]
+ var sorter = new MPropertyNameSorter
sorter.sort(sorted)
append("<article class='modules filterable'>")
append("<h2>Properties</h2>")
redef fun content do
sidebar
- append("<div class='content'>")
+ var footed = ""
+ if ctx.opt_custom_footer_text.value != null then footed = "footed"
+ append("<div class='content {footed}'>")
append("<h1>{mmodule.name}</h1>")
append("<div class='subtitle info'>")
mmodule.html_signature(self)
private fun display_module_list(list: Array[MModule]) do
append("<ul>")
- var sorter = new ComparableSorter[MModule]
+ var sorter = new MModuleNameSorter
sorter.sort(list)
for m in list do
append("<li>")
var sorted = new Array[MClass]
sorted.add_all(all_mclasses)
- var sorter = new ComparableSorter[MClass]
+ var sorter = new MClassNameSorter
sorter.sort(sorted)
append("<div class='module'>")
append("<article class='classes filterable'>")
end
for c in mmodule.mclassdefs do mpropdefs.add_all(c.mpropdefs)
var sorted = mpropdefs.to_a
- var sorter = new ComparableSorter[MPropDef]
+ var sorter = new MPropDefNameSorter
sorter.sort(sorted)
# display properties in one column
append("<article class='properties filterable'>")
end
end
# get inherited properties
- for mprop in mclass.inherited_mproperties do
- var mpropdef = mprop.intro
- if mprop.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)
+ 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 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
- inherited.add(mpropdef)
end
end
properties_column
inheritance_column
append("</div>")
- append("<div class='content'>")
+ var footed = ""
+ if ctx.opt_custom_footer_text.value != null then footed = "footed"
+ append("<div class='content {footed}'>")
class_doc
append("</div>")
end
private fun properties_column do
- var sorter = new ComparableSorter[MPropDef]
+ var sorter = new MPropDefNameSorter
append("<nav class='properties filterable'>")
append("<h3>Properties</h3>")
# virtual types
private fun inheritance_column do
var sorted = new Array[MClass]
- var sorterp = new ComparableSorter[MClass]
+ var sorterp = new MClassNameSorter
append("<nav>")
append("<h3>Inheritance</h3>")
var greaters = mclass.in_hierarchy(ctx.mainmodule).greaters.to_a
append("</div>")
# comment
var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro]
- append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
append("<section class='description'>")
- if nclass isa AStdClassdef and not nclass.full_comment.is_empty then append("<pre class=\"text_label\" title=\"122\" name=\"\" tag=\"{mclass.mclassdefs.first.location.to_s}\" type=\"2\">{nclass.full_comment}</pre><textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
process_generate_dot
append("</section>")
# concerns
append("</ul>")
append("</section>")
# properties
- var prop_sorter = new ComparableSorter[MPropDef]
- var sorterprop = new ComparableSorter[MProperty]
- var sorterc = new ComparableSorter[MClass]
+ var prop_sorter = new MPropDefNameSorter
var lmmodule = new List[MModule]
# virtual and formal types
var local_vtypes = new Array[MVirtualTypeDef]
#
redef class MModule
- super Comparable
- redef type OTHER: MModule
- redef fun <(other: OTHER): Bool do return self.name < other.name
-
# URL to nitdoc page
fun url: String do
- var res = new Buffer
- res.append("module_")
- var mowner = public_owner
- if mowner != null then
- res.append("{public_owner.name}_")
+ 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
- res.append("{self.name}.html")
- return res.to_s
+ return url_cache.as(not null)
end
+ private var url_cache: nullable String
# html anchor id to the module in a nitdoc page
fun anchor: String do
- var res = new Buffer
- res.append("MOD_")
- var mowner = public_owner
- if mowner != null then
- res.append("{public_owner.name}_")
+ 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
- res.append(self.name)
- return res.to_s
+ return anchor_cache.as(not null)
end
+ private var anchor_cache: nullable String
# Return a link (html a tag) to the nitdoc module page
fun html_link(page: NitdocPage) do
- if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
- page.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>")
- else
- page.append("<a href='{url}'>{name}</a>")
+ if html_link_cache == null then
+ var res = new Buffer
+ if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
+ res.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{name}</a>")
+ else
+ res.append("<a href='{url}'>{name}</a>")
+ 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
fun html_signature(page: NitdocPage) do
if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
page.append("<div id='description'>")
page.append("<pre class='text_label'>{page.ctx.mbuilder.mmodule2nmodule[self].full_comment}</pre>")
- page.append("<textarea class='edit' rows='1' cols='76' id='fileContent'></textarea>")
- page.append("<a id='cancelBtn'>Cancel</a>")
- page.append("<a id='commitBtn'>Commit</a>")
- page.append("<pre class='text_label' id='preSave' type='2'></pre>")
page.append("</div>")
end
end
end
redef class MClass
- super Comparable
- redef type OTHER: MClass
- redef fun <(other: OTHER): Bool do return self.name < other.name
-
# Return the module signature decorated with html
fun html_full_signature(page: NitdocPage) do
if visibility < public_visibility then page.append("{visibility.to_s} ")
# Return a link (html a tag) to the nitdoc class page
fun html_link(page: NitdocPage) do
- page.append("<a href='{url}'")
- if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
- var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
- if nclass isa AStdClassdef then
- page.append(" title=\"{nclass.short_comment}\"")
+ if html_link_cache == null then
+ var res = new Buffer
+ res.append("<a href='{url}'")
+ if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
+ var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
+ if nclass isa AStdClassdef then
+ res.append(" title=\"{nclass.short_comment}\"")
+ end
end
+ res.append(">{signature}</a>")
+ html_link_cache = res.to_s
end
- page.append(">{signature}</a>")
+ page.append(html_link_cache.as(not null))
end
+ private var html_link_cache: nullable String
# Return the class namespace decorated with html
fun html_namespace(page: NitdocPage) do
end
fun url: String do
- return "class_{public_owner}_{c_name}.html"
+ return "class_{public_owner}_{name}.html"
end
# Escape name for html output
end
redef class MProperty
- super Comparable
- redef type OTHER: MProperty
- redef fun <(other: OTHER): Bool do return self.name < other.name
-
# Return the property namespace decorated with html
fun html_namespace(page: NitdocPage) do
intro_mclassdef.mclass.html_namespace(page)
end
redef class MPropDef
- super Comparable
- redef type OTHER: MPropDef
- redef fun <(other: OTHER): Bool do return self.mproperty.name < other.mproperty.name
+ 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
- fun url: String do return "{mclassdef.mclass.url}#{anchor}"
- fun anchor: String do return "PROP_{mclassdef.mclass.public_owner.name}_{c_name}"
+ fun anchor: String do
+ if anchor_cache == null then
+ anchor_cache = "PROP_{mclassdef.mclass.public_owner.name}_{mproperty.name}"
+ end
+ return anchor_cache.as(not null)
+ end
+ private var anchor_cache: nullable String
# Return a link (html a tag) to the nitdoc class page
fun html_link(page: NitdocPage) do
- if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
- var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
- page.append("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>")
- else
- page.append("<a href=\"{url}\">{mproperty.name}</a>")
+ 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("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.name}</a>")
+ else
+ res.append("<a href=\"{url}\">{mproperty.name}</a>")
+ 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 a list item for the mpropdef
private fun html_list_item(page: NitdocPage) do
if not page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then return
var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
page.append("<div class='description'>")
- if not is_intro then
+ if not is_intro and page.ctx.mbuilder.mpropdef2npropdef.has_key(mproperty.intro) then
var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro]
- page.append("<p>from ")
+ page.append("<p class='info'>from ")
mproperty.html_namespace(page)
page.append("</p>")
if intro_nprop.full_comment == "" then
- page.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
+ page.append("<span class=\"noComment\">No comment</span>")
else
- page.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{intro_nprop.full_comment}</pre>")
+ page.append("<pre>{intro_nprop.full_comment}</pre>")
end
- page.append("<p>from ")
+ page.append("<p class='info'>from ")
mclassdef.html_namespace(page)
page.append("</p>")
end
if nprop.full_comment == "" then
- page.append("<a class=\"newComment\" title=\"32\" tag=\"\">New Comment</a>")
+ page.append("<span class=\"noComment\">No comment</span>")
else
- page.append("<pre class=\"text_label\" title=\"\" name=\"\" tag=\"\" type=\"1\">{nprop.full_comment}</pre>")
+ page.append("<pre>{nprop.full_comment}</pre>")
end
- page.append("<textarea id=\"fileContent\" class=\"edit\" cols=\"76\" rows=\"1\" style=\"display: none;\"></textarea><a id=\"cancelBtn\" style=\"display: none;\">Cancel</a><a id=\"commitBtn\" style=\"display: none;\">Commit</a><pre id=\"preSave\" class=\"text_label\" type=\"2\"></pre>")
html_inheritance(page)
page.append("</div>")
end
end
mproperty.html_namespace(page)
page.append("</div>")
- page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
end
end
page.append("type ")
mproperty.html_namespace(page)
page.append("</div>")
- page.append("<div style=\"float: right;\"><a id=\"lblDiffCommit\"></a></div>")
end
end