update code to comply with new superstring policy
[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 var declared_type = self.declared_type
557 if declared_type == null then
558 var res = new HInfoBox(v, "{name}")
559 res.new_field("local var").append("{name}")
560 return res
561 end
562 var res = new HInfoBox(v, "{name}: {declared_type}")
563 res.new_field("local var").append("{name}:").add(declared_type.linkto)
564 return res
565 end
566 redef fun linkto
567 do
568 return (new HTMLTag("span")).text(name)
569 end
570 end
571
572
573 ##
574
575 redef class ANode
576 # Optionally creates a tag that encapsulate the AST element on HTML rendering
577 protected fun make_tag(v: HighlightVisitor): nullable HTMLTag do return null
578
579 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
580 protected fun decorate_tag(v: HighlightVisitor, res: HTMLTag, token: Token): nullable HInfoBox
581 do
582 #debug("no decoration for {token.inspect}")
583 #res.add_class("nc_error")
584 return null
585 end
586
587 # Return a optional infobox
588 fun infobox(v: HighlightVisitor): nullable HInfoBox do return null
589 end
590
591 redef class AStdClassdef
592 redef fun make_tag(v)
593 do
594 var res = new HTMLTag("span")
595 res.add_class("nc_cdef")
596 var md = mclassdef
597 if md != null then res.attr("id", md.to_s)
598 return res
599 end
600 redef fun decorate_tag(v, res, token)
601 do
602 res.add_class("nc_def")
603
604 var md = mclassdef
605 if md == null then return null
606 return md.infobox(v)
607 end
608 end
609 redef class APropdef
610 redef fun make_tag(v)
611 do
612 var res = new HTMLTag("span")
613 res.add_class("nc_pdef")
614 var mpd
615 mpd = mpropdef
616 if mpd != null then
617 #res.add(tag(mpd))
618 res.attr("id", mpd.to_s)
619 end
620 if self isa AAttrPropdef then
621 mpd = mreadpropdef
622 if mpd != null then res.add(tag(mpd))
623 mpd = mwritepropdef
624 if mpd != null then res.add(tag(mpd))
625 end
626 return res
627 end
628
629 private fun tag(mpd: MPropDef): HTMLTag
630 do
631 var a = new HTMLTag("a")
632 a.attr("id", mpd.to_s)
633 return a
634 end
635 end
636
637 redef class Token
638 # Produce an HTMLTag with the correct contents and CSS classes
639 # Subclasses can redefine it to decorate the tag
640 redef fun make_tag(v: HighlightVisitor): HTMLTag
641 do
642 var res = new HTMLTag("span")
643 res.text(text)
644 return res
645 end
646 end
647
648 redef class TokenKeyword
649 redef fun make_tag(v)
650 do
651 var res = super
652 res.add_class("nc_k")
653 return res
654 end
655 end
656 redef class TokenOperator
657 redef fun make_tag(v)
658 do
659 var res = super
660 var p = parent
661 if p != null then p.decorate_tag(v, res, self)
662 res.add_class("nc_o")
663 return res
664 end
665 end
666
667 redef class AVarFormExpr
668 redef fun decorate_tag(v, res, token)
669 do
670 var variable = self.variable
671 if variable == null then return null
672 res.add_class("nc_v")
673 return variable.infobox(v)
674 end
675 end
676
677 redef class AVardeclExpr
678 redef fun decorate_tag(v, res, token)
679 do
680 var variable = self.variable
681 if variable == null then return null
682 res.add_class("nc_v")
683 return variable.infobox(v)
684 end
685 end
686
687 redef class AForExpr
688 redef fun decorate_tag(v, res, token)
689 do
690 if not token isa TId then return null
691 var vs = variables
692 if vs == null then return null
693 res.add_class("nc_v")
694 var idx = n_ids.index_of(token)
695 var variable = vs[idx]
696 return variable.infobox(v)
697 end
698 end
699
700 redef class AParam
701 redef fun decorate_tag(v, res, token)
702 do
703 var mp = mparameter
704 if mp == null then return null
705 var variable = self.variable
706 if variable == null then return null
707 res.add_class("nc_v")
708 return variable.infobox(v)
709 end
710 end
711
712 redef class AAssertExpr
713 redef fun decorate_tag(v, res, token)
714 do
715 res.add_class("nc_ast")
716 return null
717 end
718 end
719
720 redef class ALabel
721 redef fun decorate_tag(v, res, token)
722 do
723 res.add_class("nc_la")
724 return null
725 end
726 end
727
728 redef class ASendExpr
729 redef fun decorate_tag(v, res, token)
730 do
731 if callsite == null then return null
732 return callsite.infobox(v)
733 end
734 end
735
736 redef class ANewExpr
737 redef fun decorate_tag(v, res, token)
738 do
739 if callsite == null then return null
740 return callsite.infobox(v)
741 end
742 end
743
744 redef class AAssignOp
745 redef fun decorate_tag(v, res, token)
746 do
747 var p = parent
748 assert p isa AReassignFormExpr
749
750 var callsite = p.reassign_callsite
751 if callsite == null then return null
752 return callsite.infobox(v)
753 end
754 end
755
756 redef class AModuleName
757 redef fun decorate_tag(v, res, token)
758 do
759 return parent.decorate_tag(v, res, token)
760 end
761 end
762
763 redef class AModuledecl
764 redef fun decorate_tag(v, res, token)
765 do
766 res.add_class("nc_def")
767 res.add_class("nc_m")
768 var p = parent
769 assert p isa AModule
770 var mm = p.mmodule
771 if mm == null then return null
772 return mm.infobox(v)
773 end
774 end
775
776 redef class AStdImport
777 redef fun decorate_tag(v, res, token)
778 do
779 res.add_class("nc_m")
780 var mm = mmodule
781 if mm == null then return null
782 return mm.infobox(v)
783 end
784 end
785 redef class AAttrPropdef
786 redef fun decorate_tag(v, res, token)
787 do
788 res.add_class("nc_def")
789 var mpd: nullable MPropDef
790 mpd = mreadpropdef
791 if mpd == null then mpd = mpropdef
792 if mpd == null then return null
793 return mpd.infobox(v)
794 end
795 end
796
797 redef class TId
798 redef fun make_tag(v)
799 do
800 var res = super
801 var p = parent
802 if p != null then p.decorate_tag(v, res, self)
803 res.add_class("nc_i")
804 return res
805 end
806 end
807 redef class AMethid
808 redef fun make_tag(v)
809 do
810 var res = new HTMLTag("span")
811 res.add_class("nc_def")
812 return res
813 end
814 redef fun decorate_tag(v, res, token)
815 do
816 return null
817 # nothing to decorate
818 end
819 redef fun infobox(v)
820 do
821 var p = parent
822 if not p isa AMethPropdef then return null
823 var mpd = p.mpropdef
824 if mpd == null then return null
825 return mpd.infobox(v)
826 end
827 end
828 redef class TAttrid
829 redef fun make_tag(v)
830 do
831 var res = super
832 var p = parent
833 if p != null then p.decorate_tag(v, res, self)
834 res.add_class("nc_a")
835 return res
836 end
837 end
838 redef class AAttrFormExpr
839 redef fun decorate_tag(v, res, token)
840 do
841 var p = mproperty
842 if p == null then return null
843 return p.intro.infobox(v)
844 end
845 end
846 redef class TClassid
847 redef fun make_tag(v)
848 do
849 var res = super
850 var p = parent
851 if p != null then p.decorate_tag(v, res, self)
852 res.add_class("nc_t")
853 return res
854 end
855 end
856 redef class AType
857 redef fun decorate_tag(v, res, token)
858 do
859 var mt = mtype
860 if mt == null then return null
861 if mt isa MNullableType then mt = mt.mtype
862 if mt isa MVirtualType or mt isa MParameterType then
863 res.add_class("nc_vt")
864 end
865 return mt.infobox(v)
866 end
867 end
868 redef class AFormaldef
869 redef fun decorate_tag(v, res, token)
870 do
871 res.add_class("nc_vt")
872 if mtype == null then return null
873 return mtype.infobox(v)
874 end
875 end
876 redef class ATypePropdef
877 redef fun decorate_tag(v, res, token)
878 do
879 res.add_class("nc_def")
880 var md = mpropdef
881 if md == null then return null
882 return md.infobox(v)
883 end
884 end
885 redef class TComment
886 redef fun make_tag(v)
887 do
888 var res = super
889 if not parent isa ADoc then
890 res.add_class("nc_c")
891 end
892 return res
893 end
894 end
895 redef class ADoc
896 redef fun make_tag(v)
897 do
898 var res = new HTMLTag("span")
899 res.add_class("nc_d")
900 return res
901 end
902 end
903 redef class TokenLiteral
904 redef fun make_tag(v)
905 do
906 var res = super
907 res.add_class("nc_l")
908 var p = parent
909 if p != null then p.decorate_tag(v, res, self)
910 return res
911 end
912 end
913 redef class ASuperstringExpr
914 redef fun make_tag(v)
915 do
916 var res = new HTMLTag("span")
917 res.add_class("nc_ss")
918 return res
919 end
920 end
921 redef class AStringFormExpr
922 redef fun decorate_tag(v, res, token)
923 do
924 # Workaround to tag strings
925 res.classes.remove("nc_l")
926 res.add_class("nc_s")
927 return null
928 end
929 end
930 redef class AExpr
931 redef fun decorate_tag(v, res, token)
932 do
933 var t = mtype
934 if t == null then return null
935 return t.infobox(v)
936 end
937 end
938