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