highlight: rewrite using astutil and with infoboxes
[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 .nitcode .foldable { display: block } /* for block productions*/
171 .nitcode .line{ display: block } /* for lines */
172 .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 end
204
205 redef class HTMLTag
206 # Attach the infobox to the node by using BootStrap popover
207 fun attach_infobox(infobox: HInfoBox)
208 do
209 classes.add("popupable")
210 attrs["title"] = infobox.title
211 var href = infobox.href
212 if href != null then
213 attrs["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
214 end
215 attrs["data-content"] = infobox.content.write_to_string
216 attrs["data-toggle"] = "popover"
217 end
218 end
219
220
221 # A generic information container that can be used to decorate AST entities
222 class HInfoBox
223 # The visitor used for contextualisation, if needed
224 var visitor: HighlightVisitor
225
226 # A short title for the AST element
227 var title: String
228
229 # The primary link where the entity points
230 # null if no link
231 var href: nullable String = null
232
233 # The content of the popuped infobox
234 var content = new HTMLTag("div")
235
236 # Append a new field in the popuped infobox
237 fun new_field(title: String): HTMLTag
238 do
239 content.open("b").text(title)
240 content.append(" ")
241 var res = content.open("span")
242 content.open("br")
243 return res
244 end
245
246 # Append a new dropdown in the popuped content
247 fun new_dropdown(title, text: String): HTMLTag
248 do
249 content.add_raw_html """<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
250 content.append(title)
251 content.add_raw_html "</b> "
252 content.append(text)
253 content.add_raw_html """<span class="caret"></span></a>"""
254 var res = content.open("ul").add_class("dropdown-menu").attr("role", "menu").attr("aria-labelledby", "dLabel")
255 content.add_raw_html "</div>"
256 return res
257 end
258 end
259
260 ##
261
262 # Model entity or whatever that can produce an infobox
263 interface HInfoBoxable
264 # An new infobox documenting the entity
265 fun infobox(v: HighlightVisitor): HInfoBox is abstract
266
267 # A human-readable hyper-text for the entity
268 fun linkto: HTMLTag is abstract
269 end
270
271 redef class MDoc
272 # Append an entry for the doc in the given infobox
273 fun fill_infobox(res: HInfoBox)
274 do
275 if content.length < 2 then
276 res.new_field("doc").text(content.first)
277 return
278 end
279 var c = res.new_dropdown("doc", content.first)
280 for x in content.iterator.skip_head(1) do
281 c.append x
282 c.add_raw_html "<br>"
283 end
284 end
285 end
286
287 redef class MEntity
288 super HInfoBoxable
289 end
290
291 redef class MModule
292 redef fun infobox(v)
293 do
294 var res = new HInfoBox(v, "module {name}")
295 res.href = href
296 res.new_field("module").add(linkto)
297 var mdoc = self.mdoc
298 if mdoc != null then mdoc.fill_infobox(res)
299 if in_importation.greaters.length > 1 then
300 var c = res.new_dropdown("imports", "{in_importation.greaters.length-1} modules")
301 for x in in_importation.greaters do
302 if x == self then continue
303 c.open("li").add x.linkto
304 end
305 end
306 return res
307 end
308
309 fun href: String
310 do
311 return name + ".html"
312 end
313
314 redef fun linkto do return linkto_text(name)
315
316 # Link to the entitiy with a specific text
317 fun linkto_text(text: String): HTMLTag
318 do
319 return (new HTMLTag("a")).attr("href", href).text(text)
320 end
321 end
322
323 redef class MClassDef
324 redef fun infobox(v)
325 do
326 var res = new HInfoBox(v, "class {mclass.name}")
327 res.href = href
328 if is_intro then
329 res.new_field("class").text(mclass.name)
330 else
331 res.new_field("redef class").text(mclass.name)
332 res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
333 end
334 var mdoc = self.mdoc
335 if mdoc == null then mdoc = mclass.intro.mdoc
336 if mdoc != null then mdoc.fill_infobox(res)
337
338 if in_hierarchy.greaters.length > 1 then
339 var c = res.new_dropdown("hier", "super-classes")
340 for x in in_hierarchy.greaters do
341 if x == self then continue
342 if not x.is_intro then continue
343 c.open("li").add x.linkto
344 end
345 end
346 if in_hierarchy.smallers.length > 1 then
347 var c = res.new_dropdown("hier", "sub-classes")
348 for x in in_hierarchy.smallers do
349 if x == self then continue
350 if not x.is_intro then continue
351 c.open("li").add x.linkto
352 end
353 end
354 if mclass.mclassdefs.length > 1 then
355 var c = res.new_dropdown("redefs", "refinements")
356 for x in mclass.mclassdefs do
357 if x == self then continue
358 c.open("li").add x.linkto_text("in {x.mmodule}")
359 end
360 end
361 return res
362 end
363
364 fun href: String
365 do
366 return mmodule.href + "#" + to_s
367 end
368
369 redef fun linkto do return linkto_text(mclass.name)
370
371 # Link to the entitiy with a specific text
372 fun linkto_text(text: String): HTMLTag
373 do
374 return (new HTMLTag("a")).attr("href", href).text(text)
375 end
376 end
377
378 redef class MPropDef
379 redef fun infobox(v)
380 do
381 var res = new HInfoBox(v, to_s)
382 res.href = href
383 if self isa MMethodDef then
384 res.new_field("fun").append(mproperty.name).add msignature.linkto
385 else if self isa MAttributeDef then
386 res.new_field("fun").append(mproperty.name).add static_mtype.linkto
387 else if self isa MVirtualTypeDef then
388 res.new_field("add").append(mproperty.name).add bound.linkto
389 else
390 res.new_field("wat?").append(mproperty.name)
391 end
392
393 if is_intro then
394 else
395 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
396 end
397 var mdoc = self.mdoc
398 if mdoc == null then mdoc = mproperty.intro.mdoc
399 if mdoc != null then mdoc.fill_infobox(res)
400 if mproperty.mpropdefs.length > 1 then
401 var c = res.new_dropdown("redef", "redefinitions")
402 for x in mproperty.mpropdefs do
403 c.open("li").add x.linkto_text("in {x.mclassdef}")
404 end
405 end
406
407 return res
408 end
409
410 fun href: String
411 do
412 return self.mclassdef.mmodule.href + "#" + self.to_s
413 end
414
415 redef fun linkto do return linkto_text(mproperty.name)
416
417 # Link to the entitiy with a specific text
418 fun linkto_text(text: String): HTMLTag
419 do
420 return (new HTMLTag("a")).attr("href", href).text(text)
421 end
422 end
423
424 redef class MClassType
425 redef fun infobox(v)
426 do
427 var res = new HInfoBox(v, to_s)
428 res.href = mclass.intro.href
429 res.new_field("class").add mclass.intro.linkto
430 var mdoc = mclass.mdoc
431 if mdoc == null then mdoc = mclass.intro.mdoc
432 if mdoc != null then mdoc.fill_infobox(res)
433 return res
434 end
435 redef fun linkto
436 do
437 return mclass.intro.linkto
438 end
439 end
440 redef class MVirtualType
441 redef fun infobox(v)
442 do
443 var res = new HInfoBox(v, to_s)
444 res.href = mproperty.intro.href
445 var p = mproperty
446 var pd = p.intro
447 res.new_field("virtual type").add pd.linkto
448 var mdoc = pd.mdoc
449 if mdoc != null then mdoc.fill_infobox(res)
450 return res
451 end
452 redef fun linkto
453 do
454 return mproperty.intro.linkto
455 end
456 end
457 redef class MParameterType
458 redef fun infobox(v)
459 do
460 var res = new HInfoBox(v, to_s)
461 var name = mclass.intro.parameter_names[rank]
462 res.new_field("parameter type").append("{name} from class ").add mclass.intro.linkto
463 return res
464 end
465 redef fun linkto
466 do
467 var name = mclass.intro.parameter_names[rank]
468 return (new HTMLTag("span")).text(name)
469 end
470 end
471
472 redef class MNullableType
473 redef fun infobox(v)
474 do
475 return mtype.infobox(v)
476 end
477 redef fun linkto
478 do
479 var res = new HTMLTag("span")
480 res.append("nullable ").add(mtype.linkto)
481 return res
482 end
483 end
484
485 redef class MSignature
486 redef fun linkto
487 do
488 var res = new HTMLTag("span")
489 var first = true
490 if not mparameters.is_empty then
491 res.append "("
492 for p in mparameters do
493 if first then
494 first = false
495 else
496 res.append ", "
497 end
498 res.append p.name
499 res.append ": "
500 res.add p.mtype.linkto
501 end
502 res.append ")"
503 end
504 var ret = return_mtype
505 if ret != null then
506 res.append ": "
507 res.add ret.linkto
508 end
509 return res
510 end
511 end
512
513 redef class CallSite
514 super HInfoBoxable
515 redef fun infobox(v)
516 do
517 var res = new HInfoBox(v, "call {mpropdef}")
518 res.href = mpropdef.href
519 res.new_field("call").add(mpropdef.linkto).add(msignature.linkto)
520 if mpropdef.is_intro then
521 else
522 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
523 end
524 var mdoc = mpropdef.mdoc
525 if mdoc == null then mdoc = mproperty.intro.mdoc
526 if mdoc != null then mdoc.fill_infobox(res)
527
528 return res
529 end
530 redef fun linkto
531 do
532 return mpropdef.linkto
533 end
534 end
535
536 redef class Variable
537 super HInfoBoxable
538 redef fun infobox(v)
539 do
540 if declared_type == null then
541 var res = new HInfoBox(v, "{name}")
542 res.new_field("local var").append("{name}")
543 return res
544 end
545 var res = new HInfoBox(v, "{name}: {declared_type}")
546 res.new_field("local var").append("{name}:").add(declared_type.linkto)
547 return res
548 end
549 redef fun linkto
550 do
551 return (new HTMLTag("span")).text(name)
552 end
553 end
554
555
556 ##
557
558 redef class ANode
559 # Optionally creates a tag that encapsulate the AST element on HTML rendering
560 protected fun make_tag(v: HighlightVisitor): nullable HTMLTag do return null
561
562 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
563 protected fun decorate_tag(v: HighlightVisitor, res: HTMLTag, token: Token): nullable HInfoBox
564 do
565 #debug("no decoration for {token.inspect}")
566 #res.add_class("nc_error")
567 return null
568 end
569
570 # Return a optional infobox
571 fun infobox(v: HighlightVisitor): nullable HInfoBox do return null
572 end
573
574 redef class AStdClassdef
575 redef fun make_tag(v)
576 do
577 var res = new HTMLTag("span")
578 res.add_class("nc_cdef")
579 var md = mclassdef
580 if md != null then res.attr("id", md.to_s)
581 return res
582 end
583 redef fun decorate_tag(v, res, token)
584 do
585 res.add_class("nc_def")
586
587 var md = mclassdef
588 if md == null then return null
589 return md.infobox(v)
590 end
591 end
592 redef class APropdef
593 redef fun make_tag(v)
594 do
595 var res = new HTMLTag("span")
596 res.add_class("nc_pdef")
597 var mpd
598 mpd = mpropdef
599 if mpd != null then
600 #res.add(tag(mpd))
601 res.attr("id", mpd.to_s)
602 end
603 if self isa AAttrPropdef then
604 mpd = mreadpropdef
605 if mpd != null then res.add(tag(mpd))
606 mpd = mwritepropdef
607 if mpd != null then res.add(tag(mpd))
608 end
609 return res
610 end
611
612 private fun tag(mpd: MPropDef): HTMLTag
613 do
614 var a = new HTMLTag("a")
615 a.attr("id", mpd.to_s)
616 return a
617 end
618 end
619
620 redef class Token
621 # Produce an HTMLTag with the correct contents and CSS classes
622 # Subclasses can redefine it to decorate the tag
623 redef fun make_tag(v: HighlightVisitor): HTMLTag
624 do
625 var res = new HTMLTag("span")
626 res.text(text)
627 return res
628 end
629 end
630
631 redef class TokenKeyword
632 redef fun make_tag(v)
633 do
634 var res = super
635 res.add_class("nc_k")
636 return res
637 end
638 end
639 redef class TokenOperator
640 redef fun make_tag(v)
641 do
642 var res = super
643 var p = parent
644 if p != null then p.decorate_tag(v, res, self)
645 res.add_class("nc_o")
646 return res
647 end
648 end
649
650 redef class AVarFormExpr
651 redef fun decorate_tag(v, res, token)
652 do
653 res.add_class("nc_v")
654 var variable = self.variable
655 if variable == null then return null
656 return variable.infobox(v)
657 end
658 end
659
660 redef class AVardeclExpr
661 redef fun decorate_tag(v, res, token)
662 do
663 res.add_class("nc_v")
664 var variable = self.variable
665 if variable == null then return null
666 return variable.infobox(v)
667 end
668 end
669
670 redef class AForExpr
671 redef fun decorate_tag(v, res, token)
672 do
673 if not token isa TId then return null
674 res.add_class("nc_v")
675 var vs = variables
676 if vs == null then return null
677 var idx = n_ids.index_of(token)
678 var variable = vs[idx]
679 return variable.infobox(v)
680 end
681 end
682
683 redef class AParam
684 redef fun decorate_tag(v, res, token)
685 do
686 res.add_class("nc_v")
687 var mp = mparameter
688 if mp == null then return null
689 var variable = self.variable
690 if variable == null then return null
691 return variable.infobox(v)
692 end
693 end
694
695 redef class AAssertExpr
696 redef fun decorate_tag(v, res, token)
697 do
698 res.add_class("nc_ast")
699 return null
700 end
701 end
702
703 redef class ALabel
704 redef fun decorate_tag(v, res, token)
705 do
706 res.add_class("nc_la")
707 return null
708 end
709 end
710
711 redef class ASendExpr
712 redef fun decorate_tag(v, res, token)
713 do
714 if callsite == null then return null
715 return callsite.infobox(v)
716 end
717 end
718
719 redef class ANewExpr
720 redef fun decorate_tag(v, res, token)
721 do
722 if callsite == null then return null
723 return callsite.infobox(v)
724 end
725 end
726
727 redef class AAssignOp
728 redef fun decorate_tag(v, res, token)
729 do
730 var p = parent
731 assert p isa AReassignFormExpr
732
733 var callsite = p.reassign_callsite
734 if callsite == null then return null
735 return callsite.infobox(v)
736 end
737 end
738
739 redef class AModuleName
740 redef fun decorate_tag(v, res, token)
741 do
742 return parent.decorate_tag(v, res, token)
743 end
744 end
745
746 redef class AModuledecl
747 redef fun decorate_tag(v, res, token)
748 do
749 res.add_class("nc_def")
750 res.add_class("nc_m")
751 var p = parent
752 assert p isa AModule
753 var mm = p.mmodule
754 if mm == null then return null
755 return mm.infobox(v)
756 end
757 end
758
759 redef class AStdImport
760 redef fun decorate_tag(v, res, token)
761 do
762 res.add_class("nc_m")
763 var mm = mmodule
764 if mm == null then return null
765 return mm.infobox(v)
766 end
767 end
768 redef class AAttrPropdef
769 redef fun decorate_tag(v, res, token)
770 do
771 res.add_class("nc_def")
772 var mpd: nullable MPropDef
773 mpd = mreadpropdef
774 if mpd == null then mpd = mpropdef
775 if mpd == null then return null
776 return mpd.infobox(v)
777 end
778 end
779
780 redef class TId
781 redef fun make_tag(v)
782 do
783 var res = super
784 var p = parent
785 if p != null then p.decorate_tag(v, res, self)
786 res.add_class("nc_i")
787 return res
788 end
789 end
790 redef class AMethid
791 redef fun make_tag(v)
792 do
793 var res = new HTMLTag("span")
794 res.add_class("nc_def")
795 return res
796 end
797 redef fun decorate_tag(v, res, token)
798 do
799 return null
800 # nothing to decorate
801 end
802 redef fun infobox(v)
803 do
804 var p = parent
805 if not p isa AMethPropdef then return null
806 var mpd = p.mpropdef
807 if mpd == null then return null
808 return mpd.infobox(v)
809 end
810 end
811 redef class TAttrid
812 redef fun make_tag(v)
813 do
814 var res = super
815 var p = parent
816 if p != null then p.decorate_tag(v, res, self)
817 res.add_class("nc_a")
818 return res
819 end
820 end
821 redef class AAttrFormExpr
822 redef fun decorate_tag(v, res, token)
823 do
824 var p = mproperty
825 if p == null then return null
826 return p.intro.infobox(v)
827 end
828 end
829 redef class TClassid
830 redef fun make_tag(v)
831 do
832 var res = super
833 var p = parent
834 if p != null then p.decorate_tag(v, res, self)
835 res.add_class("nc_t")
836 return res
837 end
838 end
839 redef class AType
840 redef fun decorate_tag(v, res, token)
841 do
842 var mt = mtype
843 if mt == null then return null
844 if mt isa MNullableType then mt = mt.mtype
845 if mt isa MVirtualType or mt isa MParameterType then
846 res.add_class("nc_vt")
847 end
848 return mt.infobox(v)
849 end
850 end
851 redef class AFormaldef
852 redef fun decorate_tag(v, res, token)
853 do
854 res.add_class("nc_vt")
855 if mtype == null then return null
856 return mtype.infobox(v)
857 end
858 end
859 redef class ATypePropdef
860 redef fun decorate_tag(v, res, token)
861 do
862 res.add_class("nc_def")
863 var md = mpropdef
864 if md == null then return null
865 return md.infobox(v)
866 end
867 end
868 redef class TComment
869 redef fun make_tag(v)
870 do
871 var res = super
872 if not parent isa ADoc then
873 res.add_class("nc_c")
874 end
875 return res
876 end
877 end
878 redef class ADoc
879 redef fun make_tag(v)
880 do
881 var res = new HTMLTag("span")
882 res.add_class("nc_d")
883 return res
884 end
885 end
886 redef class TokenLiteral
887 redef fun make_tag(v)
888 do
889 var res = super
890 res.add_class("nc_l")
891 var p = parent
892 if p != null then p.decorate_tag(v, res, self)
893 return res
894 end
895 end
896 redef class ASuperstringExpr
897 redef fun make_tag(v)
898 do
899 var res = new HTMLTag("span")
900 res.add_class("nc_ss")
901 return res
902 end
903 end
904 redef class AStringFormExpr
905 redef fun decorate_tag(v, res, token)
906 do
907 # Workaround to tag strings
908 res.classes.remove("nc_l")
909 res.add_class("nc_s")
910 return null
911 end
912 end
913 redef class AExpr
914 redef fun decorate_tag(v, res, token)
915 do
916 var t = mtype
917 if t == null then return null
918 return t.infobox(v)
919 end
920 end
921