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