src: add new hub modules to regroup related things together.
[nit.git] / src / highlight.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 # Highliting of Nit AST
16 module highlight
17
18 import frontend
19 import html
20 import pipeline
21 import astutil
22
23 # Visitor used to produce a HTML tree based on a AST on a `Source`
24 class HighlightVisitor
25 # The root of the HTML hierarchy
26 var html = new HTMLTag("span")
27
28 # Is the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
29 # Used to have a really huge and verbose HTML (mainly for debug)
30 var with_ast writable = false
31
32 # The first line to generate, null if start at the first line
33 var first_line: nullable Int writable = null
34
35 # The last line to generate, null if finish at the last line
36 var last_line: nullable Int writable = null
37
38 init
39 do
40 html.add_class("nitcode")
41 end
42
43 fun enter_visit(n: ANode)
44 do
45 n.parentize_tokens
46 var s = n.location.file
47 htmlize(s.first_token.as(not null), s.last_token.as(not null))
48 end
49
50 # Produce HTML between two tokens
51 protected fun htmlize(first_token, last_token: Token)
52 do
53 var stack2 = new Array[HTMLTag]
54 var stack = new Array[Prod]
55 var closes = new Array[Prod]
56 var line = 0
57 var c: nullable Token = first_token
58 var hv = new HighlightVisitor
59 while c != null do
60 var starting
61
62 # Handle start of line
63 var cline = c.location.line_start
64 if cline != line then
65 # Handle starting block productions,
66 # Because c could be a detached token, get prods in
67 # the first AST token
68 var c0 = c.first_token_in_line
69 starting = null
70 if c0 != null then starting = c0.starting_prods
71 if starting != null then for p in starting do
72 if not p.is_block then continue
73 var tag = p.make_tag(hv)
74 if tag == null then continue
75 tag.add_class("foldable")
76 var infobox = p.infobox(hv)
77 if infobox != null then tag.attach_infobox(infobox)
78 stack2.add(html)
79 html.add tag
80 html = tag
81 stack.add(p)
82 end
83
84 # Add a div for the whole line
85 var tag = new HTMLTag("span")
86 tag.attrs["id"] = "L{cline}"
87 tag.classes.add "line"
88 stack2.add(html)
89 html.add tag
90 html = tag
91 line = cline
92 end
93
94 # Add the blank, verbatim
95 html.add_raw_html c.blank_before
96
97 # Handle starting span production
98 starting = c.starting_prods
99 if starting != null then for p in starting do
100 if not p.is_span then continue
101 var tag = p.make_tag(hv)
102 if tag == null then continue
103 var infobox = p.infobox(hv)
104 if infobox != null then tag.attach_infobox(infobox)
105 stack2.add(html)
106 html.add tag
107 html = tag
108 stack.add(p)
109 end
110
111 # Add the token
112 if c isa TEol then
113 html.append "\n"
114 else
115 var tag = c.make_tag(hv)
116 var pa = c.parent
117 var infobox = null
118 if c isa TId or c isa TClassid or c isa TAttrid or c isa TokenLiteral or c isa TokenOperator then
119 assert c != null
120 if pa != null then infobox = pa.decorate_tag(hv, tag, c)
121 else if c isa TComment and pa isa ADoc then
122 infobox = pa.decorate_tag(hv, tag, c)
123 end
124 if infobox != null then tag.attach_infobox(infobox)
125 html.add tag
126 end
127
128 # Handle ending span productions
129 var ending = c.ending_prods
130 if ending != null then for p in ending do
131 if not p.is_span then continue
132 if stack.is_empty or p != stack.last then continue
133 stack.pop
134 html = stack2.pop
135 end
136
137 # Handle end of line and end of file
138 var n = c.next_token
139 if c == last_token then n = null
140 if n == null or n.location.line_start != line then
141 # closes the line div
142 html = stack2.pop
143
144 # close the block production divs
145 var c0 = c.last_token_in_line
146 ending = null
147 if c0 != null then ending = c0.ending_prods
148 if ending != null then for p in ending do
149 if not p.is_block then continue
150 if stack.is_empty or p != stack.last then continue
151 stack.pop
152 html = stack2.pop
153 end
154 end
155
156 c = n
157 end
158 assert stack.is_empty
159 assert stack2.is_empty
160 end
161
162 # Return a default CSS content related to CSS classes used in the `html` tree.
163 # Could be inlined in the `.html` file of saved as a specific `.css` file.
164 fun css_content: String
165 do
166 return """
167 .nitcode a { color: inherit; cursor:pointer; }
168 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
169 pre.nitcode .foldable { display: block } /* for block productions*/
170 pre.nitcode .line{ display: block } /* for lines */
171 pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
172 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
173 /* lexical raw tokens. independent of usage or semantic: */
174 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
175 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
176 .nitcode .nc_k { font-weight: bold; } /* keyword */
177 .nitcode .nc_o {} /* operator */
178 .nitcode .nc_i {} /* standard identifier */
179 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
180 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
181 .nitcode .nc_l { color: #009999; } /* char and number literal */
182 .nitcode .nc_s { color: #8F1546; } /* string literal */
183 /* syntactic token usage. added because of their position in the AST */
184 .nitcode .nc_ast { color: blue; } /* assert label */
185 .nitcode .nc_la { color: blue; } /* break/continue label */
186 .nitcode .nc_m { color: #445588; } /* module name */
187 /* syntactic groups */
188 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
189 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
190 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
191 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
192 .nitcode .nc_cdef {} /* A whole class definition */
193 .nitcode .nc_pdef {} /* A whole property definition */
194 /* semantic token usage */
195 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
196 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
197
198 .nitcode .nc_error { border: 1px red solid;} /* not used */
199 .popover { max-width: 800px !important; }
200 """
201 end
202
203 # Additional content to inject in the <head> tag
204 # Note: does not include `css_content`; handle it yourself.
205 fun head_content: String
206 do
207 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
208 end
209
210 # Additional content to inject just before the closing </body> tag
211 fun foot_content: String
212 do
213 return """
214 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
215 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
216 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
217 end
218 end
219
220 redef class HTMLTag
221 # Attach the infobox to the node by using BootStrap popover
222 fun attach_infobox(infobox: HInfoBox)
223 do
224 classes.add("popupable")
225 attrs["title"] = infobox.title
226 var href = infobox.href
227 if href != null then
228 attrs["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
229 end
230 attrs["data-content"] = infobox.content.write_to_string
231 attrs["data-toggle"] = "popover"
232 end
233 end
234
235
236 # A generic information container that can be used to decorate AST entities
237 class HInfoBox
238 # The visitor used for contextualisation, if needed
239 var visitor: HighlightVisitor
240
241 # A short title for the AST element
242 var title: String
243
244 # The primary link where the entity points
245 # null if no link
246 var href: nullable String = null
247
248 # The content of the popuped infobox
249 var content = new HTMLTag("div")
250
251 # Append a new field in the popuped infobox
252 fun new_field(title: String): HTMLTag
253 do
254 content.open("b").text(title)
255 content.append(" ")
256 var res = content.open("span")
257 content.open("br")
258 return res
259 end
260
261 # Append a new dropdown in the popuped content
262 fun new_dropdown(title, text: String): HTMLTag
263 do
264 content.add_raw_html """<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
265 content.append(title)
266 content.add_raw_html "</b> "
267 content.append(text)
268 content.add_raw_html """<span class="caret"></span></a>"""
269 var res = content.open("ul").add_class("dropdown-menu").attr("role", "menu").attr("aria-labelledby", "dLabel")
270 content.add_raw_html "</div>"
271 return res
272 end
273 end
274
275 ##
276
277 # Model entity or whatever that can produce an infobox
278 interface HInfoBoxable
279 # An new infobox documenting the entity
280 fun infobox(v: HighlightVisitor): HInfoBox is abstract
281
282 # A human-readable hyper-text for the entity
283 fun linkto: HTMLTag is abstract
284 end
285
286 redef class MDoc
287 # Append an entry for the doc in the given infobox
288 fun fill_infobox(res: HInfoBox)
289 do
290 if content.length < 2 then
291 res.new_field("doc").text(content.first)
292 return
293 end
294 var c = res.new_dropdown("doc", content.first)
295 for x in content.iterator.skip_head(1) do
296 c.append x
297 c.add_raw_html "<br>"
298 end
299 end
300 end
301
302 redef class MEntity
303 super HInfoBoxable
304 end
305
306 redef class MModule
307 redef fun infobox(v)
308 do
309 var res = new HInfoBox(v, "module {name}")
310 res.href = href
311 res.new_field("module").add(linkto)
312 var mdoc = self.mdoc
313 if mdoc != null then mdoc.fill_infobox(res)
314 if in_importation.greaters.length > 1 then
315 var c = res.new_dropdown("imports", "{in_importation.greaters.length-1} modules")
316 for x in in_importation.greaters do
317 if x == self then continue
318 c.open("li").add x.linkto
319 end
320 end
321 return res
322 end
323
324 fun href: String
325 do
326 return name + ".html"
327 end
328
329 redef fun linkto do return linkto_text(name)
330
331 # Link to the entitiy with a specific text
332 fun linkto_text(text: String): HTMLTag
333 do
334 return (new HTMLTag("a")).attr("href", href).text(text)
335 end
336 end
337
338 redef class MClassDef
339 redef fun infobox(v)
340 do
341 var res = new HInfoBox(v, "class {mclass.name}")
342 res.href = href
343 if is_intro then
344 res.new_field("class").text(mclass.name)
345 else
346 res.new_field("redef class").text(mclass.name)
347 res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
348 end
349 var mdoc = self.mdoc
350 if mdoc == null then mdoc = mclass.intro.mdoc
351 if mdoc != null then mdoc.fill_infobox(res)
352
353 if in_hierarchy.greaters.length > 1 then
354 var c = res.new_dropdown("hier", "super-classes")
355 for x in in_hierarchy.greaters do
356 if x == self then continue
357 if not x.is_intro then continue
358 c.open("li").add x.linkto
359 end
360 end
361 if in_hierarchy.smallers.length > 1 then
362 var c = res.new_dropdown("hier", "sub-classes")
363 for x in in_hierarchy.smallers do
364 if x == self then continue
365 if not x.is_intro then continue
366 c.open("li").add x.linkto
367 end
368 end
369 if mclass.mclassdefs.length > 1 then
370 var c = res.new_dropdown("redefs", "refinements")
371 for x in mclass.mclassdefs do
372 if x == self then continue
373 c.open("li").add x.linkto_text("in {x.mmodule}")
374 end
375 end
376 return res
377 end
378
379 fun href: String
380 do
381 return mmodule.href + "#" + to_s
382 end
383
384 redef fun linkto do return linkto_text(mclass.name)
385
386 # Link to the entitiy with a specific text
387 fun linkto_text(text: String): HTMLTag
388 do
389 return (new HTMLTag("a")).attr("href", href).text(text)
390 end
391 end
392
393 redef class MPropDef
394 redef fun infobox(v)
395 do
396 var res = new HInfoBox(v, to_s)
397 res.href = href
398 if self isa MMethodDef then
399 res.new_field("fun").append(mproperty.name).add msignature.linkto
400 else if self isa MAttributeDef then
401 res.new_field("fun").append(mproperty.name).add static_mtype.linkto
402 else if self isa MVirtualTypeDef then
403 res.new_field("add").append(mproperty.name).add bound.linkto
404 else
405 res.new_field("wat?").append(mproperty.name)
406 end
407
408 if is_intro then
409 else
410 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
411 end
412 var mdoc = self.mdoc
413 if mdoc == null then mdoc = mproperty.intro.mdoc
414 if mdoc != null then mdoc.fill_infobox(res)
415 if mproperty.mpropdefs.length > 1 then
416 var c = res.new_dropdown("redef", "redefinitions")
417 for x in mproperty.mpropdefs do
418 c.open("li").add x.linkto_text("in {x.mclassdef}")
419 end
420 end
421
422 return res
423 end
424
425 fun href: String
426 do
427 return self.mclassdef.mmodule.href + "#" + self.to_s
428 end
429
430 redef fun linkto do return linkto_text(mproperty.name)
431
432 # Link to the entitiy with a specific text
433 fun linkto_text(text: String): HTMLTag
434 do
435 return (new HTMLTag("a")).attr("href", href).text(text)
436 end
437 end
438
439 redef class MClassType
440 redef fun infobox(v)
441 do
442 var res = new HInfoBox(v, to_s)
443 res.href = mclass.intro.href
444 res.new_field("class").add mclass.intro.linkto
445 var mdoc = mclass.mdoc
446 if mdoc == null then mdoc = mclass.intro.mdoc
447 if mdoc != null then mdoc.fill_infobox(res)
448 return res
449 end
450 redef fun linkto
451 do
452 return mclass.intro.linkto
453 end
454 end
455 redef class MVirtualType
456 redef fun infobox(v)
457 do
458 var res = new HInfoBox(v, to_s)
459 res.href = mproperty.intro.href
460 var p = mproperty
461 var pd = p.intro
462 res.new_field("virtual type").add pd.linkto
463 var mdoc = pd.mdoc
464 if mdoc != null then mdoc.fill_infobox(res)
465 return res
466 end
467 redef fun linkto
468 do
469 return mproperty.intro.linkto
470 end
471 end
472 redef class MParameterType
473 redef fun infobox(v)
474 do
475 var res = new HInfoBox(v, to_s)
476 var name = mclass.intro.parameter_names[rank]
477 res.new_field("parameter type").append("{name} from class ").add mclass.intro.linkto
478 return res
479 end
480 redef fun linkto
481 do
482 var name = mclass.intro.parameter_names[rank]
483 return (new HTMLTag("span")).text(name)
484 end
485 end
486
487 redef class MNullableType
488 redef fun infobox(v)
489 do
490 return mtype.infobox(v)
491 end
492 redef fun linkto
493 do
494 var res = new HTMLTag("span")
495 res.append("nullable ").add(mtype.linkto)
496 return res
497 end
498 end
499
500 redef class MSignature
501 redef fun linkto
502 do
503 var res = new HTMLTag("span")
504 var first = true
505 if not mparameters.is_empty then
506 res.append "("
507 for p in mparameters do
508 if first then
509 first = false
510 else
511 res.append ", "
512 end
513 res.append p.name
514 res.append ": "
515 res.add p.mtype.linkto
516 end
517 res.append ")"
518 end
519 var ret = return_mtype
520 if ret != null then
521 res.append ": "
522 res.add ret.linkto
523 end
524 return res
525 end
526 end
527
528 redef class CallSite
529 super HInfoBoxable
530 redef fun infobox(v)
531 do
532 var res = new HInfoBox(v, "call {mpropdef}")
533 res.href = mpropdef.href
534 res.new_field("call").add(mpropdef.linkto).add(msignature.linkto)
535 if mpropdef.is_intro then
536 else
537 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
538 end
539 var mdoc = mpropdef.mdoc
540 if mdoc == null then mdoc = mproperty.intro.mdoc
541 if mdoc != null then mdoc.fill_infobox(res)
542
543 return res
544 end
545 redef fun linkto
546 do
547 return mpropdef.linkto
548 end
549 end
550
551 redef class Variable
552 super HInfoBoxable
553 redef fun infobox(v)
554 do
555 var declared_type = self.declared_type
556 if declared_type == null then
557 var res = new HInfoBox(v, "{name}")
558 res.new_field("local var").append("{name}")
559 return res
560 end
561 var res = new HInfoBox(v, "{name}: {declared_type}")
562 res.new_field("local var").append("{name}:").add(declared_type.linkto)
563 return res
564 end
565 redef fun linkto
566 do
567 return (new HTMLTag("span")).text(name)
568 end
569 end
570
571
572 ##
573
574 redef class ANode
575 # Optionally creates a tag that encapsulate the AST element on HTML rendering
576 protected fun make_tag(v: HighlightVisitor): nullable HTMLTag do return null
577
578 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
579 protected fun decorate_tag(v: HighlightVisitor, res: HTMLTag, token: Token): nullable HInfoBox
580 do
581 #debug("no decoration for {token.inspect}")
582 #res.add_class("nc_error")
583 return null
584 end
585
586 # Return a optional infobox
587 fun infobox(v: HighlightVisitor): nullable HInfoBox do return null
588 end
589
590 redef class AStdClassdef
591 redef fun make_tag(v)
592 do
593 var res = new HTMLTag("span")
594 res.add_class("nc_cdef")
595 var md = mclassdef
596 if md != null then res.attr("id", md.to_s)
597 return res
598 end
599 redef fun decorate_tag(v, res, token)
600 do
601 res.add_class("nc_def")
602
603 var md = mclassdef
604 if md == null then return null
605 return md.infobox(v)
606 end
607 end
608 redef class APropdef
609 redef fun make_tag(v)
610 do
611 var res = new HTMLTag("span")
612 res.add_class("nc_pdef")
613 var mpd
614 mpd = mpropdef
615 if mpd != null then
616 #res.add(tag(mpd))
617 res.attr("id", mpd.to_s)
618 end
619 if self isa AAttrPropdef then
620 mpd = mreadpropdef
621 if mpd != null then res.add(tag(mpd))
622 mpd = mwritepropdef
623 if mpd != null then res.add(tag(mpd))
624 end
625 return res
626 end
627
628 private fun tag(mpd: MPropDef): HTMLTag
629 do
630 var a = new HTMLTag("a")
631 a.attr("id", mpd.to_s)
632 return a
633 end
634 end
635
636 redef class Token
637 # Produce an HTMLTag with the correct contents and CSS classes
638 # Subclasses can redefine it to decorate the tag
639 redef fun make_tag(v: HighlightVisitor): HTMLTag
640 do
641 var res = new HTMLTag("span")
642 res.text(text)
643 return res
644 end
645 end
646
647 redef class TokenKeyword
648 redef fun make_tag(v)
649 do
650 var res = super
651 res.add_class("nc_k")
652 return res
653 end
654 end
655 redef class TokenOperator
656 redef fun make_tag(v)
657 do
658 var res = super
659 var p = parent
660 if p != null then p.decorate_tag(v, res, self)
661 res.add_class("nc_o")
662 return res
663 end
664 end
665
666 redef class AVarFormExpr
667 redef fun decorate_tag(v, res, token)
668 do
669 var variable = self.variable
670 if variable == null then return null
671 res.add_class("nc_v")
672 return variable.infobox(v)
673 end
674 end
675
676 redef class AVardeclExpr
677 redef fun decorate_tag(v, res, token)
678 do
679 var variable = self.variable
680 if variable == null then return null
681 res.add_class("nc_v")
682 return variable.infobox(v)
683 end
684 end
685
686 redef class AForExpr
687 redef fun decorate_tag(v, res, token)
688 do
689 if not token isa TId then return null
690 var vs = variables
691 if vs == null then return null
692 res.add_class("nc_v")
693 var idx = n_ids.index_of(token)
694 var variable = vs[idx]
695 return variable.infobox(v)
696 end
697 end
698
699 redef class AParam
700 redef fun decorate_tag(v, res, token)
701 do
702 var mp = mparameter
703 if mp == null then return null
704 var variable = self.variable
705 if variable == null then return null
706 res.add_class("nc_v")
707 return variable.infobox(v)
708 end
709 end
710
711 redef class AAssertExpr
712 redef fun decorate_tag(v, res, token)
713 do
714 res.add_class("nc_ast")
715 return null
716 end
717 end
718
719 redef class ALabel
720 redef fun decorate_tag(v, res, token)
721 do
722 res.add_class("nc_la")
723 return null
724 end
725 end
726
727 redef class ASendExpr
728 redef fun decorate_tag(v, res, token)
729 do
730 if callsite == null then return null
731 return callsite.infobox(v)
732 end
733 end
734
735 redef class ANewExpr
736 redef fun decorate_tag(v, res, token)
737 do
738 if callsite == null then return null
739 return callsite.infobox(v)
740 end
741 end
742
743 redef class AAssignOp
744 redef fun decorate_tag(v, res, token)
745 do
746 var p = parent
747 assert p isa AReassignFormExpr
748
749 var callsite = p.reassign_callsite
750 if callsite == null then return null
751 return callsite.infobox(v)
752 end
753 end
754
755 redef class AModuleName
756 redef fun decorate_tag(v, res, token)
757 do
758 return parent.decorate_tag(v, res, token)
759 end
760 end
761
762 redef class AModuledecl
763 redef fun decorate_tag(v, res, token)
764 do
765 res.add_class("nc_def")
766 res.add_class("nc_m")
767 var p = parent
768 assert p isa AModule
769 var mm = p.mmodule
770 if mm == null then return null
771 return mm.infobox(v)
772 end
773 end
774
775 redef class AStdImport
776 redef fun decorate_tag(v, res, token)
777 do
778 res.add_class("nc_m")
779 var mm = mmodule
780 if mm == null then return null
781 return mm.infobox(v)
782 end
783 end
784 redef class AAttrPropdef
785 redef fun decorate_tag(v, res, token)
786 do
787 res.add_class("nc_def")
788 var mpd: nullable MPropDef
789 mpd = mreadpropdef
790 if mpd == null then mpd = mpropdef
791 if mpd == null then return null
792 return mpd.infobox(v)
793 end
794 end
795
796 redef class TId
797 redef fun make_tag(v)
798 do
799 var res = super
800 var p = parent
801 if p != null then p.decorate_tag(v, res, self)
802 res.add_class("nc_i")
803 return res
804 end
805 end
806 redef class AMethid
807 redef fun make_tag(v)
808 do
809 var res = new HTMLTag("span")
810 res.add_class("nc_def")
811 return res
812 end
813 redef fun decorate_tag(v, res, token)
814 do
815 return null
816 # nothing to decorate
817 end
818 redef fun infobox(v)
819 do
820 var p = parent
821 if not p isa AMethPropdef then return null
822 var mpd = p.mpropdef
823 if mpd == null then return null
824 return mpd.infobox(v)
825 end
826 end
827 redef class TAttrid
828 redef fun make_tag(v)
829 do
830 var res = super
831 var p = parent
832 if p != null then p.decorate_tag(v, res, self)
833 res.add_class("nc_a")
834 return res
835 end
836 end
837 redef class AAttrFormExpr
838 redef fun decorate_tag(v, res, token)
839 do
840 var p = mproperty
841 if p == null then return null
842 return p.intro.infobox(v)
843 end
844 end
845 redef class TClassid
846 redef fun make_tag(v)
847 do
848 var res = super
849 var p = parent
850 if p != null then p.decorate_tag(v, res, self)
851 res.add_class("nc_t")
852 return res
853 end
854 end
855 redef class AType
856 redef fun decorate_tag(v, res, token)
857 do
858 var mt = mtype
859 if mt == null then return null
860 mt = mt.as_notnullable
861 if mt isa MVirtualType or mt isa MParameterType then
862 res.add_class("nc_vt")
863 end
864 return mt.infobox(v)
865 end
866 end
867 redef class AFormaldef
868 redef fun decorate_tag(v, res, token)
869 do
870 res.add_class("nc_vt")
871 if mtype == null then return null
872 return mtype.infobox(v)
873 end
874 end
875 redef class ATypePropdef
876 redef fun decorate_tag(v, res, token)
877 do
878 res.add_class("nc_def")
879 var md = mpropdef
880 if md == null then return null
881 return md.infobox(v)
882 end
883 end
884 redef class TComment
885 redef fun make_tag(v)
886 do
887 var res = super
888 if not parent isa ADoc then
889 res.add_class("nc_c")
890 end
891 return res
892 end
893 end
894 redef class ADoc
895 redef fun make_tag(v)
896 do
897 var res = new HTMLTag("span")
898 res.add_class("nc_d")
899 return res
900 end
901 end
902 redef class TokenLiteral
903 redef fun make_tag(v)
904 do
905 var res = super
906 res.add_class("nc_l")
907 var p = parent
908 if p != null then p.decorate_tag(v, res, self)
909 return res
910 end
911 end
912 redef class ASuperstringExpr
913 redef fun make_tag(v)
914 do
915 var res = new HTMLTag("span")
916 res.add_class("nc_ss")
917 return res
918 end
919 end
920 redef class AStringFormExpr
921 redef fun decorate_tag(v, res, token)
922 do
923 # Workaround to tag strings
924 res.classes.remove("nc_l")
925 res.add_class("nc_s")
926 return null
927 end
928 end
929 redef class AExpr
930 redef fun decorate_tag(v, res, token)
931 do
932 var t = mtype
933 if t == null then return null
934 return t.infobox(v)
935 end
936 end
937