1 # This file is part of NIT ( http://www.nitlanguage.org ).
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 # Highlighting of Nit AST
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")
28 # Should the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
30 # Used to have a really huge and verbose HTML (mainly for debug)
31 var with_ast
= false is writable
33 # Prefixes used in generated IDs for line `<span>` elements.
34 # Useful if more than one highlighted code is present in the same HTML document.
36 # If set to the empty string, id for lines are disabled.
38 # Is `"L"` by default.
39 var line_id_prefix
= "L" is writable
41 # The first line to generate, null if start at the first line
42 var first_line
: nullable Int = null is writable
44 # The last line to generate, null if finish at the last line
45 var last_line
: nullable Int = null is writable
47 # When highlighting a node, show its messages (errors, warnings), if any.
50 var show_messages
= true is writable
52 # When highlighting a node, attach a full popupable infobox, if any.
54 # If `false`, only a simple `title` tooltip is used.
57 var show_infobox
= true is writable
59 # A reference to an entity used in generated `<a>` elements.
61 # It is used to refer to some specific entities when generating links.
62 # If `null` is returned, then no link are generated and `<a>` elements become `<span>`.
64 # By default, `null` is returned.
65 # Clients are therefore encouraged to redefine the method in a subclass to control where entities should link to.
66 fun hrefto
(entity
: MEntity): nullable String do return null
70 html
.add_class
("nitcode")
73 # When highlighting a node, also consider the loose tokens around it.
75 # Loose tokens are tokens discarded from the AST but attached before
76 # or after some non-loose tokens. See `Token::is_loose`.
78 # When this flag is set to `true`, the loose tokens that are before the
79 # first token and after the last token are also highlighted.
82 var include_loose_tokens
= false is writable
84 # When highlighting a node, the first and the last lines are fully included.
86 # If the highlighted node starts (or ends) in the middle of a line,
87 # this flags forces the whole line to be highlighted.
90 var include_whole_lines
= false is writable
92 # The entry-point of the highlighting.
93 # Will fill `html` with the generated HTML content.
94 fun enter_visit
(n
: ANode)
107 if f
== null then return
109 if l
== null then return
112 if include_loose_tokens
then
113 if f
.prev_looses
.not_empty
then f
= f
.prev_looses
.first
114 if l
.next_looses
.not_empty
then l
= l
.next_looses
.last
117 var line
= first_line
119 while f
.location
.line_start
< line
do
121 if f
== null then return
127 while l
.location
.line_end
> line
do
129 if l
== null then return
133 if include_whole_lines
then
134 f
= f
.first_real_token_in_line
135 l
= l
.last_real_token_in_line
141 private fun full_tag
(anode
: ANode, hv
: HighlightVisitor): nullable HTMLTag
143 var tag
= anode
.make_tag
(hv
)
144 if tag
== null then return null
145 var infobox
= anode
.infobox
(hv
)
146 if infobox
== null and anode
isa Token then
147 var pa
= anode
.parent
149 infobox
= pa
.decorate_tag
(hv
, tag
, anode
)
152 if infobox
!= null and not show_infobox
then
153 tag
.attr
("title", infobox
.title
)
154 tag
.classes
.add
"titled"
157 var messages
= anode
.location
.messages
158 if messages
!= null and show_messages
then
159 tag
.css
("border-bottom", "solid 2px red")
160 if infobox
== null then
161 infobox
= new HInfoBox(hv
, "Messages")
163 var c
= infobox
.new_dropdown
("{messages.length} message(s)", "")
165 c
.open
("li").append
(m
.text
)
168 if infobox
!= null then
169 tag
.attach_infobox
(infobox
)
174 # Highlight a full lexed source file.
176 # REQUIRE `source.first_token != null`
177 fun hightlight_source
(source
: SourceFile)
179 htmlize
(source
.first_token
.as(not null), null)
182 # Produce HTML between two tokens
183 protected fun htmlize
(first_token
: Token, last_token
: nullable Token)
185 var stack2
= new Array[HTMLTag]
186 var stack
= new Array[Prod]
188 var c
: nullable Token = first_token
193 # Handle start of line
194 var cline
= c
.location
.line_start
195 if cline
!= line
then
196 # Handle starting block productions,
197 # Because c could be a detached token, get prods in
198 # the first AST token
199 var c0
= c
.first_token_in_line
201 if c0
!= null then starting
= c0
.starting_prods
202 if starting
!= null then for p
in starting
do
203 if not p
.is_block
then continue
204 var tag
= full_tag
(p
, hv
)
205 if tag
== null then continue
206 tag
.add_class
("foldable")
213 # Add a div for the whole line
214 var tag
= new HTMLTag("span")
215 var p
= line_id_prefix
216 if p
!= "" then tag
.attrs
["id"] = "{p}{cline}"
217 tag
.classes
.add
"line"
224 # Add the blank, verbatim
225 html
.add_raw_html c
.blank_before
227 # Handle starting span production
228 starting
= c
.starting_prods
229 if starting
!= null then for p
in starting
do
230 if not p
.is_span
then continue
231 var tag
= full_tag
(p
, hv
)
232 if tag
== null then continue
243 var tag
= full_tag
(c
, hv
)
244 if tag
!= null then html
.add tag
247 # Handle ending span productions
248 var ending
= c
.ending_prods
249 if ending
!= null then for p
in ending
do
250 if not p
.is_span
then continue
251 if stack
.is_empty
or p
!= stack
.last
then continue
256 # Handle end of line and end of file
258 if c
== last_token
then n
= null
259 if n
== null or n
.location
.line_start
!= line
then
260 # closes the line div
263 # close the block production divs
264 var c0
= c
.last_token_in_line
266 if c0
!= null then ending
= c0
.ending_prods
267 if ending
!= null then for p
in ending
do
268 if not p
.is_block
then continue
269 if stack
.is_empty
or p
!= stack
.last
then continue
277 if not stack2
.is_empty
then html
= stack2
.first
280 # Return a default CSS content related to CSS classes used in the `html` tree.
281 # Could be inlined in the `.html` file of saved as a specific `.css` file.
282 fun css_content
: String
285 .nitcode a { color: inherit; cursor:pointer; }
286 .nitcode .titled:hover { text-decoration: underline; } /* underline titles */
287 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
288 .nitcode .foldable { display: block } /* for block productions*/
289 .nitcode .line{ display: block } /* for lines */
290 .nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
291 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
292 /* lexical raw tokens. independent of usage or semantic: */
293 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
294 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
295 .nitcode .nc_k { font-weight: bold; } /* keyword */
296 .nitcode .nc_o {} /* operator */
297 .nitcode .nc_i {} /* standard identifier */
298 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
299 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
300 .nitcode .nc_l { color: #009999; } /* char and number literal */
301 .nitcode .nc_s { color: #8F1546; } /* string literal */
302 /* syntactic token usage. added because of their position in the AST */
303 .nitcode .nc_ast { color: blue; } /* assert label */
304 .nitcode .nc_la { color: blue; } /* break/continue label */
305 .nitcode .nc_m { color: #445588; } /* module name */
306 /* syntactic groups */
307 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
308 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
309 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
310 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
311 .nitcode .nc_cdef {} /* A whole class definition */
312 .nitcode .nc_pdef {} /* A whole property definition */
313 /* semantic token usage */
314 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
315 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
317 .nitcode .nc_error { border: 1px red solid;} /* not used */
318 .popover { max-width: 800px !important; }
322 # Additional content to inject in the <head> tag
323 # Note: does not include `css_content`; handle it yourself.
324 fun head_content
: String
326 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
329 # Additional content to inject just before the closing </body> tag
330 fun foot_content
: String
333 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
334 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
335 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
340 # Attach the infobox to the node by using BootStrap popover
341 fun attach_infobox
(infobox
: HInfoBox)
343 classes
.add
("popupable")
344 attrs
["title"] = infobox
.title
345 var href
= infobox
.href
347 attrs
["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
349 attrs
["data-content"] = infobox
.content
.write_to_string
350 attrs
["data-toggle"] = "popover"
355 # A generic information container that can be used to decorate AST entities
357 # The visitor used for contextualisation, if needed
358 var visitor
: HighlightVisitor
360 # A short title for the AST element
363 # The primary link where the entity points
365 var href
: nullable String = null
367 # The content of the popuped infobox
368 var content
= new HTMLTag("div")
370 # Append a new field in the popuped infobox
371 fun new_field
(title
: String): HTMLTag
373 content
.open
("b").text
(title
)
375 var res
= content
.open
("span")
380 # Append a new dropdown in the popuped content
381 fun new_dropdown
(title
, text
: String, text_is_html
: nullable Bool): HTMLTag
383 content
.add_raw_html
"""<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
384 content
.append
(title
)
385 content
.add_raw_html
"</b> "
386 if text_is_html
== true then
387 content
.add_raw_html
(text
)
388 else content
.append
(text
)
389 content
.add_raw_html
"""<span class="caret"></span></a>"""
390 var res
= content
.open
("ul").add_class
("dropdown-menu").attr
("role", "menu").attr
("aria-labelledby", "dLabel")
391 content
.add_raw_html
"</div>"
398 # Model entity or whatever that can produce an infobox
399 interface HInfoBoxable
400 # An new infobox documenting the entity
401 fun infobox
(v
: HighlightVisitor): HInfoBox is abstract
405 # Append an entry for the doc in the given infobox
406 fun fill_infobox
(res
: HInfoBox)
408 if content
.length
< 2 then
409 res
.new_field
("doc").text
(content
.first
)
412 var c
= res
.new_dropdown
("doc", content
.first
)
413 for x
in content
.iterator
.skip_head
(1) do
415 c
.add_raw_html
"<br>"
423 # A HTML version of `to_s` with hyper-links.
425 # By default, `linkto_text(v, to_s)` is used, c.f. see `linkto_text`.
427 # For some complex entities, like generic types, multiple `<a>` and `<span>` elements can be generated.
428 # E.g. `Array[Int]` might become `<a>Array</a>[<a>Int</a>]` with the correct `href` attributes
429 # provided by `v.hrefto`.
430 fun linkto
(v
: HighlightVisitor): HTMLTag do return linkto_text
(v
, to_s
)
432 # Link to the `self` with a specific text.
434 # The whole text is linked with a single `<a>` element.
436 # The `href` used is provided by `v.hrefto`.
437 # If `href` is null then a `<span>` element is used instead of `<a>`.
438 fun linkto_text
(v
: HighlightVisitor, text
: String): HTMLTag
440 var href
= v
.hrefto
(self)
442 return (new HTMLTag("span")).text
(text
)
444 return (new HTMLTag("a")).attr
("href", href
).text
(text
)
447 # Append an entry for the doc in the given infobox
448 private fun add_doc_to_infobox
(res
: HInfoBox)
450 var mdoc
= mdoc_or_fallback
451 if mdoc
!= null then mdoc
.fill_infobox
(res
)
458 var res
= new HInfoBox(v
, "module {name}")
459 res
.href
= v
.hrefto
(self)
460 res
.new_field
("module").add
(linkto
(v
))
461 add_doc_to_infobox
(res
)
462 if in_importation
.greaters
.length
> 1 then
463 var c
= res
.new_dropdown
("imports", "{in_importation.greaters.length-1} modules")
464 for x
in in_importation
.greaters
do
465 if x
== self then continue
466 c
.open
("li").add x
.linkto
(v
)
472 redef fun linkto
(v
) do return linkto_text
(v
, name
)
475 redef class MClassDef
478 var res
= new HInfoBox(v
, "class {mclass.name}")
479 res
.href
= v
.hrefto
(self)
481 res
.new_field
("class").text
(mclass
.name
)
483 res
.new_field
("redef class").text
(mclass
.name
)
484 res
.new_field
("intro").add mclass
.intro
.linkto_text
(v
, "in {mclass.intro_mmodule.to_s}")
486 add_doc_to_infobox
(res
)
488 var in_hierarchy
= self.in_hierarchy
489 if in_hierarchy
== null then return res
491 if in_hierarchy
.greaters
.length
> 1 then
492 var c
= res
.new_dropdown
("hier", "super-classes")
493 for x
in in_hierarchy
.greaters
do
494 if x
== self then continue
495 if not x
.is_intro
then continue
496 c
.open
("li").add x
.linkto
(v
)
499 if in_hierarchy
.smallers
.length
> 1 then
500 var c
= res
.new_dropdown
("hier", "sub-classes")
501 for x
in in_hierarchy
.smallers
do
502 if x
== self then continue
503 if not x
.is_intro
then continue
504 c
.open
("li").add x
.linkto
(v
)
507 if mclass
.mclassdefs
.length
> 1 then
508 var c
= res
.new_dropdown
("redefs", "refinements")
509 for x
in mclass
.mclassdefs
do
510 if x
== self then continue
511 c
.open
("li").add x
.linkto_text
(v
, "in {x.mmodule}")
521 var res
= new HInfoBox(v
, to_s
)
522 res
.href
= v
.hrefto
(self)
523 if self isa MMethodDef then
524 var msignature
= self.msignature
525 if msignature
!= null then res
.new_field
("fun").append
(mproperty
.name
).add msignature
.linkto
(v
)
526 else if self isa MAttributeDef then
527 var static_mtype
= self.static_mtype
528 if static_mtype
!= null then res
.new_field
("fun").append
(mproperty
.name
).add static_mtype
.linkto
(v
)
529 else if self isa MVirtualTypeDef then
530 var bound
= self.bound
531 if bound
!= null then res
.new_field
("add").append
(mproperty
.name
).add bound
.linkto
(v
)
533 res
.new_field
("wat?").append
(mproperty
.name
)
538 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
540 add_doc_to_infobox
(res
)
541 if mproperty
.mpropdefs
.length
> 1 then
542 var c
= res
.new_dropdown
("redef", "redefinitions")
543 for x
in mproperty
.mpropdefs
do
544 c
.open
("li").add x
.linkto_text
(v
, "in {x.mclassdef}")
552 redef class MClassType
555 var res
= new HInfoBox(v
, to_s
)
556 res
.href
= v
.hrefto
(self)
557 res
.new_field
("class").add mclass
.intro
.linkto
(v
)
558 add_doc_to_infobox
(res
)
563 return mclass
.intro
.linkto
(v
)
566 redef class MVirtualType
569 var res
= new HInfoBox(v
, to_s
)
570 res
.href
= v
.hrefto
(mproperty
)
572 res
.new_field
("virtual type").add p
.intro
.linkto
(v
)
573 add_doc_to_infobox
(res
)
578 return mproperty
.intro
.linkto
(v
)
581 redef class MParameterType
584 var res
= new HInfoBox(v
, to_s
)
585 res
.new_field
("parameter type").append
("{name} from class ").add mclass
.intro
.linkto
(v
)
590 redef class MNullableType
593 return mtype
.infobox
(v
)
597 var res
= new HTMLTag("span")
598 res
.append
("nullable ").add
(mtype
.linkto
(v
))
603 redef class MNotNullType
606 return mtype
.infobox
(v
)
610 var res
= new HTMLTag("span")
611 res
.append
("not null ").add
(mtype
.linkto
(v
))
616 redef class MNullType
619 var res
= new HInfoBox(v
, to_s
)
624 var res
= new HTMLTag("span")
630 redef class MSignature
633 var res
= new HTMLTag("span")
635 if not mparameters
.is_empty
then
637 for p
in mparameters
do
645 res
.add p
.mtype
.linkto
(v
)
649 var ret
= return_mtype
652 res
.add ret
.linkto
(v
)
661 var res
= new HInfoBox(v
, "call {mpropdef}")
662 res
.href
= v
.hrefto
(mpropdef
)
663 res
.new_field
("call").add
(mpropdef
.linkto
(v
)).add
(msignature
.linkto
(v
))
664 if mpropdef
.is_intro
then
666 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
668 add_doc_to_infobox
(res
)
674 return mpropdef
.linkto
(v
)
682 var declared_type
= self.declared_type
683 if declared_type
== null then
684 var res
= new HInfoBox(v
, "{name}")
685 res
.new_field
("local var").append
("{name}")
688 var res
= new HInfoBox(v
, "{name}: {declared_type}")
689 res
.new_field
("local var").append
("{name}:").add
(declared_type
.linkto
(v
))
698 # Optionally creates a tag that encapsulate the AST element on HTML rendering
699 protected fun make_tag
(v
: HighlightVisitor): nullable HTMLTag do return null
701 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
702 protected fun decorate_tag
(v
: HighlightVisitor, res
: HTMLTag, token
: Token): nullable HInfoBox
704 #debug("no decoration for {token.inspect}")
705 #res.add_class("nc_error")
709 # Return a optional infobox
710 fun infobox
(v
: HighlightVisitor): nullable HInfoBox do return null
713 redef class AQclassid
714 redef fun decorate_tag
(v
, res
, token
)
716 if token
!= n_id
then return null
717 var parent
= self.parent
718 if parent
== null then return null
719 return parent
.decorate_tag
(v
, res
, token
)
724 redef fun decorate_tag
(v
, res
, token
)
726 if token
!= n_id
then return null
727 var parent
= self.parent
728 if parent
== null then return null
729 return parent
.decorate_tag
(v
, res
, token
)
733 redef class AStdClassdef
734 redef fun make_tag
(v
)
736 var res
= new HTMLTag("span")
737 res
.add_class
("nc_cdef")
739 if md
!= null then res
.attr
("id", md
.to_s
)
742 redef fun decorate_tag
(v
, res
, token
)
744 if not token
isa TClassid then return null
745 res
.add_class
("nc_def")
748 if md
== null then return null
753 redef fun make_tag
(v
)
755 var res
= new HTMLTag("span")
756 res
.add_class
("nc_pdef")
761 res
.attr
("id", mpd
.to_s
)
763 if self isa AAttrPropdef then
765 if mpd
!= null then res
.add
(tag
(mpd
))
767 if mpd
!= null then res
.add
(tag
(mpd
))
772 private fun tag
(mpd
: MPropDef): HTMLTag
774 var a
= new HTMLTag("a")
775 a
.attr
("id", mpd
.to_s
)
781 # Produce an HTMLTag with the correct contents and CSS classes
782 # Subclasses can redefine it to decorate the tag
783 redef fun make_tag
(v
): HTMLTag
785 var res
= new HTMLTag("span")
791 redef class TokenKeyword
792 redef fun make_tag
(v
)
795 res
.add_class
("nc_k")
799 redef class TokenOperator
800 redef fun make_tag
(v
)
803 res
.add_class
("nc_o")
808 redef class AVarFormExpr
809 redef fun decorate_tag
(v
, res
, token
)
811 if token
!= n_id
then return null
812 var variable
= self.variable
813 if variable
== null then return null
814 res
.add_class
("nc_v")
815 return variable
.infobox
(v
)
819 redef class AVardeclExpr
820 redef fun decorate_tag
(v
, res
, token
)
822 if token
!= n_id
then return null
823 var variable
= self.variable
824 if variable
== null then return null
825 res
.add_class
("nc_v")
826 return variable
.infobox
(v
)
830 redef class AForGroup
831 redef fun decorate_tag
(v
, res
, token
)
833 if not token
isa TId then return null
835 if vs
== null then return null
836 res
.add_class
("nc_v")
837 var idx
= n_ids
.index_of
(token
)
838 var variable
= vs
[idx
]
839 return variable
.infobox
(v
)
844 redef fun decorate_tag
(v
, res
, token
)
846 if token
!= n_id
then return null
848 if mp
== null then return null
849 var variable
= self.variable
850 if variable
== null then return null
851 res
.add_class
("nc_v")
852 return variable
.infobox
(v
)
856 redef class AAssertExpr
857 redef fun decorate_tag
(v
, res
, token
)
859 if not token
isa TId then return null
860 res
.add_class
("nc_ast")
866 redef fun decorate_tag
(v
, res
, token
)
868 if not token
isa TId then return null
869 res
.add_class
("nc_la")
874 redef class ASendExpr
875 redef fun decorate_tag
(v
, res
, token
)
877 var callsite
= self.callsite
878 if callsite
== null then return null
879 return callsite
.infobox
(v
)
884 redef fun decorate_tag
(v
, res
, token
)
886 var callsite
= self.callsite
887 if callsite
== null then return null
888 return callsite
.infobox
(v
)
892 redef class AAssignOp
893 redef fun decorate_tag
(v
, res
, token
)
896 assert p
isa AReassignFormExpr
898 var callsite
= p
.reassign_callsite
899 if callsite
== null then return null
900 return callsite
.infobox
(v
)
904 redef class AModuleName
905 redef fun decorate_tag
(v
, res
, token
)
908 if p
== null then return null
909 return p
.decorate_tag
(v
, res
, token
)
913 redef class AModuledecl
914 redef fun decorate_tag
(v
, res
, token
)
916 if not token
isa TId then return null
917 res
.add_class
("nc_def")
918 res
.add_class
("nc_m")
922 if mm
== null then return null
927 redef class AStdImport
928 redef fun decorate_tag
(v
, res
, token
)
930 if not token
isa TId then return null
931 res
.add_class
("nc_m")
933 if mm
== null then return null
937 redef class AAttrPropdef
938 redef fun decorate_tag
(v
, res
, token
)
940 if not token
isa TId then return null
941 res
.add_class
("nc_def")
942 var mpd
: nullable MPropDef
944 if mpd
== null then mpd
= mpropdef
945 if mpd
== null then return null
946 return mpd
.infobox
(v
)
951 redef fun make_tag
(v
)
954 res
.add_class
("nc_i")
959 redef fun make_tag
(v
)
961 var res
= new HTMLTag("span")
962 res
.add_class
("nc_def")
965 redef fun decorate_tag
(v
, res
, token
)
968 # nothing to decorate
973 if not p
isa AMethPropdef then return null
975 if mpd
== null then return null
976 return mpd
.infobox
(v
)
980 redef fun make_tag
(v
)
983 res
.add_class
("nc_a")
987 redef class AAttrFormExpr
988 redef fun decorate_tag
(v
, res
, token
)
990 if not token
isa TAttrid then return null
992 if p
== null then return null
993 return p
.intro
.infobox
(v
)
997 redef fun make_tag
(v
)
1000 res
.add_class
("nc_t")
1005 redef fun decorate_tag
(v
, res
, token
)
1007 if not token
isa TClassid then return null
1009 if mt
== null then return null
1011 if mt
isa MFormalType then
1012 res
.add_class
("nc_vt")
1014 return mt
.infobox
(v
)
1017 redef class AFormaldef
1018 redef fun decorate_tag
(v
, res
, token
)
1020 if not token
isa TClassid then return null
1021 res
.add_class
("nc_vt")
1022 var mtype
= self.mtype
1023 if mtype
== null then return null
1024 return mtype
.infobox
(v
)
1027 redef class ATypePropdef
1028 redef fun decorate_tag
(v
, res
, token
)
1030 if not token
isa TClassid then return null
1031 res
.add_class
("nc_def")
1033 if md
== null then return null
1034 return md
.infobox
(v
)
1037 redef class TComment
1038 redef fun make_tag
(v
)
1042 res
.add_class
("nc_c")
1048 redef fun make_tag
(v
)
1050 var res
= new HTMLTag("span")
1051 res
.add_class
("nc_d")
1055 redef class TokenLiteral
1056 redef fun make_tag
(v
)
1059 res
.add_class
("nc_l")
1063 redef class ASuperstringExpr
1064 redef fun make_tag
(v
)
1066 var res
= new HTMLTag("span")
1067 res
.add_class
("nc_ss")
1071 redef class AStringFormExpr
1072 redef fun decorate_tag
(v
, res
, token
)
1074 # Workaround to tag strings
1075 res
.classes
.remove
("nc_l")
1076 res
.add_class
("nc_s")
1081 redef fun decorate_tag
(v
, res
, token
)
1084 if t
== null then return null