src/doc: introduce `html_comment` and `html_short_comment` services
[nit.git] / src / doc / doc_phases / doc_html.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Render the DocModel pages as HTML pages.
16 #
17 # FIXME this module is all f*cked up to maintain compatibility with
18 # the original `doc_templates` and `doc_model` modules.
19 # This will change in further refactorings.
20 module doc_html
21
22 import doc_structure
23 import doc_hierarchies
24 import doc_intros_redefs
25 import doc_graphs
26 import html_templates
27
28 redef class ToolContext
29
30 # File pattern used to link documentation to source code.
31 var opt_source = new OptionString("link for source (%f for filename, " +
32 "%l for first line, %L for last line)", "--source")
33
34 # Directory where the CSS and JS is stored.
35 var opt_sharedir = new OptionString("directory containing nitdoc assets", "--sharedir")
36
37 # Use a shareurl instead of copy shared files.
38 #
39 # This is usefull if you don't want to store the Nitdoc templates with your
40 # documentation.
41 var opt_shareurl = new OptionString("use shareurl instead of copy shared files", "--shareurl")
42
43 # Use a custom title for the homepage.
44 var opt_custom_title = new OptionString("custom title for homepage", "--custom-title")
45
46 # Display a custom brand or logo in the documentation top menu.
47 var opt_custom_brand = new OptionString("custom link to external site", "--custom-brand")
48
49 # Display a custom introduction text before the projects overview.
50 var opt_custom_intro = new OptionString("custom intro text for homepage", "--custom-overview-text")
51 # Display a custom footer on each documentation page.
52 #
53 # Generally used to display the documentation or product version.
54 var opt_custom_footer = new OptionString("custom footer text", "--custom-footer-text")
55
56 # Piwik tracker URL.
57 #
58 # If you want to monitor your visitors.
59 var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: nitlanguage.org/piwik/)", "--piwik-tracker")
60
61 # Piwik tracker site id.
62 var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
63
64 # These options are not currently used in Nitdoc.
65
66 # FIXME redo the plugin
67 var opt_github_upstream = new OptionString("Git branch where edited commits will be pulled into (ex: user:repo:branch)", "--github-upstream")
68 # FIXME redo the plugin
69 var opt_github_base_sha1 = new OptionString("Git sha1 of base commit used to create pull request", "--github-base-sha1")
70 # FIXME redo the plugin
71 var opt_github_gitdir = new OptionString("Git working directory used to resolve path name (ex: /home/me/myproject/)", "--github-gitdir")
72
73 redef init do
74 super
75
76 option_context.add_option(
77 opt_source, opt_sharedir, opt_shareurl, opt_custom_title,
78 opt_custom_footer, opt_custom_intro, opt_custom_brand,
79 opt_github_upstream, opt_github_base_sha1, opt_github_gitdir,
80 opt_piwik_tracker, opt_piwik_site_id)
81 end
82
83 redef fun process_options(args) do
84 super
85 var upstream = opt_github_upstream
86 var base_sha = opt_github_base_sha1
87 var git_dir = opt_github_gitdir
88 var opts = [upstream.value, base_sha.value, git_dir.value]
89 if not opts.has_only(null) and opts.has(null) then
90 print "Option Error: options {upstream.names.first}, " +
91 "{base_sha.names.first} and {git_dir.names.first} " +
92 "are required to enable the GitHub plugin"
93 exit 1
94 end
95 end
96 end
97
98 # Render the Nitdoc as a HTML website.
99 class RenderHTMLPhase
100 super DocPhase
101
102 # Used to sort sidebar elements by name.
103 var name_sorter = new MEntityNameSorter
104
105 redef fun apply do
106 init_output_dir
107 for page in doc.pages do
108 page.render(self, doc).write_to_file("{ctx.output_dir.to_s}/{page.html_url}")
109 end
110 end
111
112 # Creates the output directory and imports assets files form `resources/`.
113 fun init_output_dir do
114 # create destination dir if it's necessary
115 var output_dir = ctx.output_dir
116 if not output_dir.file_exists then output_dir.mkdir
117 # locate share dir
118 var sharedir = ctx.opt_sharedir.value
119 if sharedir == null then
120 var dir = ctx.nit_dir
121 sharedir = dir/"share/nitdoc"
122 if not sharedir.file_exists then
123 print "Error: cannot locate nitdoc share files. Uses --sharedir or envvar NIT_DIR"
124 abort
125 end
126 end
127 # copy shared files
128 if ctx.opt_shareurl.value == null then
129 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/* {output_dir.to_s.escape_to_sh}/")
130 else
131 sys.system("cp -r -- {sharedir.to_s.escape_to_sh}/resources/ {output_dir.to_s.escape_to_sh}/resources/")
132 end
133
134 end
135
136 # A source link template for a given location
137 fun tpl_showsource(location: nullable Location): nullable String
138 do
139 if location == null then return null
140 var source = ctx.opt_source.value
141 if source == null then
142 var url = location.file.filename.simplify_path
143 return "<a target='_blank' title='Show source' href=\"{url.html_escape}\">View Source</a>"
144 end
145 # THIS IS JUST UGLY ! (but there is no replace yet)
146 var x = source.split_with("%f")
147 source = x.join(location.file.filename.simplify_path)
148 x = source.split_with("%l")
149 source = x.join(location.line_start.to_s)
150 x = source.split_with("%L")
151 source = x.join(location.line_end.to_s)
152 source = source.simplify_path
153 return "<a target='_blank' title='Show source' href=\"{source.to_s.html_escape}\">View Source</a>"
154 end
155 end
156
157 redef class DocPage
158
159 # Render the page as a html template.
160 private fun render(v: RenderHTMLPhase, doc: DocModel): Writable do
161 var shareurl = "."
162 if v.ctx.opt_shareurl.value != null then
163 shareurl = v.ctx.opt_shareurl.value.as(not null)
164 end
165
166 # init page options
167 self.shareurl = shareurl
168 self.footer = v.ctx.opt_custom_footer.value
169 self.body_attrs.add(new TagAttribute("data-bootstrap-share", shareurl))
170
171 # build page
172 init_title(v, doc)
173 init_sidebar(v, doc)
174 init_topmenu(v, doc)
175 init_content(v, doc)
176
177 # piwik tracking
178 var tracker_url = v.ctx.opt_piwik_tracker.value
179 var site_id = v.ctx.opt_piwik_site_id.value
180 if tracker_url != null and site_id != null then
181 self.scripts.add new TplPiwikScript(tracker_url, site_id)
182 end
183 return self
184 end
185
186 # FIXME diff hack
187 # all properties below are roughly copied from `doc_pages`
188
189 # Build page title string
190 fun init_title(v: RenderHTMLPhase, doc: DocModel) is abstract
191
192 # Build top menu template if any.
193 fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
194 topmenu = new DocTopMenu
195 var brand = v.ctx.opt_custom_brand.value
196 if brand != null then
197 var tpl = new Template
198 tpl.add "<span class='navbar-brand'>"
199 tpl.add brand
200 tpl.add "</span>"
201 topmenu.brand = tpl
202 end
203 var title = "Overview"
204 if v.ctx.opt_custom_title.value != null then
205 title = v.ctx.opt_custom_title.value.to_s
206 end
207 topmenu.add_li new ListItem(new Link("index.html", title))
208 topmenu.add_li new ListItem(new Link("search.html", "Index"))
209 topmenu.active_item = topmenu.items.first
210 end
211
212 # Build page sidebar if any.
213 fun init_sidebar(v: RenderHTMLPhase, doc: DocModel) do
214 sidebar = new TplSidebar
215 end
216
217 # Build page content template.
218 fun init_content(v: RenderHTMLPhase, doc: DocModel) do end
219 end
220
221 redef class OverviewPage
222 redef var html_url = "index.html"
223
224 redef fun init_title(v, doc) do
225 title = "Overview"
226 if v.ctx.opt_custom_title.value != null then
227 title = v.ctx.opt_custom_title.value.to_s
228 end
229 end
230
231 # TODO this should be done in StructurePhase.
232 redef fun init_content(v, doc) do
233 # intro text
234 var section = new TplSection.with_title("overview", title)
235 var article = new TplArticle("intro")
236 if v.ctx.opt_custom_intro.value != null then
237 article.content = v.ctx.opt_custom_intro.value.to_s
238 end
239 section.add_child article
240 # Projects list
241 var mprojects = doc.model.mprojects.to_a
242 var sorter = new MConcernRankSorter
243 sorter.sort mprojects
244 var ssection = new TplSection.with_title("projects", "Projects")
245 for mproject in mprojects do
246 var sarticle = mproject.tpl_article
247 sarticle.subtitle = mproject.html_declaration
248 sarticle.content = mproject.tpl_definition
249 var comment = mproject.html_short_comment
250 if comment != null then
251 sarticle.content = comment
252 end
253 ssection.add_child sarticle
254 end
255 section.add_child ssection
256 self.add_section section
257 end
258
259 redef fun init_sidebar(v, doc) do sidebar = new TplSidebar
260 end
261
262 redef class SearchPage
263 redef var html_url = "search.html"
264 redef fun init_title(v, doc) do title = "Index"
265
266 redef fun init_topmenu(v, doc) do
267 super
268 topmenu.active_item = topmenu.items.last
269 end
270
271 redef fun init_sidebar(v, doc) do end
272
273 # TODO this should be done in StructurePhase.
274 redef fun init_content(v, doc) do
275 var tpl = new TplSearchPage("search_all")
276 var section = new TplSection("search")
277 # title
278 tpl.title = "Index"
279 # modules list
280 for mmodule in modules_list(v, doc) do
281 tpl.modules.add mmodule.html_link
282 end
283 # classes list
284 for mclass in classes_list(v, doc) do
285 tpl.classes.add mclass.html_link
286 end
287 # properties list
288 for mproperty in mprops_list(v, doc) do
289 var m = new Template
290 m.add mproperty.intro.html_link
291 m.add " ("
292 m.add mproperty.intro.mclassdef.mclass.html_link
293 m.add ")"
294 tpl.props.add m
295 end
296 section.add_child tpl
297 self.add_section section
298 end
299
300 # Extract mmodule list to display (sorted by name)
301 private fun modules_list(v: RenderHTMLPhase, doc: DocModel): Array[MModule] do
302 var sorted = new Array[MModule]
303 for mmodule in doc.model.mmodule_importation_hierarchy do
304 if mmodule.is_fictive or mmodule.is_test_suite then continue
305 sorted.add mmodule
306 end
307 v.name_sorter.sort(sorted)
308 return sorted
309 end
310
311 # Extract mclass list to display (sorted by name)
312 private fun classes_list(v: RenderHTMLPhase, doc: DocModel): Array[MClass] do
313 var sorted = doc.mclasses.to_a
314 v.name_sorter.sort(sorted)
315 return sorted
316 end
317
318 # Extract mproperty list to display (sorted by name)
319 private fun mprops_list(v: RenderHTMLPhase, doc: DocModel): Array[MProperty] do
320 var sorted = doc.mproperties.to_a
321 v.name_sorter.sort(sorted)
322 return sorted
323 end
324 end
325
326 redef class MEntityPage
327 redef var html_url is lazy do return mentity.nitdoc_url
328 redef fun init_title(v, doc) do title = mentity.html_name
329 redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
330 end
331
332 # FIXME all clases below are roughly copied from `doc_pages` and adapted to new
333 # doc phases. This is to preserve the compatibility with the current
334 # `doc_templates` module.
335
336 redef class MGroupPage
337 redef fun init_topmenu(v, doc) do
338 super
339 var mproject = mentity.mproject
340 if not mentity.is_root then
341 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
342 end
343 topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
344 topmenu.active_item = topmenu.items.last
345 end
346
347 redef fun init_sidebar(v, doc) do
348 super
349 var mclasses = new HashSet[MClass]
350 mclasses.add_all intros
351 mclasses.add_all redefs
352 if mclasses.is_empty then return
353 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
354
355 var sorted = mclasses.to_a
356 v.name_sorter.sort(sorted)
357 for mclass in sorted do
358 list.add_li tpl_sidebar_item(mclass)
359 end
360 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
361 end
362
363 private fun tpl_sidebar_item(def: MClass): TplListItem do
364 var classes = def.intro.tpl_css_classes.to_a
365 if intros.has(def) then
366 classes.add "intro"
367 else
368 classes.add "redef"
369 end
370 var lnk = new Template
371 lnk.add new TplLabel.with_classes(classes)
372 lnk.add def.html_link
373 return new TplListItem.with_content(lnk)
374 end
375 end
376
377 redef class MModulePage
378 redef fun init_topmenu(v, doc) do
379 super
380 var mproject = mentity.mproject
381 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
382 topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
383 topmenu.active_item = topmenu.items.last
384 end
385
386 # Class list to display in sidebar
387 redef fun init_sidebar(v, doc) do
388 # TODO filter here?
389 super
390 var mclasses = new HashSet[MClass]
391 mclasses.add_all mentity.filter_intro_mclasses(v.ctx.min_visibility)
392 mclasses.add_all mentity.filter_redef_mclasses(v.ctx.min_visibility)
393 if mclasses.is_empty then return
394 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
395
396 var sorted = mclasses.to_a
397 v.name_sorter.sort(sorted)
398 for mclass in sorted do
399 list.add_li tpl_sidebar_item(mclass)
400 end
401 sidebar.boxes.add new TplSideBox.with_content("All classes", list)
402 end
403
404 private fun tpl_sidebar_item(def: MClass): TplListItem do
405 var classes = def.intro.tpl_css_classes.to_a
406 if def.intro_mmodule == self.mentity then
407 classes.add "intro"
408 else
409 classes.add "redef"
410 end
411 var lnk = new Template
412 lnk.add new TplLabel.with_classes(classes)
413 lnk.add def.html_link
414 return new TplListItem.with_content(lnk)
415 end
416 end
417
418 redef class MClassPage
419
420 redef fun init_topmenu(v, doc) do
421 super
422 var mproject = mentity.intro_mmodule.mgroup.mproject
423 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
424 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
425 topmenu.active_item = topmenu.items.last
426 end
427
428 redef fun init_sidebar(v, doc) do
429 super
430 var by_kind = new PropertiesByKind.with_elements(mclass_inherited_mprops(v, doc))
431 var summary = new TplList.with_classes(["list-unstyled"])
432
433 by_kind.sort_groups(v.name_sorter)
434 for g in by_kind.groups do tpl_sidebar_list(g, summary)
435 sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
436 end
437
438 private fun tpl_sidebar_list(mprops: PropertyGroup[MProperty], summary: TplList) do
439 if mprops.is_empty then return
440 var entry = new TplListItem.with_content(mprops.title)
441 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
442 for mprop in mprops do
443 list.add_li tpl_sidebar_item(mprop)
444 end
445 entry.append list
446 summary.elts.add entry
447 end
448
449 private fun tpl_sidebar_item(mprop: MProperty): TplListItem do
450 var classes = mprop.intro.tpl_css_classes.to_a
451 if not mprop_is_local(mprop) then
452 classes.add "inherit"
453 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
454 var def_url = "{cls_url}#{mprop.nitdoc_id}"
455 var lnk = new TplLink(def_url, mprop.html_name)
456 var mdoc = mprop.intro.mdoc_or_fallback
457 if mdoc != null then lnk.title = mdoc.short_comment
458 var item = new Template
459 item.add new TplLabel.with_classes(classes)
460 item.add lnk
461 return new TplListItem.with_content(item)
462 end
463 if mpropdefs.has(mprop.intro) then
464 classes.add "intro"
465 else
466 classes.add "redef"
467 end
468 var lnk = new Template
469 lnk.add new TplLabel.with_classes(classes)
470 lnk.add mprop.html_link_to_anchor
471 return new TplListItem.with_content(lnk)
472 end
473
474 private fun mclass_inherited_mprops(v: RenderHTMLPhase, doc: DocModel): Set[MProperty] do
475 var res = new HashSet[MProperty]
476 var local = mentity.local_mproperties(v.ctx.min_visibility)
477 for mprop in mentity.inherited_mproperties(doc.mainmodule, v.ctx.min_visibility) do
478 if local.has(mprop) then continue
479 #if mprop isa MMethod and mprop.is_init then continue
480 if mprop.intro.mclassdef.mclass.name == "Object" and
481 (mprop.visibility == protected_visibility or
482 mprop.intro.mclassdef.mmodule.name != "kernel") then continue
483 res.add mprop
484 end
485 res.add_all local
486 return res
487 end
488
489 private fun mprop_is_local(mprop: MProperty): Bool do
490 for mpropdef in mprop.mpropdefs do
491 if self.mpropdefs.has(mpropdef) then return true
492 end
493 return false
494 end
495 end
496
497 redef class MPropertyPage
498 redef fun init_title(v, doc) do
499 title = "{mentity.html_name}{mentity.html_short_signature.write_to_string}"
500 end
501
502 redef fun init_topmenu(v, doc) do
503 super
504 var mmodule = mentity.intro_mclassdef.mmodule
505 var mproject = mmodule.mgroup.mproject
506 var mclass = mentity.intro_mclassdef.mclass
507 topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
508 topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
509 topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
510 topmenu.active_item = topmenu.items.last
511 end
512 end
513
514 redef class DocComposite
515 # Render this DocComposite as HTML.
516 #
517 # FIXME needed to maintain TplSection compatibility.
518 fun render(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage, parent: TplSectionElt) is abstract
519 end
520
521 redef class DocRoot
522
523 # Start the rendering from root.
524 #
525 # FIXME needed to maintain TplSection compatibility.
526 fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
527 var section = new TplSection("top")
528 var mentity = page.mentity
529 section.title = mentity.html_name
530 section.subtitle = mentity.html_declaration
531 # FIXME ugly hack to avoid diff
532 if mentity isa MGroup and mentity.is_root then
533 section.title = mentity.mproject.html_name
534 section.subtitle = mentity.mproject.html_declaration
535 else if mentity isa MProperty then
536 section.title = "{mentity.html_name}{mentity.intro.html_signature.write_to_string}"
537 section.subtitle = mentity.html_namespace
538 section.summary_title = mentity.html_name
539 end
540 render(v, doc, page, section)
541 return section
542 end
543
544 redef fun render(v, doc, page, parent) do
545 for child in children do
546 child.render(v, doc, page, parent)
547 end
548 end
549 end
550
551 redef class ConcernSection
552 redef fun render(v, doc, page, parent) do
553 var section = new TplSection(mentity.nitdoc_id)
554 var mentity = self.mentity
555 # FIXME hideous hacks to avoid diff
556 if page.mentity isa MModule and mentity isa MModule then
557 render_concern_mmodule(page, section, mentity)
558 else if page.mentity isa MClass and mentity isa MModule then
559 render_concern_other(page, section, mentity)
560 else if page.mentity isa MProperty and mentity isa MModule then
561 render_concern_other(page, section, mentity)
562 end
563 for child in children do
564 child.render(v, doc, page, section)
565 end
566 parent.add_child section
567 end
568
569 private fun render_concern_mmodule(page: MEntityPage, section: TplSection, mmodule: MModule) do
570 var title = new Template
571 if mmodule == page.mentity then
572 title.add "in "
573 section.summary_title = "in {mmodule.html_name}"
574 else
575 title.add "from "
576 section.summary_title = "from {mmodule.html_name}"
577 end
578 title.add mmodule.html_namespace
579 section.title = title
580 end
581
582 private fun render_concern_other(page: MEntityPage, section: TplSection, mmodule: MModule) do
583 var title = new Template
584 title.add "in "
585 title.add mmodule.html_namespace
586 section.title = title
587 section.summary_title = "in {mmodule.html_name}"
588 end
589 end
590
591 redef class MEntitySection
592 redef fun render(v, doc, page, parent) do
593 for child in children do child.render(v, doc, page, parent)
594 end
595 end
596
597 redef class IntroArticle
598 redef fun render(v, doc, page, parent) do
599 var article = new TplArticle("intro")
600 var mentity = self.mentity
601 if mentity isa MModule then
602 article.source_link = v.tpl_showsource(mentity.location)
603 else if mentity isa MClassDef then
604 article.source_link = v.tpl_showsource(mentity.location)
605 else if mentity isa MPropDef then
606 article.source_link = v.tpl_showsource(mentity.location)
607 end
608 # article.subtitle = mentity.html_declaration
609 # FIXME diff hack
610 if mentity isa MProperty then
611 # intro title
612 var ns = mentity.intro.mclassdef.mmodule.html_namespace
613 var section = new TplSection("intro")
614 var title = new Template
615 title.add "Introduction in "
616 title.add ns
617 section.title = title
618 section.summary_title = "Introduction"
619 var intro = mentity.intro.tpl_article
620 intro.source_link = v.tpl_showsource(mentity.intro.location)
621 section.add_child intro
622 parent.add_child section
623 else
624 article.content = mentity.tpl_definition
625 parent.add_child article
626 end
627 end
628 end
629
630 redef class ConcernsArticle
631 redef fun render(v, doc, page, parent) do
632 # FIXME diff hack
633 var title = "concerns"
634 if page.mentity isa MProperty then title = "Concerns"
635 parent.add_child new TplArticle.
636 with_content(title, "Concerns", concerns.to_tpl)
637 end
638 end
639
640 redef class DefinitionArticle
641 redef fun render(v, doc, page, parent) do
642 var article: TplArticle
643 var mentity = self.mentity
644 # FIXME hideous hacks...
645 if mentity isa MModule then
646 article = mentity.tpl_article
647 article.subtitle = mentity.html_declaration
648 article.content = mentity.tpl_definition
649 else if mentity isa MClass then
650 article = make_mclass_article(v, page)
651 else if mentity isa MClassDef then
652 article = make_mclassdef_article(v, page)
653 article.source_link = v.tpl_showsource(mentity.location)
654 else if mentity isa MPropDef and page.mentity isa MClass then
655 article = make_mpropdef_article(v, doc, page)
656 else
657 article = mentity.tpl_article
658 article.subtitle = mentity.html_declaration
659 if mentity isa MPropDef then
660 article.source_link = v.tpl_showsource(mentity.location)
661 end
662 end
663 for child in children do
664 child.render(v, doc, page, article)
665 end
666 parent.add_child article
667 end
668
669 # FIXME avoid diff while preserving TplArticle compatibility.
670
671 private fun make_mclass_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
672 var article = mentity.tpl_article
673 article.subtitle = mentity.html_namespace
674 article.content = null
675 return article
676 end
677
678 private fun make_mclassdef_article(v: RenderHTMLPhase, page: MEntityPage): TplArticle do
679 var mclassdef = mentity.as(MClassDef)
680 var article = mentity.tpl_article
681 if mclassdef.is_intro and mclassdef.mmodule != page.mentity then
682 article = mentity.tpl_short_article
683 end
684 var title = new Template
685 title.add "in "
686 title.add mclassdef.mmodule.html_namespace
687 article.subtitle = title
688 return article
689 end
690
691 private fun make_mpropdef_article(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplArticle
692 do
693 var mpropdef = mentity.as(MPropDef)
694 var mprop = mpropdef.mproperty
695 var article = new TplArticle(mprop.nitdoc_id)
696 var title = new Template
697 title.add mprop.tpl_icon
698 title.add "<span id='{mpropdef.nitdoc_id}'></span>"
699 if mpropdef.is_intro then
700 title.add mprop.html_link
701 title.add mprop.intro.html_signature
702 else
703 var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
704 var def_url = "{cls_url}#{mprop.nitdoc_id}"
705 var lnk = new TplLink.with_title(def_url, mprop.html_name,
706 "Go to introduction")
707 title.add "redef "
708 title.add lnk
709 end
710 article.title = title
711 article.title_classes.add "signature"
712 article.summary_title = "{mprop.html_name}"
713 article.subtitle = mpropdef.html_namespace
714 var comment = mpropdef.html_comment
715 if comment != null then
716 article.content = comment
717 end
718 # TODO move in its own phase? let's see after doc_template refactoring.
719 # Add linearization
720 var all_defs = new HashSet[MPropDef]
721 for local_def in local_defs(page.as(MClassPage), mprop) do
722 all_defs.add local_def
723 var smpropdef = local_def
724 while not smpropdef.is_intro do
725 smpropdef = smpropdef.lookup_next_definition(
726 doc.mainmodule, smpropdef.mclassdef.bound_mtype)
727 all_defs.add smpropdef
728 end
729 end
730 var lin = all_defs.to_a
731 doc.mainmodule.linearize_mpropdefs(lin)
732 if lin.length > 1 then
733 var lin_article = new TplArticle("{mpropdef.nitdoc_id}.lin")
734 lin_article.title = "Inheritance"
735 var lst = new TplList.with_classes(["list-unstyled", "list-labeled"])
736 for smpropdef in lin do
737 lst.add_li smpropdef.tpl_inheritance_item
738 end
739 lin_article.content = lst
740 article.add_child lin_article
741 end
742 return article
743 end
744
745 # Filter `page.mpropdefs` for this `mpropertie`.
746 #
747 # FIXME compatability with current templates.
748 private fun local_defs(page: MClassPage, mproperty: MProperty): HashSet[MPropDef] do
749 var mpropdefs = new HashSet[MPropDef]
750 for mpropdef in page.mpropdefs do
751 if mpropdef.mproperty == mproperty then
752 mpropdefs.add mpropdef
753 end
754 end
755 return mpropdefs
756 end
757 end
758
759 redef class IntrosRedefsListArticle
760 redef fun render(v, doc, page, parent) do
761 if mentities.is_empty then return
762 var title = list_title
763 # FIXME diff hack
764 var id = "intros"
765 if title == "Redefines" then id = "redefs"
766 var article = new TplArticle.with_title("{mentity.nitdoc_id}.{id}", title)
767 var list = new TplList.with_classes(["list-unstyled", "list-labeled"])
768 for mentity in mentities do
769 list.add_li mentity.tpl_list_item
770 end
771 article.content = list
772 parent.add_child article
773 end
774 end
775
776 # FIXME compatibility with doc_templates.
777 redef class ImportationListSection
778 redef fun render(v, doc, page, parent) do
779 var section = new TplSection.with_title("dependencies", "Dependencies")
780 for child in children do
781 child.render(v, doc, page, section)
782 end
783 parent.add_child section
784 end
785 end
786
787 # FIXME compatibility with doc_templates.
788 redef class InheritanceListSection
789 redef fun render(v, doc, page, parent) do
790 var section = new TplSection.with_title("inheritance", "Inheritance")
791 for child in children do
792 child.render(v, doc, page, section)
793 end
794 parent.add_child section
795 end
796 end
797
798 # FIXME compatibility with doc_templates.
799 redef class HierarchyListArticle
800 redef fun render(v, doc, page, parent) do
801 if mentities.is_empty then return
802 var title = list_title
803 var id = list_title.to_lower
804 var article = new TplArticle.with_title(id, title)
805 var list = new TplList.with_classes(["list-unstyled", "list-definition"])
806 for mentity in mentities do
807 list.elts.add mentity.tpl_list_item
808 end
809 article.content = list
810 parent.add_child article
811 end
812 end
813
814 redef class GraphArticle
815 redef fun render(v, doc, page, parent) do
816 var output_dir = v.ctx.output_dir
817 var path = output_dir / id
818 var path_sh = path.escape_to_sh
819 var file = new FileWriter.open("{path}.dot")
820 file.write(dot)
821 file.close
822 sys.system("\{ test -f {path_sh}.png && test -f {path_sh}.s.dot && diff -- {path_sh}.dot {path_sh}.s.dot >/dev/null 2>&1 ; \} || \{ cp -- {path_sh}.dot {path_sh}.s.dot && dot -Tpng -o{path_sh}.png -Tcmapx -o{path_sh}.map {path_sh}.s.dot ; \}")
823 var fmap = new FileReader.open("{path}.map")
824 var map = fmap.read_all
825 fmap.close
826
827 var article = new TplArticle("graph")
828 var alt = ""
829 # FIXME diff hack
830 # if title != null then
831 # article.title = title
832 # alt = "alt='{title.html_escape}'"
833 # end
834 article.css_classes.add "text-center"
835 var content = new Template
836 var name_html = id.html_escape
837 content.add "<img src='{name_html}.png' usemap='#{name_html}' style='margin:auto' {alt}/>"
838 content.add map
839 article.content = content
840 parent.add_child article
841 end
842 end
843
844 redef class Location
845 # Github url based on this location
846 fun github(gitdir: String): String do
847 var base_dir = getcwd.join_path(gitdir).simplify_path
848 var file_loc = getcwd.join_path(file.filename).simplify_path
849 var gith_loc = file_loc.substring(base_dir.length + 1, file_loc.length)
850 return "{gith_loc}:{line_start},{column_start}--{line_end},{column_end}"
851 end
852 end
853
854 redef class MEntity
855 # A template article that briefly describe the entity
856 fun tpl_short_article: TplArticle do
857 var tpl = tpl_article
858 var comment = html_short_comment
859 if comment != null then
860 tpl.content = comment
861 end
862 return tpl
863 end
864
865 # A template article that describe the entity
866 fun tpl_article: TplArticle do
867 var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
868 tpl.title_classes.add "signature"
869 tpl.subtitle = html_namespace
870 tpl.summary_title = html_name
871 return tpl
872 end
873
874 # A template definition of the mentity
875 # include name, sysnopsys, comment and namespace
876 fun tpl_definition: TplDefinition is abstract
877
878 # A li element that can go in a list
879 fun tpl_list_item: TplListItem do
880 var lnk = new Template
881 lnk.add new TplLabel.with_classes(tpl_css_classes)
882 lnk.add html_link
883 var comment = html_short_comment
884 if comment != null then
885 lnk.add ": "
886 lnk.add comment
887 end
888 return new TplListItem.with_content(lnk)
889 end
890
891 var tpl_css_classes = new Array[String]
892
893 # Box title for this mentity
894 fun tpl_title: Template do
895 var title = new Template
896 title.add tpl_icon
897 title.add html_namespace
898 return title
899 end
900
901 # Icon that will be displayed before the title
902 fun tpl_icon: TplIcon do
903 var icon = new TplIcon.with_icon("tag")
904 icon.css_classes.add_all(tpl_css_classes)
905 return icon
906 end
907 end
908
909 redef class MConcern
910 # Return a li element for `self` that can be displayed in a concern list
911 private fun tpl_concern_item: TplListItem do
912 var lnk = new Template
913 lnk.add html_link_to_anchor
914 var comment = html_short_comment
915 if comment != null then
916 lnk.add ": "
917 lnk.add comment
918 end
919 return new TplListItem.with_content(lnk)
920 end
921 end
922
923 redef class MProject
924 redef fun tpl_definition do
925 var tpl = new TplDefinition
926 var comment = html_comment
927 if comment != null then
928 tpl.comment = comment
929 end
930 return tpl
931 end
932
933 redef fun tpl_css_classes do return ["public"]
934 end
935
936 redef class MGroup
937 redef fun tpl_definition do
938 var tpl = new TplDefinition
939 var comment = html_comment
940 if comment != null then
941 tpl.comment = comment
942 end
943 return tpl
944 end
945 end
946
947 redef class MModule
948 redef fun tpl_definition do
949 var tpl = new TplClassDefinition
950 var comment = html_comment
951 if comment != null then
952 tpl.comment = comment
953 end
954 return tpl
955 end
956
957 redef fun tpl_css_classes do return ["public"]
958 end
959
960 redef class MClass
961 redef fun tpl_definition do return intro.tpl_definition
962
963 redef fun tpl_title do
964 var title = new Template
965 title.add tpl_icon
966 title.add html_link
967 return title
968 end
969
970 redef fun tpl_icon do return intro.tpl_icon
971 redef fun tpl_css_classes do return intro.tpl_css_classes
972 end
973
974 redef class MClassDef
975 redef fun tpl_article do
976 var tpl = new TplArticle(nitdoc_id)
977 tpl.summary_title = "in {mmodule.html_name}"
978 tpl.title = html_declaration
979 tpl.title_classes.add "signature"
980 var title = new Template
981 title.add "in "
982 title.add mmodule.html_namespace
983 tpl.subtitle = title
984 var comment = html_comment
985 if comment != null then
986 tpl.content = comment
987 end
988 return tpl
989 end
990
991 redef fun tpl_title do
992 var title = new Template
993 title.add tpl_icon
994 title.add html_link
995 return title
996 end
997
998 redef fun tpl_definition do
999 var tpl = new TplClassDefinition
1000 var comment = html_comment
1001 if comment != null then
1002 tpl.comment = comment
1003 end
1004 return tpl
1005 end
1006
1007 redef fun tpl_css_classes do
1008 var set = new HashSet[String]
1009 if is_intro then set.add "intro"
1010 for m in mclass.intro.modifiers do set.add m.to_cmangle
1011 for m in modifiers do set.add m.to_cmangle
1012 return set.to_a
1013 end
1014
1015 fun tpl_modifiers: Template do
1016 var tpl = new Template
1017 for modifier in modifiers do
1018 if modifier == "public" then continue
1019 tpl.add "{modifier.html_escape} "
1020 end
1021 return tpl
1022 end
1023 end
1024
1025 redef class MProperty
1026 redef fun tpl_title do return intro.tpl_title
1027 redef fun tpl_icon do return intro.tpl_icon
1028 redef fun tpl_css_classes do return intro.tpl_css_classes
1029 end
1030
1031 redef class MPropDef
1032 redef fun tpl_article do
1033 var tpl = new TplArticle(nitdoc_id)
1034 tpl.summary_title = "in {mclassdef.html_name}"
1035 var title = new Template
1036 title.add "in "
1037 title.add mclassdef.html_link
1038 tpl.title = title
1039 tpl.subtitle = html_declaration
1040 var comment = html_comment
1041 if comment != null then
1042 tpl.content = comment
1043 end
1044 return tpl
1045 end
1046
1047 redef fun tpl_definition do
1048 var tpl = new TplDefinition
1049 var comment = html_comment
1050 if comment != null then
1051 tpl.comment = comment
1052 end
1053 return tpl
1054 end
1055
1056 redef fun tpl_css_classes do
1057 var set = new HashSet[String]
1058 if is_intro then set.add "intro"
1059 for m in mproperty.intro.modifiers do set.add m.to_cmangle
1060 for m in modifiers do set.add m.to_cmangle
1061 return set.to_a
1062 end
1063
1064 fun tpl_modifiers: Template do
1065 var tpl = new Template
1066 for modifier in modifiers do
1067 if modifier == "public" then continue
1068 tpl.add "{modifier.html_escape} "
1069 end
1070 return tpl
1071 end
1072
1073 redef fun tpl_list_item do
1074 var lnk = new Template
1075 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1076 var atext = html_link.text
1077 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1078 var atitle = html_link.title
1079 var anchor = new Link.with_title(ahref, atext, atitle)
1080 lnk.add anchor
1081 var comment = html_short_comment
1082 if comment != null then
1083 lnk.add ": "
1084 lnk.add comment
1085 end
1086 return new TplListItem.with_content(lnk)
1087 end
1088
1089 fun tpl_inheritance_item: TplListItem do
1090 var lnk = new Template
1091 lnk.add new TplLabel.with_classes(tpl_css_classes.to_a)
1092 lnk.add mclassdef.mmodule.html_namespace
1093 lnk.add "::"
1094 var atext = mclassdef.html_link.text
1095 var ahref = "{mclassdef.mclass.nitdoc_url}#{mproperty.nitdoc_id}"
1096 var atitle = mclassdef.html_link.title
1097 var anchor = new Link.with_title(ahref, atext, atitle)
1098 lnk.add anchor
1099 var comment = html_short_comment
1100 if comment != null then
1101 lnk.add ": "
1102 lnk.add comment
1103 end
1104 var li = new TplListItem.with_content(lnk)
1105 li.css_classes.add "signature"
1106 return li
1107 end
1108 end
1109
1110 redef class ConcernsTree
1111
1112 private var seen = new HashSet[MConcern]
1113
1114 redef fun add(p, e) do
1115 if seen.has(e) then return
1116 seen.add e
1117 super(p, e)
1118 end
1119
1120 fun to_tpl: TplList do
1121 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1122 for r in roots do
1123 var li = r.tpl_concern_item
1124 lst.add_li li
1125 build_list(r, li)
1126 end
1127 return lst
1128 end
1129
1130 private fun build_list(e: MConcern, li: TplListItem) do
1131 if not sub.has_key(e) then return
1132 var subs = sub[e]
1133 var lst = new TplList.with_classes(["list-unstyled", "list-definition"])
1134 for e2 in subs do
1135 if e2 isa MGroup and e2.is_root then
1136 build_list(e2, li)
1137 else
1138 var sli = e2.tpl_concern_item
1139 lst.add_li sli
1140 build_list(e2, sli)
1141 end
1142 end
1143 li.append lst
1144 end
1145 end
1146
1147 redef class MInnerClassDef
1148 redef fun tpl_definition do
1149 var tpl = new TplClassDefinition
1150 var comment = html_comment
1151 if comment != null then
1152 tpl.comment = comment
1153 end
1154 return tpl
1155 end
1156 end