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