X-Git-Url: http://nitlanguage.org diff --git a/src/ni_nitdoc.nit b/src/ni_nitdoc.nit index 770a568..535614b 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,15 +12,17 @@ # 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 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 @@ -46,31 +46,30 @@ class NitdocContext 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 @@ -80,10 +79,10 @@ class NitdocContext 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 @@ -158,19 +157,17 @@ class NitdocContext 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 @@ -180,15 +177,13 @@ class NitdocContext 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 @@ -196,21 +191,22 @@ 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 protected fun head do append("") append("") + append("") append("") + append("") + append("") append("") append("") var title = "" @@ -233,43 +229,6 @@ abstract class NitdocPage append("") append("") @@ -312,12 +271,12 @@ abstract class NitdocPage source = x.join(l.line_start.to_s) x = source.split_with("%L") source = x.join(l.line_end.to_s) - return " (source)" + return " (source)" end end # Render the page as a html string - fun render: String do + protected fun render do append("") append("") head @@ -329,15 +288,18 @@ abstract class NitdocPage append("") footer append("") - 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 @@ -362,7 +324,7 @@ class NitdocOverview end end # sort modules - var sorter = new ComparableSorter[MModule] + var sorter = new MModuleNameSorter self.mmodules.add_all(mmodules) sorter.sort(self.mmodules) end @@ -376,7 +338,9 @@ class NitdocOverview end redef fun content do - append("
") + 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 @@ -451,7 +415,9 @@ class NitdocFullindex end redef fun content do - append("
") + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
") append("

Full Index

") module_column classes_column @@ -462,7 +428,7 @@ class NitdocFullindex # 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("
") append("

Modules

") @@ -479,7 +445,7 @@ class NitdocFullindex # 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("
") append("

Classes

") @@ -497,7 +463,7 @@ class NitdocFullindex # 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("
") append("

Properties

") @@ -549,7 +515,9 @@ class NitdocModule redef fun content do sidebar - append("
") + var footed = "" + if ctx.opt_custom_footer_text.value != null then footed = "footed" + append("
") append("

{mmodule.name}

