X-Git-Url: http://nitlanguage.org diff --git a/src/nitdoc.nit b/src/nitdoc.nit index 2765264..bdaa346 100644 --- a/src/nitdoc.nit +++ b/src/nitdoc.nit @@ -27,7 +27,8 @@ class DocContext super AbstractCompiler # Destination directory readable writable var _dir: String = "doc" - + # GitHub Repo name + var github_repo: nullable String = null # Content of a generated file var _stage_context: StageContext = new StageContext(null) @@ -86,8 +87,12 @@ class DocContext readable var _opt_private: OptionBool = new OptionBool("Generate the private API", "--private") readable var _opt_nodot: OptionBool = new OptionBool("Do not generate graphes with graphviz", "--no-dot") readable var _opt_sharedir: OptionString = new OptionString("Directory containing the nitdoc files", "--sharedir") - readable var _opt_overview_text: OptionString = new OptionString("Text displayed as introduction of Overview page", "--overview-text") - readable var _opt_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--footer-text") + + readable 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") + readable 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") + readable var _opt_custom_overview_text: OptionString = new OptionString("Text displayed as introduction of Overview page before the modules list", "--custom-overview-text") + readable var _opt_custom_footer_text: OptionString = new OptionString("Text displayed as footer of all pages", "--custom-footer-text") + readable var _opt_github_repo_name: OptionString = new OptionString("GitHub repo name, example: --github MyRepoName", "--github") var sharedir: nullable String fun public_only: Bool @@ -157,27 +162,33 @@ class DocContext end var head = "" + - "\n" + + "\n" + + "\n" + "\n" + "" - var action_bar = "
\n" + var custom_items = "" + if self._opt_custom_menu_items.value != null then custom_items = self._opt_custom_menu_items.value.as(not null) + var action_bar = "
\n" + var custom_title = "Nitdoc" + if self._opt_custom_title.value != null then custom_title = self._opt_custom_title.value.as(not null) + var overview_text = "" - if self._opt_overview_text.value != null then overview_text = self._opt_overview_text.value.as(not null) + if self._opt_custom_overview_text.value != null then overview_text = self._opt_custom_overview_text.value.as(not null) var footer_text = "" - if self._opt_footer_text.value != null then footer_text = self._opt_footer_text.value.as(not null) - + if self._opt_custom_footer_text.value != null then footer_text = self._opt_custom_footer_text.value.as(not null) + # generate the index self.filename = "index.html" clear add("") - add("{head}Index\n") + add("{head}Overview | {custom_title}\n") add(action_bar) add("
") add("
") - add("

Modules

\n
{overview_text}
    ") + add("

    {custom_title}

    \n
    {overview_text}

    Modules

      ") var modss = mainmod.mhe.greaters_and_self.to_a sort(modss) for mod in modss do @@ -203,9 +214,10 @@ class DocContext op.append("\}\n") self.gen_dot(op.to_s, "dep", "Modules hierarchy") add("
") - add("
") add("
") add("") + addGithubInformation + addCommitForm add("\n") write_to("{dir}/index.html") @@ -215,15 +227,17 @@ class DocContext assert mod isa MMSrcModule if not mod.require_doc(self) then continue self.filename = mod.html_name - action_bar = "
\n" + action_bar = "
\n" clear add("") - add("{head}Module {mod.name}\n") + add("{head}{mod.name} module | {custom_title}\n") add(action_bar) add("
") mod.file_page_doc(self) add("
") add("") + addGithubInformation + addCommitForm add("\n") write_to("{dir}/{mod.html_name}.html") end @@ -232,24 +246,26 @@ class DocContext for c in mainmod.local_classes do if not c.require_doc(self) then continue self.filename = c.html_name - action_bar = "
\n" + action_bar = "
\n" clear add("") - add("{head}Class {c.name}\n") + add("{head}{c.name} class | {custom_title}\n") add(action_bar) add("
") c.file_page_doc(self) add("
") add("") + addGithubInformation + addCommitForm add("\n") write_to("{dir}/{c.html_name}.html") end self.filename = "fullindex" - action_bar = "
\n" + action_bar = "
\n" clear add("") - add("{head}Full Index\n") + add("{head}Full Index | {custom_title}\n") add(action_bar) add("
") add("
") @@ -257,17 +273,33 @@ class DocContext add("
") add("
") add("") + addGithubInformation + addCommitForm add("\n") write_to("{dir}/full-index.html") + + self.filename = "quicksearch-list" + clear + mainmod.file_quicksearch_list_doc(self) + write_to("{dir}/quicksearch-list.js") + end + + # Add or not a tag for the github repository + fun addGithubInformation do + if not github_repo == null then add("
") end + # Add all tags for the commit form + fun addCommitForm do + add("
Signed-Off
Commit

