highlight: do not add html classes to unresolved local variables
[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 modelize_property
19 import frontend
20 import html
21 import pipeline
22 import astutil
23
24 # Visitor used to produce a HTML tree based on a AST on a `Source`
25 class HighlightVisitor
26 # The root of the HTML hierarchy
27 var html = new HTMLTag("span")
28
29 # Is the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
30 # Used to have a really huge and verbose HTML (mainly for debug)
31 var with_ast writable = false
32
33 # The first line to generate, null if start at the first line
34 var first_line: nullable Int writable = null
35
36 # The last line to generate, null if finish at the last line
37 var last_line: nullable Int writable = null
38
39 init
40 do
41 html.add_class("nitcode")
42 end
43
44 fun enter_visit(n: ANode)
45 do
46 n.parentize_tokens
47 var s = n.location.file
48 htmlize(s.first_token.as(not null), s.last_token.as(not null))
49 end
50
51 # Produce HTML between two tokens
52 protected fun htmlize(first_token, last_token: Token)
53 do
54 var stack2 = new Array[HTMLTag]
55 var stack = new Array[Prod]
56 var closes = new Array[Prod]
57 var line = 0
58 var c: nullable Token = first_token
59 var hv = new HighlightVisitor
60 while c != null do
61 var starting
62
63 # Handle start of line
64 var cline = c.location.line_start
65 if cline != line then
66 # Handle starting block productions,
67 # Because c could be a detached token, get prods in
68 # the first AST token
69 var c0 = c.first_token_in_line
70 starting = null
71 if c0 != null then starting = c0.starting_prods
72 if starting != null then for p in starting do
73 if not p.is_block then continue
74 var tag = p.make_tag(hv)
75 if tag == null then continue
76 tag.add_class("foldable")
77 var infobox = p.infobox(hv)
78 if infobox != null then tag.attach_infobox(infobox)
79 stack2.add(html)
80 html.add tag
81 html = tag
82 stack.add(p)
83 end
84
85 # Add a div for the whole line
86 var tag = new HTMLTag("span")
87 tag.attrs["id"] = "L{cline}"
88 tag.classes.add "line"
89 stack2.add(html)
90 html.add tag
91 html = tag
92 line = cline
93 end
94
95 # Add the blank, verbatim
96 html.add_raw_html c.blank_before
97
98 # Handle starting span production
99 starting = c.starting_prods
100 if starting != null then for p in starting do
101 if not p.is_span then continue
102 var tag = p.make_tag(hv)
103 if tag == null then continue
104 var infobox = p.infobox(hv)
105 if infobox != null then tag.attach_infobox(infobox)
106 stack2.add(html)
107 html.add tag
108 html = tag
109 stack.add(p)
110 end
111
112 # Add the token
113 if c isa TEol then
114 html.append "\n"
115 else
116 var tag = c.make_tag(hv)
117 var pa = c.parent
118 var infobox = null
119 if c isa TId or c isa TClassid or c isa TAttrid or c isa TokenLiteral or c isa TokenOperator then
120 assert c != null
121 if pa != null then infobox = pa.decorate_tag(hv, tag, c)
122 else if c isa TComment and pa isa ADoc then
123 infobox = pa.decorate_tag(hv, tag, c)
124 end
125 if infobox != null then tag.attach_infobox(infobox)
126 html.add tag
127 end
128
129 # Handle ending span productions
130 var ending = c.ending_prods
131 if ending != null then for p in ending do
132 if not p.is_span then continue
133 if stack.is_empty or p != stack.last then continue
134 stack.pop
135 html = stack2.pop
136 end
137
138 # Handle end of line and end of file
139 var n = c.next_token
140 if c == last_token then n = null
141 if n == null or n.location.line_start != line then
142 # closes the line div
143 html = stack2.pop
144
145 # close the block production divs
146 var c0 = c.last_token_in_line
147 ending = null
148 if c0 != null then ending = c0.ending_prods
149 if ending != null then for p in ending do
150 if not p.is_block then continue
151 if stack.is_empty or p != stack.last then continue
152 stack.pop
153 html = stack2.pop
154 end
155 end
156
157 c = n
158 end
159 assert stack.is_empty
160 assert stack2.is_empty
161 end
162
163 # Return a default CSS content related to CSS classes used in the `html` tree.
164 # Could be inlined in the `.html` file of saved as a specific `.css` file.
165 fun css_content: String
166 do
167 return """
168 .nitcode a { color: inherit; cursor:pointer; }
169 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
170 pre.nitcode .foldable { display: block } /* for block productions*/
171 pre.nitcode .line{ display: block } /* for lines */
172 pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
173 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
174 /* lexical raw tokens. independent of usage or semantic: */
175 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
176 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
177 .nitcode .nc_k { font-weight: bold; } /* keyword */
178 .nitcode .nc_o {} /* operator */
179 .nitcode .nc_i {} /* standard identifier */
180 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
181 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
182 .nitcode .nc_l { color: #009999; } /* char and number literal */
183 .nitcode .nc_s { color: #8F1546; } /* string literal */
184 /* syntactic token usage. added because of their position in the AST */
185 .nitcode .nc_ast { color: blue; } /* assert label */
186 .nitcode .nc_la { color: blue; } /* break/continue label */
187 .nitcode .nc_m { color: #445588; } /* module name */
188 /* syntactic groups */
189 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
190 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
191 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
192 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
193 .nitcode .nc_cdef {} /* A whole class definition */
194 .nitcode .nc_pdef {} /* A whole property definition */
195 /* semantic token usage */
196 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
197 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
198
199 .nitcode .nc_error { border: 1px red solid;} /* not used */
200 .popover { max-width: 800px !important; }
201 """
202 end
203
204 # Additional content to inject in the <head> tag
205 # Note: does not include `css_content`; handle it yourself.
206 fun head_content: String
207 do
208 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
209 end
210
211 # Additional content to inject just before the closing </body> tag
212 fun foot_content: String
213 do
214 return """
215 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
216 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
217 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
218 end
219 end
220
221 redef class HTMLTag
222 # Attach the infobox to the node by using BootStrap popover
223 fun attach_infobox(infobox: HInfoBox)
224 do
225 classes.add("popupable")
226 attrs["title"] = infobox.title
227 var href = infobox.href
228 if href != null then
229 attrs["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
230 end
231 attrs["data-content"] = infobox.content.write_to_string
232 attrs["data-toggle"] = "popover"
233 end
234 end
235
236
237 # A generic information container that can be used to decorate AST entities
238 class HInfoBox
239 # The visitor used for contextualisation, if needed
240 var visitor: HighlightVisitor
241
242 # A short title for the AST element
243 var title: String
244
245 # The primary link where the entity points
246 # null if no link
247 var href: nullable String = null
248
249 # The content of the popuped infobox
250 var content = new HTMLTag("div")
251
252 # Append a new field in the popuped infobox
253 fun new_field(title: String): HTMLTag
254 do
255 content.open("b").text(title)
256 content.append(" ")
257 var res = content.open("span")
258 content.open("br")
259 return res
260 end
261
262 # Append a new dropdown in the popuped content
263 fun new_dropdown(title, text: String): HTMLTag
264 do
265 content.add_raw_html """<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
266 content.append(title)
267 content.add_raw_html "</b> "
268 content.append(text)
269 content.add_raw_html """<span class="caret"></span></a>"""
270 var res = content.open("ul").add_class("dropdown-menu").attr("role", "menu").attr("aria-labelledby", "dLabel")
271 content.add_raw_html "</div>"
272 return res
273 end
274 end
275
276 ##
277
278 # Model entity or whatever that can produce an infobox
279 interface HInfoBoxable
280 # An new infobox documenting the entity
281 fun infobox(v: HighlightVisitor): HInfoBox is abstract
282
283 # A human-readable hyper-text for the entity
284 fun linkto: HTMLTag is abstract
285 end
286
287 redef class MDoc
288 # Append an entry for the doc in the given infobox
289 fun fill_infobox(res: HInfoBox)
290 do
291 if content.length < 2 then
292 res.new_field("doc").text(content.first)
293 return
294 end
295 var c = res.new_dropdown("doc", content.first)
296 for x in content.iterator.skip_head(1) do
297 c.append x
298 c.add_raw_html "<br>"
299 end
300 end
301 end
302
303 redef class MEntity
304 super HInfoBoxable
305 end
306
307 redef class MModule
308 redef fun infobox(v)
309 do
310 var res = new HInfoBox(v, "module {name}")
311 res.href = href
312 res.new_field("module").add(linkto)
313 var mdoc = self.mdoc
314 if mdoc != null then mdoc.fill_infobox(res)
315 if in_importation.greaters.length > 1 then
316 var c = res.new_dropdown("imports", "{in_importation.greaters.length-1} modules")
317 for x in in_importation.greaters do
318 if x == self then continue
319 c.open("li").add x.linkto
320 end
321 end
322 return res
323 end
324
325 fun href: String
326 do
327 return name + ".html"
328 end
329
330 redef fun linkto do return linkto_text(name)
331
332 # Link to the entitiy with a specific text
333 fun linkto_text(text: String): HTMLTag
334 do
335 return (new HTMLTag("a")).attr("href", href).text(text)
336 end
337 end
338
339 redef class MClassDef
340 redef fun infobox(v)
341 do
342 var res = new HInfoBox(v, "class {mclass.name}")
343 res.href = href
344 if is_intro then
345 res.new_field("class").text(mclass.name)
346 else
347 res.new_field("redef class").text(mclass.name)
348 res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
349 end
350 var mdoc = self.mdoc
351 if mdoc == null then mdoc = mclass.intro.mdoc
352 if mdoc != null then mdoc.fill_infobox(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 res.new_field("fun").append(mproperty.name).add msignature.linkto
401 else if self isa MAttributeDef then
402 res.new_field("fun").append(mproperty.name).add static_mtype.linkto
403 else if self isa MVirtualTypeDef then
404 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 var name = mclass.intro.parameter_names[rank]
478 res.new_field("parameter type").append("{name} from class ").add mclass.intro.linkto
479 return res
480 end
481 redef fun linkto
482 do
483 var name = mclass.intro.parameter_names[rank]
484 return (new HTMLTag("span")).text(name)
485 end
486 end
487
488 redef class MNullableType
489 redef fun infobox(v)
490 do
491 return mtype.infobox(v)
492 end
493 redef fun linkto
494 do
495 var res = new HTMLTag("span")
496 res.append("nullable ").add(mtype.linkto)
497 return res
498 end
499 end
500
501 redef class MSignature
502 redef fun linkto
503 do
504 var res = new HTMLTag("span")
505 var first = true
506 if not mparameters.is_empty then
507 res.append "("
508 for p in mparameters do
509 if first then
510 first = false
511 else
512 res.append ", "
513 end
514 res.append p.name
515 res.append ": "
516 res.add p.mtype.linkto
517 end
518 res.append ")"
519 end
520 var ret = return_mtype
521 if ret != null then
522 res.append ": "
523 res.add ret.linkto
524 end
525 return res
526 end
527 end
528
529 redef class CallSite
530 super HInfoBoxable
531 redef fun infobox(v)
532 do
533 var res = new HInfoBox(v, "call {mpropdef}")
534 res.href = mpropdef.href
535 res.new_field("call").add(mpropdef.linkto).add(msignature.linkto)
536 if mpropdef.is_intro then
537 else
538 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
539 end
540 var mdoc = mpropdef.mdoc
541 if mdoc == null then mdoc = mproperty.intro.mdoc
542 if mdoc != null then mdoc.fill_infobox(res)
543
544 return res
545 end
546 redef fun linkto
547 do
548 return mpropdef.linkto
549 end
550 end
551
552 redef class Variable
553 super HInfoBoxable
554 redef fun infobox(v)
555 do
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 if mt isa MNullableType then mt = mt.mtype
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