") append("
") mmodule.html_signature(self) @@ -612,6 +580,7 @@ class NitdocModule end var clients = new Array[MModule] for dep in mmodule.in_importation.smallers do + if dep.name == "
" then continue if dep == mmodule or dep.public_owner != null then continue clients.add(dep) end @@ -633,7 +602,7 @@ class NitdocModule private fun display_module_list(list: Array[MModule]) do append("
    ") - var sorter = new ComparableSorter[MModule] + var sorter = new MModuleNameSorter sorter.sort(list) for m in list do append("
  • ") @@ -657,7 +626,7 @@ class NitdocModule var sorted = new Array[MClass] sorted.add_all(all_mclasses) - var sorter = new ComparableSorter[MClass] + var sorter = new MClassNameSorter sorter.sort(sorted) append("
    ") append("
    ") @@ -689,7 +658,7 @@ class NitdocModule 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("
    ") @@ -735,18 +704,23 @@ class NitdocClass 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 @@ -781,13 +755,15 @@ class NitdocClass properties_column inheritance_column append("
    ") - 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 ComparableSorter[MPropDef] + var sorter = new MPropDefNameSorter append("
    ") # comment var nclass = ctx.mbuilder.mclassdef2nclassdef[mclass.intro] - append("
    ") append("
    ") - if nclass isa AStdClassdef and not nclass.full_comment.is_empty then append("
    {nclass.full_comment}
    CancelCommit
    ")
     		process_generate_dot
     		append("
    ") # concerns @@ -944,9 +918,7 @@ class NitdocClass append("
") append("") # 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] @@ -958,9 +930,9 @@ class NitdocClass if mclass.arity > 0 and nclass isa AStdClassdef then for ft, bound in mclass.parameter_types do append("
") - append("

{ft}: ") + append("

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

") + append("") append("
formal generic type
") append("
") end @@ -1036,7 +1008,7 @@ class NitdocClass prop_sorter.sort(mmethods) append("

Defined in ") c.html_link(self) - append("}: ") + append(": ") for i in [0..mmethods.length[ do var mmethod = mmethods[i] mmethod.html_link(self) @@ -1100,42 +1072,52 @@ end # 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("{name}") - else - page.append("{name}") + if html_link_cache == null then + var res = new Buffer + if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then + res.append("{name}") + else + res.append("{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 fun html_signature(page: NitdocPage) do @@ -1173,20 +1155,12 @@ redef class MModule if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then page.append("

") page.append("
{page.ctx.mbuilder.mmodule2nmodule[self].full_comment}
") - page.append("") - page.append("Cancel") - page.append("Commit") - page.append("
")
 			page.append("
") 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} ") @@ -1206,15 +1180,21 @@ redef class MClass # Return a link (html a tag) to the nitdoc class page fun html_link(page: NitdocPage) do - page.append("{signature}") + html_link_cache = res.to_s end - page.append(">{signature}") + 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 @@ -1225,7 +1205,7 @@ redef class MClass end fun url: String do - return "class_{public_owner}_{c_name}.html" + return "class_{public_owner}_{name}.html" end # Escape name for html output @@ -1233,10 +1213,6 @@ redef class MClass 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) @@ -1297,22 +1273,37 @@ redef class MClassDef 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("{mproperty.name}") - else - page.append("{mproperty.name}") + 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.name}") + else + res.append("{mproperty.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 a list item for the mpropdef private fun html_list_item(page: NitdocPage) do @@ -1411,45 +1402,60 @@ redef class MPropDef end page.append(".

") end + + private fun html_comment(page: NitdocClass) do + if not page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then return + var nprop = page.ctx.mbuilder.mpropdef2npropdef[self] + page.append("
") + 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("

from ") + mproperty.html_namespace(page) + page.append("

") + if intro_nprop.full_comment == "" then + page.append("No comment") + else + page.append("
{intro_nprop.full_comment}
") + end + page.append("

from ") + mclassdef.html_namespace(page) + page.append("

") + end + if nprop.full_comment == "" then + page.append("No comment") + else + page.append("
{nprop.full_comment}
") + end + html_inheritance(page) + page.append("
") + end end redef class MMethodDef redef fun html_full_desc(page) do - if not page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then return - var nprop = page.ctx.mbuilder.mpropdef2npropdef[self] var classes = new Array[String] var is_redef = mproperty.intro_mclassdef.mclass != page.mclass - classes.add("fun") - if mproperty.is_init then classes.add("init") + if mproperty.is_init then + classes.add("init") + else + classes.add("fun") + end if is_redef then classes.add("redef") classes.add(mproperty.visibility.to_s) page.append("
") - if nprop isa AAttrPropdef then - if nprop.mreadpropdef == self then - page.append("

{mproperty.name}: ") - nprop.html_signature(page) - page.append("

") - else - page.append("

{mproperty.name}(value: ") - nprop.html_signature(page) - page.append(")

") - end + if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then + page.append("

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

") else - var intro_nprop = page.ctx.mbuilder.mpropdef2npropdef[mproperty.intro] - page.append("

{mproperty.name}") - intro_nprop.html_signature(page) - page.append("

") + page.append("

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

") end html_info(page) - page.append("
") - if nprop.full_comment == "" then - page.append("New Comment") - else - page.append("
{nprop.full_comment}
") - end - page.append("CancelCommit
")
-		html_inheritance(page)
-		page.append("
") + html_comment(page) page.append("
") end @@ -1457,10 +1463,13 @@ redef class MMethodDef page.append("
") if mproperty.visibility < public_visibility then page.append("{mproperty.visibility.to_s} ") if mproperty.intro_mclassdef.mclass != page.mclass then page.append("redef ") - page.append("fun ") + if mproperty.is_init then + page.append("init ") + else + page.append("fun ") + end mproperty.html_namespace(page) page.append("
") - page.append("
") end end @@ -1472,21 +1481,11 @@ redef class MVirtualTypeDef if is_redef then classes.add("redef") classes.add(mproperty.visibility.to_s) page.append("
") - page.append("

{mproperty.name}: ") + page.append("

{mproperty.name}: ") bound.html_link(page) - page.append("

") + page.append("") html_info(page) - page.append("
") - - if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) and page.ctx.mbuilder.mpropdef2npropdef[self].full_comment != "" then - var nprop = page.ctx.mbuilder.mpropdef2npropdef[self] - page.append("
{nprop.full_comment}
") - else - page.append("New Comment") - end - page.append("CancelCommit
")
-		html_inheritance(page)
-		page.append("
") + html_comment(page) page.append("
") end @@ -1496,7 +1495,44 @@ redef class MVirtualTypeDef page.append("type ") mproperty.html_namespace(page) page.append("
") - page.append("
") + end +end + +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 + if return_mtype != null then + page.append(": ") + return_mtype.html_link(page) + end + end + + 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 MParameter + private fun html_link(page: NitdocPage) do + page.append("{name}: ") + mtype.html_link(page) + if is_vararg then page.append("...") end end @@ -1539,95 +1575,18 @@ redef class AStdClassdef end redef class APropdef - private fun short_comment: String is abstract - private fun full_comment: String is abstract - private fun html_signature(page: NitdocPage) is abstract -end - -redef class AAttrPropdef - redef fun short_comment do - if n_doc != null then return n_doc.n_comment.first.text.substring_from(2).replace("\n", "").html_escape - return "" - end - - redef fun full_comment: String do - var res = new Buffer - if n_doc != null then - for t in n_doc.n_comment do res.append(t.text.substring_from(1).html_escape) - end - return res.to_s - end - - redef fun html_signature(page) do - if n_type != null then n_type.mtype.html_link(page) - end -end - -redef class AMethPropdef - redef fun short_comment do - if n_doc != null then return n_doc.n_comment.first.text.substring_from(2).replace("\n", "").html_escape - return "" - end - - redef fun full_comment do - var res = new Buffer - if n_doc != null then - for t in n_doc.n_comment do res.append(t.text.substring_from(1).html_escape) - end - return res.to_s - end - - redef fun html_signature(page) do - if n_signature != null then n_signature.html_link(page) - end -end - -redef class ATypePropdef - redef fun short_comment do + private fun short_comment: String do if n_doc != null then return n_doc.n_comment.first.text.substring_from(2).replace("\n", "").html_escape return "" end - redef fun full_comment do + private fun full_comment: String do var res = new Buffer if n_doc != null then for t in n_doc.n_comment do res.append(t.text.substring_from(1).html_escape) end return res.to_s end - - redef fun html_signature(page) do - mpropdef.bound.html_link(page) - end -end - -redef class ASignature - fun html_link(page: NitdocPage) do - #TODO closures - if not n_params.is_empty then - page.append("(") - for i in [0..n_params.length[ do - n_params[i].html_link(page) - if i < n_params.length - 1 then page.append(", ") - end - page.append(")") - end - if n_type != null then - page.append(":") - n_type.mtype.html_link(page) - end - end -end - -redef class AParam - fun html_link(page: NitdocPage) do - page.append(n_id.text) - if n_type != null then - page.append(": ") - n_type.mtype.html_link(page) - if n_dotdotdot != null then page.append("...") - end - end end var nitdoc = new NitdocContext