src/doc/commands: move `render_code` to clients modules
[nit.git] / src / doc / static / static_cards.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 # Cards templates for the static documentation
16 module static_cards
17
18 import doc::commands::commands_graph
19 import doc::commands::commands_catalog
20 import doc::commands::commands_docdown
21 import templates_html
22
23 # A card that can be rendered to HTML
24 #
25 # Basically, these cards are templates with additionnal data and behavior.
26 abstract class StaticCard
27 super Template
28
29 # Card title
30 var title: String is writable
31
32 # Card id
33 var id: String is writable
34 end
35
36 # A list of cards
37 class CardList
38 super StaticCard
39
40 # Cards contained in this list
41 var cards = new Array[StaticCard] is writable
42
43 redef fun rendering do
44 addn "<div id='{id}' class='card-list'>"
45 for card in cards do
46 addn card
47 end
48 addn "</div>"
49 end
50 end
51
52 # Doc elements
53
54 # A card that display custom text data
55 class CardText
56 super StaticCard
57 autoinit(content)
58
59 # Custom content from options
60 var content: nullable String is writable
61
62 redef var id = "home"
63 redef var title = "Home"
64
65 redef fun rendering do
66 var content = self.content
67 if content == null then return
68 addn "<div>"
69 addn content
70 addn "</div>"
71 addn "<hr/>"
72 end
73 end
74
75 # A heading section
76 #
77 # It displays an heading at a specific level from 1 to 6.
78 class CardSection
79 super StaticCard
80 autoinit(level, title, subtitle)
81
82 # Section heading level
83 var level: Int is writable
84
85 # Section subtitle
86 var subtitle: nullable String is writable
87
88 redef var id = title.to_cmangle is lazy
89
90 redef fun rendering do
91 addn "<h{level} id='{id}'>{title}</h{level}>"
92 end
93 end
94
95 # A page header
96 class CardPageHeader
97 super CardSection
98 autoinit(title, subtitle)
99
100 redef var level = 2
101
102 redef fun rendering do
103 addn "<div class='page-header'>"
104 super
105 var subtitle = self.subtitle
106 if subtitle != null then
107 addn "<p class='text-muted'>"
108 addn subtitle
109 addn "</p>"
110 end
111 addn "</div>"
112 end
113 end
114
115 # A card that displays a summary of a list of cards
116 class CardSummary
117 super CardList
118 autoinit(no_title)
119
120 redef var id = "summary"
121 redef var title = "Summary"
122
123 # Show the summary title
124 var no_title: Bool = false is optional, writable
125
126 redef fun rendering do
127 if not no_title then
128 addn "<h4>Summary</h4>"
129 end
130 addn "<div class='summary'>"
131 addn " <ul class='list-unstyled'>"
132 var sections = new Array[CardSection]
133 for card in cards do
134 if card isa CardSection then
135 while sections.not_empty and sections.last.level >= card.level do
136 sections.pop
137 end
138 sections.add card
139 end
140 var level = if sections.is_empty then 1 else sections.last.level
141 if not card isa CardSection then level += 1
142 addn "<li><a href='#{card.id}'><h{level}>{card.title}</h{level}></a></li>"
143 end
144 addn " </ul>"
145 addn "</div>"
146 end
147 end
148
149 # A card that displays the summary of a Markdown document
150 class CardMdSummary
151 super CardMDoc
152 autoinit(md_processor, headlines)
153
154 # Markdown processor used to extract and render the content
155 var md_processor: MarkdownProcessor is writable
156
157 # Headlines found in the document
158 var headlines: ArrayMap[String, HeadLine] is writable
159
160 redef var id = "summary"
161 redef var title = "Summary"
162
163 redef fun rendering do
164 addn "<h4>Summary</h4>"
165 addn "<div class='summary'>"
166 addn " <ul class='list-unstyled'>"
167 for id, headline in headlines do
168 var level = headline.level
169 var title = md_processor.process(headline.title)
170 addn "<li><a href='#{id}'><h{level}>{title}</h{level}></a></li>"
171 end
172 addn " </ul>"
173 addn "</div>"
174 end
175 end
176
177 # MEntity related cards
178
179 # A card about a mentity
180 #
181 # It displays the documentation about the model entity.
182 class CardMEntity
183 super StaticCard
184 autoinit(mentity, full_doc)
185
186 # MEntity displayed in this card
187 var mentity: MEntity is writable
188
189 # Render the mentity full documentation?
190 var full_doc = false is optional, writable
191
192 redef var id = mentity.html_id is lazy
193 redef var title = mentity.html_name is lazy
194
195 redef fun rendering do
196 addn """
197 <div id='{{{id}}}' class='card'>
198 <div class='card-left text-center'>
199 {{{mentity.html_icon.write_to_string}}}
200 </div>
201 <div class='card-body'>
202 <h5 class='card-heading'>
203 {{{mentity.html_declaration.write_to_string}}}
204 </h5>
205 <p><small>{{{mentity.html_namespace.write_to_string}}}</small></p>"""
206 var mdoc = mentity.mdoc_or_fallback
207 if mdoc != null then
208 if full_doc then
209 addn mdoc.html_documentation
210 else
211 addn mdoc.html_synopsis
212 end
213 end
214 addn """
215 </div>
216 </div>"""
217 end
218 end
219
220 # A card that displays the content of a MDoc
221 class CardMDoc
222 super CardMEntity
223 autoinit(mentity, mdoc, full_doc)
224
225 # MDoc to display in this card
226 var mdoc: nullable MDoc is writable
227
228 redef fun rendering do
229 var mdoc = self.mdoc
230 if mdoc == null then return
231 addn "<div id='{id}' class='card'>"
232 addn " <div class='card-body nitdoc'>"
233 addn mdoc.html_documentation
234 addn " </div>"
235 addn "</div>"
236 end
237 end
238
239 # A card about the inheritance of a MEntity
240 class CardInheritance
241 super CardMEntity
242
243 # Ancestors list
244 var ancestors: nullable Array[MEntity] is writable
245
246 # Parents list
247 var parents: nullable Array[MEntity] is writable
248
249 # Children list
250 var children: nullable Array[MEntity] is writable
251
252 # Descendants list
253 var descendants: nullable Array[MEntity] is writable
254
255 redef var id = "inh_{super}" is lazy
256 redef var title = "Inheritance" is lazy
257
258 redef fun rendering do
259 var ancestors = self.ancestors
260 var descendants = self.descendants
261 if ancestors == null and parents == null and
262 children == null and descendants == null then return
263
264 addn "<div id='{id}' class='card'>"
265 addn " <div class='card-body'>"
266 if ancestors != null and ancestors.length <= 10 then
267 render_list("Ancestors", ancestors)
268 else
269 render_list("Parents", parents)
270 end
271 if descendants != null and descendants.length <= 10 then
272 render_list("Descendants", descendants)
273 else
274 render_list("Children", children)
275 end
276 addn " </div>"
277 addn "</div>"
278 end
279
280 private fun render_list(title: String, mentities: nullable Array[MEntity]) do
281 if mentities == null or mentities.is_empty then return
282 addn "<h4 id='{id}'>{title}</h4>"
283 addn "<ul class='list-unstyled'>"
284 for mentity in mentities do
285 addn html_list_item(mentity)
286 end
287 addn "</ul>"
288 end
289
290 private fun html_list_item(mentity: MEntity): ListItem do
291 var tpl = new Template
292 tpl.add mentity.html_namespace
293 var comment = mentity.mdoc_or_fallback
294 if comment != null then
295 tpl.add ": "
296 tpl.add comment.html_synopsis
297 end
298 return new ListItem(tpl)
299 end
300 end
301
302 # A card about the linearization of a MEntity
303 class CardLinearizationList
304 super CardMEntity
305
306 # Linearization cards contained in this list
307 var cards = new Array[CardLinearizationDef] is writable
308
309 redef var id = "lin_{super}" is lazy
310 redef var title = "Linearization" is lazy
311
312 redef fun rendering do
313 if cards.is_empty then return
314
315 addn "<div id='{id}'>"
316 for card in cards do
317 addn card
318 if card == cards.last then break
319 addn "<h4 class='text-muted text-center'>"
320 addn " <span class='glyphicon glyphicon-chevron-up'></span>"
321 addn "</h4>"
322 end
323 addn "</div>"
324 end
325 end
326
327 # A card about a definition in a linearization list
328 class CardLinearizationDef
329 super CardCode
330
331 # Is this card displayed by default?
332 var is_active: Bool = false is optional, writable
333
334 # Link to external code repository
335 #
336 # Used if `node` is null
337 var url: nullable String = null is optional, writable
338
339 redef var id = "def_{super}" is lazy
340 redef var title = mentity.full_name is lazy
341
342 redef fun rendering do
343 var url = self.url
344
345 var cin = if is_active then "in" else ""
346 var active = if is_active then "active" else ""
347 addn """
348 <div class='card {{{active}}}' id='{{{id}}}'>
349 <div class='card-body'>
350 <h5>
351 {{{mentity.html_icon.write_to_string}}}
352 {{{mentity.html_namespace.write_to_string}}}"""
353 if node != null then
354 addn """
355 <div class='btn-bar'>
356 <button class='btn btn-link' data-toggle='collapse'
357 data-target='#{{{mentity.html_id}}}'>
358 <span class='glyphicon glyphicon-console' title='Show code' />
359 </button>
360 </div>"""
361 else if url != null then
362 addn """
363 <div class='btn-bar'>
364 <a class='btn btn-link' href='{{{url}}}'>
365 <span class='glyphicon glyphicon-console' title='Show code' />
366 </a>
367 </div>"""
368 var mdoc = mentity.mdoc
369 if mdoc != null then
370 addn "<br/><br/>"
371 addn mdoc.html_documentation
372 end
373 end
374 addn "</h5>"
375 if node != null then
376 addn """
377 <div id='{{{mentity.html_id}}}' class='collapse {{{cin}}}'>
378 <pre>"""
379 render_code
380 addn """</pre>
381 <span class='text-muted'>{{{mentity.location.to_s}}}</span>
382 </div>"""
383 end
384 addn """
385 </div>
386 </div>"""
387 end
388 end
389
390 # A card that displays the code of a MEntity
391 class CardCode
392 super CardMEntity
393 autoinit(mentity, node)
394
395 # AST node to display in this card
396 var node: nullable ANode is writable
397
398 redef var id = "code_{super}" is lazy
399 redef var title = "Code"
400
401 redef fun rendering do
402 addn "<div id='{id}' class='card'>"
403 addn " <div class='card-body'>"
404
405 if node != null then
406 addn "<pre>"
407 render_code
408 addn "</pre>"
409 end
410 addn "<span class='text-muted'>{mentity.location}</span>"
411
412 addn " </div>"
413 addn "</div>"
414 end
415
416 private fun render_code do
417 var node = self.node
418 if node == null then return
419 var hl = new HtmlightVisitor
420 hl.show_infobox = false
421 hl.highlight_node node
422 addn hl.html
423 end
424 end
425
426 # A card that displays a graph
427 class CardGraph
428 super CardMEntity
429 autoinit(mentity, graph)
430
431 # Graph to display in this card
432 var graph: InheritanceGraph is writable
433
434 redef var id = "graph_{super}" is lazy
435 redef var title = "Graph"
436
437 redef fun rendering do
438 addn "<div id='{id}' class='card'>"
439 addn " <div class='card-body'>"
440 addn " <div class='text-center'>"
441 addn graph.graph.to_svg
442 addn " </div>"
443 addn " </div>"
444 addn "</div>"
445 end
446 end
447
448 # Catalog related cards
449
450 # A card that displays Nit catalog related data
451 abstract class CardCatalog
452 super StaticCard
453 autoinit(catalog)
454
455 # Catalog used to extract the data
456 var catalog: Catalog is writable
457 end
458
459 # A card that displays statistics about a Nit catalog
460 class CardCatalogStats
461 super CardCatalog
462
463 redef var id = "catalog_stats"
464 redef var title = "Stats"
465
466 redef fun rendering do
467 addn "<div id='{id}' class='container-fluid'>"
468 for key, value in catalog.catalog_stats.to_map do
469 addn "<span class='text-muted small'>"
470 addn " <strong>{value}</strong>&nbsp;<span>{key}</span>&nbsp;"
471 addn "</span>"
472 end
473 addn "</div>"
474 addn "<hr/>"
475 end
476 end
477
478 # A card that displays a list of tags
479 class CardCatalogTags
480 super CardCatalog
481
482 redef var id = "catalog_tags"
483 redef var title = "Tags"
484
485 # Sorter to sort tags alphabetically
486 var tags_sorter = new CatalogTagsSorter is writable
487
488 redef fun rendering do
489 var tags = catalog.tag2proj.keys.to_a
490 if tags.is_empty then return
491 tags_sorter.sort(tags)
492
493 addn "<h2 id='{id}'>Tags</h2>"
494 addn "<div class='container-fluid'>"
495 for tag in tags do
496 addn "<div class='col-xs-6 col-sm-3 col-md-2'>"
497 addn " <span class='badge'>{catalog.tag2proj[tag].length}</span>"
498 addn " <a href='tag_{tag.to_cmangle}.html'>{tag}</a>"
499 addn "</div>"
500 end
501 addn "</div>"
502 addn "<hr/>"
503 end
504 end
505
506 # A card that displays a package from a Nit catalog
507 class CardCatalogPackage
508 super CardCatalog
509 super CardMEntity
510 autoinit(catalog, mentity)
511
512 redef var id = "package_{super}" is lazy
513
514 redef fun rendering do
515 var mpackage = self.mentity
516 if not mpackage isa MPackage then return
517
518 addn """
519 <div id='{{{id}}}' class='card'>
520 <div class='card-left text-center'>{{{mpackage.html_icon.write_to_string}}}</div>
521 <div class='card-body' style='width: 75%'>
522 <h5 class='card-heading'>
523 {{{mentity.html_declaration.write_to_string}}}
524 <small>&nbsp;"""
525 for tag in mpackage.metadata.tags do
526 add "<span>"
527 add "<a href='tag_{tag.to_cmangle}.html' class='text-muted'>{tag}</a>"
528 if tag != mpackage.metadata.tags.last then addn ", "
529 add "</span>"
530 end
531 addn """</small>
532 </h5>"""
533 var mdoc = mentity.mdoc_or_fallback
534 if mdoc != null then
535 if full_doc then
536 addn mdoc.html_documentation
537 else
538 addn mdoc.html_synopsis
539 end
540 end
541 addn " </div>"
542 addn " <div class='card-right' style='width: 25%'>"
543 for maintainer in mpackage.metadata.maintainers do
544 addn maintainer.to_html
545 end
546 addn " <br>"
547 var license = mpackage.metadata.license
548 if license != null then
549 addn """
550 <span class='text-muted'>
551 <a href='http://opensource.org/licenses/{{{license}}}' class='text-muted'>
552 {{{license}}}
553 </a>
554 </span>"""
555 end
556 addn " </div>"
557 addn "</div>"
558 end
559 end
560
561 # A card that displays the metadata about a package in the Nit catalog
562 class CardMetadata
563 super CardMEntity
564 autoinit(mentity, metadata, stats, deps, clients)
565
566 # Package metadata to display
567 var metadata: MPackageMetadata is writable
568
569 # Package stats
570 var stats: MPackageStats is writable
571
572 # Package dependencies
573 var deps: Array[MPackage] is writable
574
575 # Package clients
576 var clients: Array[MPackage] is writable
577
578 redef var id = "metadata_{super}" is lazy
579 redef var title = "Metadata"
580
581 redef fun rendering do
582 for maintainer in metadata.maintainers do
583 addn """
584 <p class='lead'>
585 {{{maintainer.to_html}}}
586 </p>"""
587 end
588 var license = metadata.license
589 if license != null then
590 addn """
591 <span class='text-muted'>
592 <a href='http://opensource.org/licenses/{{{license}}}'>{{{license}}}</a>
593 license
594 </span>"""
595 end
596
597 var homepage = metadata.homepage
598 var browse = metadata.browse
599 var issues = metadata.issues
600 if homepage != null or browse != null or issues != null then
601 addn """
602 <h4>Links</h4>
603 <ul class='list-unstyled'>"""
604 if homepage != null then addn "<li><a href='{homepage}'>Homepage</a></li>"
605 if browse != null then addn "<li><a href='{browse}'>Source Code</a></li>"
606 if issues != null then addn "<li><a href='{issues}'>Issues</a></li>"
607 addn "</ul>"
608 end
609
610 var git = metadata.git
611 var last_date = metadata.last_date
612 var first_date = metadata.first_date
613 if git != null then
614 addn """
615 <h4>Git</h4>
616 <ul class='list-unstyled'>
617 <li><a href='{{{git}}}'>{{{git}}}</a></li>
618 </ul>
619 <span class='text-muted'><b>{{{stats.commits}}}</b> commits</span>
620 <br>"""
621 if last_date != null then
622 addn """<b class=text-muted>Last:</b> {{{last_date}}}<br>"""
623 end
624 if first_date != null then
625 addn """<b class=text-muted>First:</b> {{{first_date}}}"""
626 end
627 end
628
629 addn """
630 <h4>Quality</h4>
631 <ul class='list-unstyled'>
632 <li>{{{stats.documentation_score}}}% documented</li>
633 </ul>"""
634
635 if metadata.tags.not_empty then
636 addn "<h4>Tags</h4>"
637 for tag in metadata.tags do
638 addn " <a href='tag_{tag.to_cmangle}.html'>{tag}</a>"
639 if tag != metadata.tags.last then add ", "
640 end
641 end
642
643 if deps.not_empty then
644 addn "<h4>Dependencies</h4>"
645 for dep in deps do
646 add dep.html_link
647 if dep != deps.last then add ", "
648 end
649 end
650
651 if clients.not_empty then
652 addn "<h4>Clients</h4>"
653 for client in clients do
654 add client.html_link
655 if client != clients.last then add ", "
656 end
657 end
658
659 if metadata.contributors.not_empty then
660 addn """
661 <h4>Contributors</h4>
662 <ul class='list-unstyled'>"""
663 for contrib in metadata.contributors do
664 addn """<li>{{{contrib.to_html}}}</li>"""
665 end
666 addn "</ul>"
667 end
668
669 addn """
670 <h4>Stats</h4>
671 <ul class='list-unstyled'>
672 <li>{{{stats.mmodules}}} modules</li>
673 <li>{{{stats.mclasses}}} classes</li>
674 <li>{{{stats.mmethods}}} methods</li>
675 <li>{{{stats.loc}}} loc</li>
676 </ul>"""
677 end
678 end