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