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