YesNo
\n\n") + end # Add a (source) link fo a given location fun show_source(l: Location) do var s = opt_source.value if s == null then - add("in {l.file.filename.simplify_path}") + add("({l.file.filename.simplify_path})") else # THIS IS JUST UGLY ! (but there is no replace yet) var x = s.split_with("%f") @@ -280,6 +312,24 @@ class DocContext end end + # Return source link for a given location + fun get_source(l: Location): String + do + var s = opt_source.value + if s == null then + return l.file.filename.simplify_path + else + # THIS IS JUST UGLY ! (but there is no replace yet) + var x = s.split_with("%f") + s = x.join(l.file.filename.simplify_path) + x = s.split_with("%l") + s = x.join(l.line_start.to_s) + x = s.split_with("%L") + s = x.join(l.line_end.to_s) + return s + end + end + # Generate a clicable graphiz image using a dot content. # `name' refer to the filename (without extension) and the id name of the map. # `name' must also match the name of the graph in the dot content (eg. digraph NAME {...) @@ -307,8 +357,11 @@ class DocContext option_context.add_option(opt_source) option_context.add_option(opt_nodot) option_context.add_option(opt_sharedir) - option_context.add_option(opt_overview_text) - option_context.add_option(opt_footer_text) + option_context.add_option(opt_custom_title) + option_context.add_option(opt_custom_menu_items) + option_context.add_option(opt_custom_overview_text) + option_context.add_option(opt_custom_footer_text) + option_context.add_option(opt_github_repo_name) end redef fun process_options @@ -328,7 +381,7 @@ class DocContext sharedir = opt_sharedir.value if sharedir == null then - var dir = once ("NIT_DIR".to_symbol).environ + var dir = "NIT_DIR".environ if dir.is_empty then dir = "{sys.program_name.dirname}/../share/nitdoc" if dir.file_exists then sharedir = dir @@ -345,6 +398,8 @@ class DocContext end end + var git = opt_github_repo_name.value + if not git == null then github_repo = git end redef fun handle_property_conflict(lc, impls) @@ -427,7 +482,7 @@ class AlphaSorter[E: Object] end # Generalization of metamodel entities -class MMEntity +interface MMEntity # Return a link to fun html_link(dctx: DocContext): String is abstract @@ -437,12 +492,44 @@ class MMEntity # The doc node from the AST # Return null is none fun doc: nullable ADoc do return null + + # Return a JSON entry for quicksearch list + fun json_entry(dctx: DocContext): String is abstract + + # Return the qualified name as string + fun qualified_name: String is abstract + end redef class MMModule super MMEntity redef fun html_link(dctx) do - return "{self}" + if short_doc == " " then + return "{self}" + else + return "{self}" + end + end + + fun html_anchor: String do + return "" + end + + fun html_link_to_anchor: String do + return "{self}" + end + + redef fun json_entry(dctx) do + return "\{txt:\"{self.qualified_name}\",url:\"{html_name}.html\"\}," + end + + redef fun qualified_name do + var buffer = new Buffer + for m in mnhe.smallers do + buffer.append("{m.html_name}::") + end + buffer.append("{self.name}") + return buffer.to_s end fun require_doc(dctx: DocContext): Bool @@ -547,13 +634,16 @@ redef class MMModule dctx.add("{m.html_link(dctx)}::") end dctx.add("{self.name}\n") - + dctx.add("
") dctx.add("
\n") var doc = doc if doc != null then dctx.add("
\n") - dctx.add("
{doc.to_html}
\n") + dctx.add("
{doc.to_html}
\n") + dctx.add("\n") + dctx.add("CancelCommit") + dctx.add("
")
 			dctx.add("
\n") end @@ -776,7 +866,7 @@ redef class MMModule var lpi = self[gp.intro.local_class.global][gp] lps.remove(lpi) - dctx.add("
  • I {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})
  • \n") + dctx.add("
  • I {lpi.html_open_link(dctx)}{lpi.html_name} ({lpi.local_class})
  • \n") if lps.length >= 1 then dctx.sort(lps) for lp in lps do @@ -787,14 +877,81 @@ redef class MMModule dctx.stage("\n") dctx.close_stage end + + # Fill the quicksearch list JSON object + fun file_quicksearch_list_doc(dctx: DocContext) + do + var entities = new HashMap[String, Array[MMEntity]] + var props = new HashMap[MMGlobalProperty, Array[MMLocalProperty]] + for m in mhe.greaters_and_self do + if not m.require_doc(dctx) then continue + var a = new Array[MMEntity] + a.add(m) + entities[m.html_name] = a + end + for g in global_classes do + var lc = self[g] + if not lc.require_doc(dctx) then continue + var a = new Array[MMEntity] + a.add(lc) + entities[lc.html_name] = a + for gp in lc.global_properties do + var lp = lc[gp] + if not lp.require_doc(dctx) then continue + if lp.kind == "var" then continue + if props.has_key(lp.global) then + if not props[lp.global].has(lp) then + props[lp.global].add(lp) + end + else + props[lp.global] = [lp] + end + end + end + + for k, v in props do + entities[k.short_name] = v + end + + var keys = entities.keys.to_a + var sorter = new AlphaSorter[String] + sorter.sort(keys) + + dctx.open_stage + dctx.stage("var entries = \{") + for key in keys do + dctx.add("\"{key}\": [") + for entity in entities[key] do + dctx.add(entity.json_entry(dctx)) + end + dctx.add("],") + end + dctx.stage("\};") + dctx.close_stage + end end +redef class MMGlobalProperty + # Return the short name of the property + fun short_name: String do + return self.intro.html_name + end +end + redef class MMLocalProperty super MMEntity # Anchor of the property description in the module html file fun html_anchor: String do - return "PROP_{local_class}_{cmangle(name)}" + return "PROP_{self.mmmodule.toplevel_owner}_{local_class}_{cmangle(name)}" + end + + redef fun json_entry(dctx) do + return "\{txt:\"{qualified_name}\",url:\"{local_class.html_name}.html#{html_anchor}\"\}," + end + + redef fun qualified_name do + return "{intro_module.qualified_name}::{local_class.html_name}::{html_name}" end fun html_open_link(dctx: DocContext): String @@ -914,7 +1071,6 @@ redef class MMLocalProperty dctx.add("
    \n") dctx.add("

    {html_name}{signature.to_html(dctx, true)}

    \n") dctx.add("
    \n") - #dctx.add("

    LP: {self.mmmodule.html_link(dctx)}::{self.local_class.html_link(dctx)}::{self.html_link(dctx)}

    ") if is_redef then dctx.add("redef ") @@ -935,12 +1091,12 @@ redef class MMLocalProperty dctx.add("::{mmmodule[intro_class.global].html_link(dctx)}") end if is_redef then - dctx.add("::{mmmodule[intro_class.global][global].html_link(dctx)}") + dctx.add("::{mmmodule[intro_class.global][global].global.intro.html_link(dctx)}") else dctx.add("::{html_name}") end dctx.add("
    ") - + dctx.add("
    ") dctx.add("
    ") # Collect all refinement of the global property in the same global property @@ -956,7 +1112,10 @@ redef class MMLocalProperty end end if introdoc then - dctx.add("
    {global.intro.doc.to_html}
    ") + dctx.add("
    {global.intro.doc.to_html}
    ") + dctx.add("") + dctx.add("CancelCommit") + dctx.add("
    ")
     		end
     
     		var tlmods = new Array[MMModule]
    @@ -972,7 +1131,7 @@ redef class MMLocalProperty
     			var tlp
     			if tm.global_classes.has(lc.global) then
     				tlp = tm[lc.global][self.global]
    -				assert lps.has(tlp)
    +				#assert lps.has(tlp) # FIXME What this line is used for?
     			else if tm.global_classes.has(self.local_class.global) then
     				# Self is the inherited property. Process it
     				tlp = tm[self.local_class.global][self.global]
    @@ -987,12 +1146,22 @@ redef class MMLocalProperty
     				dctx.add("

    In module {tm.html_link(dctx)} :

    ") end - #dctx.add("

    TLP: {tm} x {lc} : {tlp.full_name}

    ") - var doc = tlp.doc + var n = tlp.node if doc != null and (not introdoc or global.intro.doc != doc) then - dctx.add("
    {doc.to_html}
    ") + if n != null then + var l = n.location + dctx.add("
    {doc.to_html}
    ") + end + else if not is_redef then + if n != null then + var l = n.location + dctx.add("New comment\n") + end end + dctx.add("") + dctx.add("CancelCommit") + dctx.add("
    ")
     			dctx.add("

    ") if tlp.local_class.global != lc.global then dctx.add("inherited from {tlp.local_class.html_link(dctx)} ") @@ -1000,7 +1169,6 @@ redef class MMLocalProperty if tm != tlp.mmmodule then dctx.add("defined by the module {tlp.mmmodule.html_link(dctx)} ") end - var n = tlp.node if n != null then var l = n.location dctx.show_source(l) @@ -1022,11 +1190,6 @@ redef class MMLocalProperty var l = n.location dctx.show_source(l) end - - #var doc = lp.doc - #if doc != null and (not introdoc or global.intro.doc != doc) then - # dctx.add("

    {doc.to_html}
    ") - #end end dctx.close_stage dctx.add("

    ") @@ -1104,7 +1267,19 @@ redef class MMLocalClass redef fun html_link(dctx) do if not require_doc(dctx) then print "{dctx.filename}: not required {self}" - return "{self}" + if short_doc == " " then + return "{self}" + else + return "{self}" + end + end + + redef fun json_entry(dctx) do + return "\{txt:\"{qualified_name}\",url:\"{html_name}.html\"\}," + end + + redef fun qualified_name do + return "{intro_module.qualified_name}::{html_name}" end redef fun short_doc do return global.intro.short_doc @@ -1265,11 +1440,15 @@ redef class MMLocalClass dctx.add("(unexported) ") end dctx.add("{kind} {global.intro.mmmodule.toplevel_owner.html_link(dctx)}::{name}
    ") - + dctx.add("
    ") dctx.add("
    \n") var doc = doc if doc != null then - dctx.add("
    {doc.to_html}
    \n") + var l = doc.location + dctx.add("
    {doc.to_html}
    \n") + dctx.add("") + dctx.add("CancelCommit") + dctx.add("
    ")
     		end
     
     		var cla = new HashSet[MMLocalClass]
    @@ -1314,7 +1493,12 @@ redef class MMLocalClass
     		end
     		op.append("\}\n")
     		dctx.gen_dot(op.to_s, name.to_s, "Inheritance graph for class {name}")
    +		dctx.add("
    \n") + # Concerns table + dctx.open_stage + dctx.stage("
    \n") + dctx.stage("

    Concerns

    \n") var mods = new Array[MMModule] mods.add(global.intro.mmmodule.toplevel_owner) @@ -1323,28 +1507,28 @@ redef class MMLocalClass var m = lc.mmmodule.toplevel_owner if not mods.has(m) then mods.add(m) end - dctx.sort(mods) + + var intro = global.intro.mmmodule + var short_doc + dctx.add("
      \n") for m in mods do - if m == global.intro.mmmodule.toplevel_owner then - dctx.add("

      Introduced by {m.html_link(dctx)}") - else - dctx.add("

      Refined by {m.html_link(dctx)}") - end - dctx.open_stage - dctx.stage(". Definition in:") - for lc in crhe.greaters do + short_doc = "" + if m.short_doc != " " then short_doc = ": {m.short_doc}" + dctx.add("

    • {m.html_link_to_anchor}{short_doc}") + dctx.add("
        \n") + for lc in crhe.linear_extension.reversed do if lc.mmmodule.toplevel_owner != m then continue - dctx.add(" {lc.mmmodule.html_link(dctx)} ") - assert lc isa MMSrcLocalClass - var n = lc.node - if n != null then - dctx.show_source(n.location) - end + if lc.mmmodule == m then continue + short_doc = "" + if lc.mmmodule.short_doc != " " then short_doc = ": {lc.mmmodule.short_doc}" + dctx.add("
      • {lc.mmmodule.html_link_to_anchor}{short_doc}
      • ") end - dctx.close_stage - dctx.add("

        \n") + dctx.add("
      \n") + dctx.add("
    • \n") end - dctx.add("
    \n") + dctx.add("\n") + dctx.stage("
    \n") + dctx.close_stage dctx.open_stage dctx.stage("
    \n") @@ -1373,23 +1557,89 @@ redef class MMLocalClass dctx.open_stage dctx.stage("
    \n") dctx.stage("

    Methods

    \n") + var redefs = new HashMap[MMModule, HashMap[MMModule, Array[MMMethod]]] for p in props do if p.global.is_init then continue if p.local_class.global != self.global then continue if not p isa MMMethod then continue - p.full_documentation(dctx, self) + # Top level module + var toplevel_module = p.mmmodule.toplevel_owner + if not redefs.has_key(toplevel_module) then + redefs[toplevel_module] = new HashMap[MMModule, Array[MMMethod]] + end + # Nested module + var nested_module = p.mmmodule + if not redefs[toplevel_module].has_key(nested_module) then + redefs[toplevel_module][nested_module] = new Array[MMMethod] + end + # Props + redefs[toplevel_module][nested_module].add(p) + + # Redefs + if p.mmmodule.toplevel_owner != p.intro_module then + toplevel_module = p.intro_module + nested_module = p.global.intro.mmmodule + + if not redefs.has_key(toplevel_module) then + redefs[toplevel_module] = new HashMap[MMModule, Array[MMMethod]] + end + if not redefs[toplevel_module].has_key(nested_module) then + redefs[toplevel_module][nested_module] = new Array[MMMethod] + end + + redefs[toplevel_module][nested_module].add(p.global.intro.as(MMMethod)) + end + end + + # Display toplevel blocks + for m in mods do + if not redefs.has_key(m) then continue + dctx.add(m.html_anchor) + if m != global.intro.mmmodule.toplevel_owner then + dctx.add("

    Methods refined in {m.html_link(dctx)}

    ") + end + + # Display nested module blocks + for lc in crhe.linear_extension.reversed do + if lc.mmmodule.toplevel_owner != m then continue + var nm = lc.mmmodule + if not redefs[m].has_key(nm) then continue + dctx.add(nm.html_anchor) + if nm != global.intro.mmmodule then + short_doc = "" + if nm.short_doc != " " then short_doc = ": {nm.short_doc}" + dctx.add("

    {nm.html_name}{short_doc}

    \n") + end + + var pps = redefs[m][nm] + dctx.sort(pps) + for p in pps do + p.full_documentation(dctx, self) + end + end end + if not inhs.is_empty then dctx.open_stage dctx.stage("

    Inherited Methods

    \n") for lc in inhs do dctx.open_stage dctx.stage("

    Defined in {lc.html_link(dctx)}:") + + var ims = new Array[MMMethod] for p in inh[lc] do if p.global.is_init then continue if not p isa MMMethod then continue + ims.add(p) + end + + var i = 0 + for p in ims do dctx.add(" {p.html_link(dctx)}") + if i < ims.length - 1 then dctx.add(",") + i += 1 end + dctx.stage("

    ") dctx.close_stage end