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
24 # A standalone highlighted piece of code
28 # The highlighter used
29 var hl
: HighlightVisitor
34 # The pseudo source-file
35 var source
: SourceFile
37 # JavaScript code to update an existing codemirror editor.
38 fun code_mirror_update
: Template
41 var res
= new Template
43 function nitmessage() {
44 editor.operation(function(){
45 for (var i = 0; i < widgets.length; ++i)
46 editor.removeLineWidget(widgets[i]);
50 for m
in source
.messages
do
52 var l = document.createElement("div");
53 l.className = "lint-error"
54 l.innerHTML = "<span class='glyphicon glyphicon-warning-sign lint-error-icon'></span> {{{m.text.html_escape}}}";
55 var w = editor.addLineWidget({{{m.location.line_start-1}}}, l);
63 redef fun core_serialize_to
(v
)
65 v
.serialize_attribute
("code", hl
.html
.write_to_string
)
66 var msgs
= new Array[Map[String, Serializable]]
67 for m
in source
.messages
do
68 var o
= new Map[String, Serializable]
70 o
["line"] = m
.location
.line_start-1
73 v
.serialize_attribute
("messages", msgs
)
77 # Visitor used to produce a HTML tree based on a AST on a `Source`
78 class HighlightVisitor
79 # The root of the HTML hierarchy
80 var html
= new HTMLTag("span")
82 # Should the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
84 # Used to have a really huge and verbose HTML (mainly for debug)
85 var with_ast
= false is writable
87 # Prefixes used in generated IDs for line `<span>` elements.
88 # Useful if more than one highlighted code is present in the same HTML document.
90 # If set to the empty string, id for lines are disabled.
92 # Is `"L"` by default.
93 var line_id_prefix
= "L" is writable
95 # The first line to generate, null if start at the first line
96 var first_line
: nullable Int = null is writable
98 # The last line to generate, null if finish at the last line
99 var last_line
: nullable Int = null is writable
101 # When highlighting a node, show its messages (errors, warnings), if any.
104 var show_messages
= true is writable
106 # When highlighting a node, attach a full popupable infobox, if any.
108 # If `false`, only a simple `title` tooltip is used.
111 var show_infobox
= true is writable
113 # A reference to an entity used in generated `<a>` elements.
115 # It is used to refer to some specific entities when generating links.
116 # If `null` is returned, then no link are generated and `<a>` elements become `<span>`.
118 # By default, `null` is returned.
119 # Clients are therefore encouraged to redefine the method in a subclass to control where entities should link to.
120 fun hrefto
(entity
: MEntity): nullable String do return null
124 html
.add_class
("nitcode")
127 # When highlighting a node, also consider the loose tokens around it.
129 # Loose tokens are tokens discarded from the AST but attached before
130 # or after some non-loose tokens. See `Token::is_loose`.
132 # When this flag is set to `true`, the loose tokens that are before the
133 # first token and after the last token are also highlighted.
136 var include_loose_tokens
= false is writable
138 # When highlighting a node, the first and the last lines are fully included.
140 # If the highlighted node starts (or ends) in the middle of a line,
141 # this flags forces the whole line to be highlighted.
144 var include_whole_lines
= false is writable
146 # Highlight a AST element.
147 fun highlight_node
(n
: ANode)
160 if f
== null then return
162 if l
== null then return
165 if include_loose_tokens
then
166 if f
.prev_looses
.not_empty
then f
= f
.prev_looses
.first
167 if l
.next_looses
.not_empty
then l
= l
.next_looses
.last
170 var line
= first_line
172 while f
.location
.line_start
< line
do
174 if f
== null then return
180 while l
.location
.line_end
> line
do
182 if l
== null then return
186 if include_whole_lines
then
187 f
= f
.first_real_token_in_line
188 l
= l
.last_real_token_in_line
194 private fun full_tag
(anode
: ANode, hv
: HighlightVisitor): nullable HTMLTag
196 var tag
= anode
.make_tag
(hv
)
197 if tag
== null then return null
198 var infobox
= anode
.infobox
(hv
)
199 if infobox
== null and anode
isa Token then
200 var pa
= anode
.parent
202 infobox
= pa
.decorate_tag
(hv
, tag
, anode
)
205 if infobox
!= null and not show_infobox
then
206 tag
.attr
("title", infobox
.title
)
207 tag
.classes
.add
"titled"
210 var messages
= anode
.location
.messages
211 if messages
!= null and show_messages
then
212 tag
.css
("border-bottom", "solid 2px red")
213 if infobox
== null then
214 infobox
= new HInfoBox(hv
, "Messages")
216 var c
= infobox
.new_dropdown
("{messages.length} message(s)", "")
218 c
.open
("li").append
(m
.text
)
221 if infobox
!= null then
222 tag
.attach_infobox
(infobox
)
227 # Highlight a full lexed source file.
229 # REQUIRE `source.first_token != null`
230 fun highlight_source
(source
: SourceFile)
232 do_highlight
(source
.first_token
.as(not null), null)
235 # Low-level highlighting between 2 tokens
236 protected fun do_highlight
(first_token
: Token, last_token
: nullable Token)
238 var stack2
= new Array[HTMLTag]
239 var stack
= new Array[Prod]
241 var c
: nullable Token = first_token
246 # Handle start of line
247 var cline
= c
.location
.line_start
248 if cline
!= line
then
249 # Handle starting block productions,
250 # Because c could be a detached token, get prods in
251 # the first AST token
252 var c0
= c
.first_token_in_line
254 if c0
!= null then starting
= c0
.starting_prods
255 if starting
!= null then for p
in starting
do
256 if not p
.is_block
then continue
257 var tag
= full_tag
(p
, hv
)
258 if tag
== null then continue
259 tag
.add_class
("foldable")
266 # Add a div for the whole line
267 var tag
= new HTMLTag("span")
268 var p
= line_id_prefix
269 if p
!= "" then tag
.attrs
["id"] = "{p}{cline}"
270 tag
.classes
.add
"line"
277 # Add the blank, verbatim
278 html
.add_raw_html c
.blank_before
280 # Handle starting span production
281 starting
= c
.starting_prods
282 if starting
!= null then for p
in starting
do
283 if not p
.is_span
then continue
284 var tag
= full_tag
(p
, hv
)
285 if tag
== null then continue
296 var tag
= full_tag
(c
, hv
)
297 if tag
!= null then html
.add tag
300 # Handle ending span productions
301 var ending
= c
.ending_prods
302 if ending
!= null then for p
in ending
do
303 if not p
.is_span
then continue
304 if stack
.is_empty
or p
!= stack
.last
then continue
309 # Handle end of line and end of file
311 if c
== last_token
then n
= null
312 if n
== null or n
.location
.line_start
!= line
then
313 # closes the line div
316 # close the block production divs
317 var c0
= c
.last_token_in_line
319 if c0
!= null then ending
= c0
.ending_prods
320 if ending
!= null then for p
in ending
do
321 if not p
.is_block
then continue
322 if stack
.is_empty
or p
!= stack
.last
then continue
330 if not stack2
.is_empty
then html
= stack2
.first
333 # Return a default CSS content related to CSS classes used in the `html` tree.
334 # Could be inlined in the `.html` file of saved as a specific `.css` file.
335 fun css_content
: String
338 .nitcode a { color: inherit; cursor:pointer; }
339 .nitcode .titled:hover { text-decoration: underline; } /* underline titles */
340 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
341 .nitcode .foldable { display: block } /* for block productions*/
342 .nitcode .line{ display: block } /* for lines */
343 .nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
344 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
345 /* lexical raw tokens. independent of usage or semantic: */
346 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
347 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
348 .nitcode .nc_k { font-weight: bold; } /* keyword */
349 .nitcode .nc_o {} /* operator */
350 .nitcode .nc_i {} /* standard identifier */
351 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
352 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
353 .nitcode .nc_l { color: #009999; } /* char and number literal */
354 .nitcode .nc_s { color: #8F1546; } /* string literal */
355 /* syntactic token usage. added because of their position in the AST */
356 .nitcode .nc_ast { color: blue; } /* assert label */
357 .nitcode .nc_la { color: blue; } /* break/continue label */
358 .nitcode .nc_m { color: #445588; } /* module name */
359 /* syntactic groups */
360 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
361 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
362 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
363 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
364 .nitcode .nc_cdef {} /* A whole class definition */
365 .nitcode .nc_pdef {} /* A whole property definition */
366 /* semantic token usage */
367 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
368 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
370 .nitcode .nc_error { border: 1px red solid;} /* not used */
371 .popover { max-width: 800px !important; }
375 # Additional content to inject in the <head> tag
376 # Note: does not include `css_content`; handle it yourself.
377 fun head_content
: String
379 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
382 # Additional content to inject just before the closing </body> tag
383 fun foot_content
: String
386 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
387 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
388 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
391 # Fully process `content` as a Nit source file.
393 # Set `print_errors = true` to print errors in the code to the console.
394 fun highlightcode
(content
: String, print_errors
: nullable Bool): HLCode
396 # Prepare a stand-alone tool context
397 var tc
= new ToolContext
398 tc
.nit_dir
= tc
.locate_nit_dir
# still use the common lib to have core
399 tc
.keep_going
= true # no exit, obviously
400 if print_errors
!= true then tc
.opt_warn
.value
= -1 # no output
402 # Prepare an stand-alone model and model builder.
403 # Unfortunately, models are enclosing and append-only.
404 # There is no way (yet?) to have a shared module `core` with
405 # isolated and throwable user modules.
406 var model
= new Model
407 var mb
= new ModelBuilder(model
, tc
)
410 var source
= new SourceFile.from_string
("", content
+ "\n")
411 var lexer
= new Lexer(source
)
412 var parser
= new Parser(lexer
)
413 var tree
= parser
.parse
415 var hlcode
= new HLCode(self, content
, source
)
419 if eof
isa AError then
420 mb
.error
(eof
, eof
.message
)
421 highlight_source
(source
)
424 var amodule
= tree
.n_base
.as(not null)
426 # Load the AST as a module in the model
428 mb
.load_rt_module
(null, amodule
, "")
431 # Highlight the processed module
432 highlight_node
(amodule
)
438 # Attach the infobox to the node by using BootStrap popover
439 fun attach_infobox
(infobox
: HInfoBox)
441 classes
.add
("popupable")
442 attrs
["title"] = infobox
.title
443 var href
= infobox
.href
445 attrs
["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
447 attrs
["data-content"] = infobox
.content
.write_to_string
448 attrs
["data-toggle"] = "popover"
453 # A generic information container that can be used to decorate AST entities
455 # The visitor used for contextualisation, if needed
456 var visitor
: HighlightVisitor
458 # A short title for the AST element
461 # The primary link where the entity points
463 var href
: nullable String = null
465 # The content of the popuped infobox
466 var content
= new HTMLTag("div")
468 # Append a new field in the popuped infobox
469 fun new_field
(title
: String): HTMLTag
471 content
.open
("b").text
(title
)
473 var res
= content
.open
("span")
478 # Append a new dropdown in the popuped content
479 fun new_dropdown
(title
, text
: String, text_is_html
: nullable Bool): HTMLTag
481 content
.add_raw_html
"""<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
482 content
.append
(title
)
483 content
.add_raw_html
"</b> "
484 if text_is_html
== true then
485 content
.add_raw_html
(text
)
486 else content
.append
(text
)
487 content
.add_raw_html
"""<span class="caret"></span></a>"""
488 var res
= content
.open
("ul").add_class
("dropdown-menu").attr
("role", "menu").attr
("aria-labelledby", "dLabel")
489 content
.add_raw_html
"</div>"
496 # Model entity or whatever that can produce an infobox
497 interface HInfoBoxable
498 # An new infobox documenting the entity
499 fun infobox
(v
: HighlightVisitor): HInfoBox is abstract
503 # Append an entry for the doc in the given infobox
504 fun fill_infobox
(res
: HInfoBox)
506 if content
.length
< 2 then
507 res
.new_field
("doc").text
(content
.first
)
510 var c
= res
.new_dropdown
("doc", content
.first
)
511 for x
in content
.iterator
.skip_head
(1) do
513 c
.add_raw_html
"<br>"
521 # A HTML version of `to_s` with hyper-links.
523 # By default, `linkto_text(v, to_s)` is used, c.f. see `linkto_text`.
525 # For some complex entities, like generic types, multiple `<a>` and `<span>` elements can be generated.
526 # E.g. `Array[Int]` might become `<a>Array</a>[<a>Int</a>]` with the correct `href` attributes
527 # provided by `v.hrefto`.
528 fun linkto
(v
: HighlightVisitor): HTMLTag do return linkto_text
(v
, to_s
)
530 # Link to the `self` with a specific text.
532 # The whole text is linked with a single `<a>` element.
534 # The `href` used is provided by `v.hrefto`.
535 # If `href` is null then a `<span>` element is used instead of `<a>`.
536 fun linkto_text
(v
: HighlightVisitor, text
: String): HTMLTag
538 var href
= v
.hrefto
(self)
540 return (new HTMLTag("span")).text
(text
)
542 return (new HTMLTag("a")).attr
("href", href
).text
(text
)
545 # Append an entry for the doc in the given infobox
546 private fun add_doc_to_infobox
(res
: HInfoBox)
548 var mdoc
= mdoc_or_fallback
549 if mdoc
!= null then mdoc
.fill_infobox
(res
)
556 var res
= new HInfoBox(v
, "module {name}")
557 res
.href
= v
.hrefto
(self)
558 res
.new_field
("module").add
(linkto
(v
))
559 add_doc_to_infobox
(res
)
560 if in_importation
.greaters
.length
> 1 then
561 var c
= res
.new_dropdown
("imports", "{in_importation.greaters.length-1} modules")
562 for x
in in_importation
.greaters
do
563 if x
== self then continue
564 c
.open
("li").add x
.linkto
(v
)
570 redef fun linkto
(v
) do return linkto_text
(v
, name
)
573 redef class MClassDef
576 var res
= new HInfoBox(v
, "class {mclass.name}")
577 res
.href
= v
.hrefto
(self)
579 res
.new_field
("class").text
(mclass
.name
)
581 res
.new_field
("redef class").text
(mclass
.name
)
582 res
.new_field
("intro").add mclass
.intro
.linkto_text
(v
, "in {mclass.intro_mmodule.to_s}")
584 add_doc_to_infobox
(res
)
586 var in_hierarchy
= self.in_hierarchy
587 if in_hierarchy
== null then return res
589 if in_hierarchy
.greaters
.length
> 1 then
590 var c
= res
.new_dropdown
("hier", "super-classes")
591 for x
in in_hierarchy
.greaters
do
592 if x
== self then continue
593 if not x
.is_intro
then continue
594 c
.open
("li").add x
.linkto
(v
)
597 if in_hierarchy
.smallers
.length
> 1 then
598 var c
= res
.new_dropdown
("hier", "sub-classes")
599 for x
in in_hierarchy
.smallers
do
600 if x
== self then continue
601 if not x
.is_intro
then continue
602 c
.open
("li").add x
.linkto
(v
)
605 if mclass
.mclassdefs
.length
> 1 then
606 var c
= res
.new_dropdown
("redefs", "refinements")
607 for x
in mclass
.mclassdefs
do
608 if x
== self then continue
609 c
.open
("li").add x
.linkto_text
(v
, "in {x.mmodule}")
619 var res
= new HInfoBox(v
, to_s
)
620 res
.href
= v
.hrefto
(self)
621 if self isa MMethodDef then
622 var msignature
= self.msignature
623 if msignature
!= null then res
.new_field
("fun").append
(mproperty
.name
).add msignature
.linkto
(v
)
624 else if self isa MAttributeDef then
625 var static_mtype
= self.static_mtype
626 if static_mtype
!= null then res
.new_field
("fun").append
(mproperty
.name
).add static_mtype
.linkto
(v
)
627 else if self isa MVirtualTypeDef then
628 var bound
= self.bound
629 if bound
!= null then res
.new_field
("add").append
(mproperty
.name
).add bound
.linkto
(v
)
631 res
.new_field
("wat?").append
(mproperty
.name
)
636 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
638 add_doc_to_infobox
(res
)
639 if mproperty
.mpropdefs
.length
> 1 then
640 var c
= res
.new_dropdown
("redef", "redefinitions")
641 for x
in mproperty
.mpropdefs
do
642 c
.open
("li").add x
.linkto_text
(v
, "in {x.mclassdef}")
650 redef class MClassType
653 var res
= new HInfoBox(v
, to_s
)
654 res
.href
= v
.hrefto
(self)
655 res
.new_field
("class").add mclass
.intro
.linkto
(v
)
656 add_doc_to_infobox
(res
)
661 return mclass
.intro
.linkto
(v
)
664 redef class MVirtualType
667 var res
= new HInfoBox(v
, to_s
)
668 res
.href
= v
.hrefto
(mproperty
)
670 res
.new_field
("virtual type").add p
.intro
.linkto
(v
)
671 add_doc_to_infobox
(res
)
676 return mproperty
.intro
.linkto
(v
)
679 redef class MParameterType
682 var res
= new HInfoBox(v
, to_s
)
683 res
.new_field
("parameter type").append
("{name} from class ").add mclass
.intro
.linkto
(v
)
688 redef class MNullableType
691 return mtype
.infobox
(v
)
695 var res
= new HTMLTag("span")
696 res
.append
("nullable ").add
(mtype
.linkto
(v
))
701 redef class MNotNullType
704 return mtype
.infobox
(v
)
708 var res
= new HTMLTag("span")
709 res
.append
("not null ").add
(mtype
.linkto
(v
))
714 redef class MNullType
717 var res
= new HInfoBox(v
, to_s
)
722 var res
= new HTMLTag("span")
728 redef class MSignature
731 var res
= new HTMLTag("span")
733 if not mparameters
.is_empty
then
735 for p
in mparameters
do
743 res
.add p
.mtype
.linkto
(v
)
747 var ret
= return_mtype
750 res
.add ret
.linkto
(v
)
759 var res
= new HInfoBox(v
, "call {mpropdef}")
760 res
.href
= v
.hrefto
(mpropdef
)
761 res
.new_field
("call").add
(mpropdef
.linkto
(v
)).add
(msignature
.linkto
(v
))
762 if mpropdef
.is_intro
then
764 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
766 add_doc_to_infobox
(res
)
772 return mpropdef
.linkto
(v
)
780 var declared_type
= self.declared_type
781 if declared_type
== null then
782 var res
= new HInfoBox(v
, "{name}")
783 res
.new_field
("local var").append
("{name}")
786 var res
= new HInfoBox(v
, "{name}: {declared_type}")
787 res
.new_field
("local var").append
("{name}:").add
(declared_type
.linkto
(v
))
796 # Optionally creates a tag that encapsulate the AST element on HTML rendering
797 protected fun make_tag
(v
: HighlightVisitor): nullable HTMLTag do return null
799 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
800 protected fun decorate_tag
(v
: HighlightVisitor, res
: HTMLTag, token
: Token): nullable HInfoBox
802 #debug("no decoration for {token.inspect}")
803 #res.add_class("nc_error")
807 # Return a optional infobox
808 fun infobox
(v
: HighlightVisitor): nullable HInfoBox do return null
811 redef class AQclassid
812 redef fun decorate_tag
(v
, res
, token
)
814 if token
!= n_id
then return null
815 var parent
= self.parent
816 if parent
== null then return null
817 return parent
.decorate_tag
(v
, res
, token
)
822 redef fun decorate_tag
(v
, res
, token
)
824 if token
!= n_id
then return null
825 var parent
= self.parent
826 if parent
== null then return null
827 return parent
.decorate_tag
(v
, res
, token
)
831 redef class AStdClassdef
832 redef fun make_tag
(v
)
834 var res
= new HTMLTag("span")
835 res
.add_class
("nc_cdef")
837 if md
!= null then res
.attr
("id", md
.to_s
)
840 redef fun decorate_tag
(v
, res
, token
)
842 if not token
isa TClassid then return null
843 res
.add_class
("nc_def")
846 if md
== null then return null
851 redef fun make_tag
(v
)
853 var res
= new HTMLTag("span")
854 res
.add_class
("nc_pdef")
859 res
.attr
("id", mpd
.to_s
)
861 if self isa AAttrPropdef then
863 if mpd
!= null then res
.add
(tag
(mpd
))
865 if mpd
!= null then res
.add
(tag
(mpd
))
870 private fun tag
(mpd
: MPropDef): HTMLTag
872 var a
= new HTMLTag("a")
873 a
.attr
("id", mpd
.to_s
)
879 # Produce an HTMLTag with the correct contents and CSS classes
880 # Subclasses can redefine it to decorate the tag
881 redef fun make_tag
(v
): HTMLTag
883 var res
= new HTMLTag("span")
889 redef class TokenKeyword
890 redef fun make_tag
(v
)
893 res
.add_class
("nc_k")
897 redef class TokenOperator
898 redef fun make_tag
(v
)
901 res
.add_class
("nc_o")
906 redef class AVarFormExpr
907 redef fun decorate_tag
(v
, res
, token
)
909 if token
!= n_id
then return null
910 var variable
= self.variable
911 if variable
== null then return null
912 res
.add_class
("nc_v")
913 return variable
.infobox
(v
)
917 redef class AVardeclExpr
918 redef fun decorate_tag
(v
, res
, token
)
920 if token
!= n_id
then return null
921 var variable
= self.variable
922 if variable
== null then return null
923 res
.add_class
("nc_v")
924 return variable
.infobox
(v
)
928 redef class AForGroup
929 redef fun decorate_tag
(v
, res
, token
)
931 if not token
isa TId then return null
933 if vs
== null then return null
934 res
.add_class
("nc_v")
935 var idx
= n_ids
.index_of
(token
)
936 var variable
= vs
[idx
]
937 return variable
.infobox
(v
)
942 redef fun decorate_tag
(v
, res
, token
)
944 if token
!= n_id
then return null
946 if mp
== null then return null
947 var variable
= self.variable
948 if variable
== null then return null
949 res
.add_class
("nc_v")
950 return variable
.infobox
(v
)
954 redef class AAssertExpr
955 redef fun decorate_tag
(v
, res
, token
)
957 if not token
isa TId then return null
958 res
.add_class
("nc_ast")
964 redef fun decorate_tag
(v
, res
, token
)
966 if not token
isa TId then return null
967 res
.add_class
("nc_la")
972 redef class ASendExpr
973 redef fun decorate_tag
(v
, res
, token
)
975 var callsite
= self.callsite
976 if callsite
== null then return null
977 return callsite
.infobox
(v
)
982 redef fun decorate_tag
(v
, res
, token
)
984 var callsite
= self.callsite
985 if callsite
== null then return null
986 return callsite
.infobox
(v
)
990 redef class AAssignOp
991 redef fun decorate_tag
(v
, res
, token
)
994 assert p
isa AReassignFormExpr
996 var callsite
= p
.reassign_callsite
997 if callsite
== null then return null
998 return callsite
.infobox
(v
)
1002 redef class AModuleName
1003 redef fun decorate_tag
(v
, res
, token
)
1006 if p
== null then return null
1007 return p
.decorate_tag
(v
, res
, token
)
1011 redef class AModuledecl
1012 redef fun decorate_tag
(v
, res
, token
)
1014 if not token
isa TId then return null
1015 res
.add_class
("nc_def")
1016 res
.add_class
("nc_m")
1018 assert p
isa AModule
1020 if mm
== null then return null
1021 return mm
.infobox
(v
)
1025 redef class AStdImport
1026 redef fun decorate_tag
(v
, res
, token
)
1028 if not token
isa TId then return null
1029 res
.add_class
("nc_m")
1031 if mm
== null then return null
1032 return mm
.infobox
(v
)
1035 redef class AAttrPropdef
1036 redef fun decorate_tag
(v
, res
, token
)
1038 if not token
isa TId then return null
1039 res
.add_class
("nc_def")
1040 var mpd
: nullable MPropDef
1042 if mpd
== null then mpd
= mpropdef
1043 if mpd
== null then return null
1044 return mpd
.infobox
(v
)
1049 redef fun make_tag
(v
)
1052 res
.add_class
("nc_i")
1057 redef fun make_tag
(v
)
1059 var res
= new HTMLTag("span")
1060 res
.add_class
("nc_def")
1063 redef fun decorate_tag
(v
, res
, token
)
1066 # nothing to decorate
1068 redef fun infobox
(v
)
1071 if not p
isa AMethPropdef then return null
1072 var mpd
= p
.mpropdef
1073 if mpd
== null then return null
1074 return mpd
.infobox
(v
)
1078 redef fun make_tag
(v
)
1081 res
.add_class
("nc_a")
1085 redef class AAttrFormExpr
1086 redef fun decorate_tag
(v
, res
, token
)
1088 if not token
isa TAttrid then return null
1090 if p
== null then return null
1091 return p
.intro
.infobox
(v
)
1094 redef class TClassid
1095 redef fun make_tag
(v
)
1098 res
.add_class
("nc_t")
1103 redef fun decorate_tag
(v
, res
, token
)
1105 if not token
isa TClassid then return null
1107 if mt
== null then return null
1109 if mt
isa MFormalType then
1110 res
.add_class
("nc_vt")
1112 return mt
.infobox
(v
)
1115 redef class AFormaldef
1116 redef fun decorate_tag
(v
, res
, token
)
1118 if not token
isa TClassid then return null
1119 res
.add_class
("nc_vt")
1120 var mtype
= self.mtype
1121 if mtype
== null then return null
1122 return mtype
.infobox
(v
)
1125 redef class ATypePropdef
1126 redef fun decorate_tag
(v
, res
, token
)
1128 if not token
isa TClassid then return null
1129 res
.add_class
("nc_def")
1131 if md
== null then return null
1132 return md
.infobox
(v
)
1135 redef class TComment
1136 redef fun make_tag
(v
)
1140 res
.add_class
("nc_c")
1146 redef fun make_tag
(v
)
1148 var res
= new HTMLTag("span")
1149 res
.add_class
("nc_d")
1153 redef class TokenLiteral
1154 redef fun make_tag
(v
)
1157 res
.add_class
("nc_l")
1161 redef class ASuperstringExpr
1162 redef fun make_tag
(v
)
1164 var res
= new HTMLTag("span")
1165 res
.add_class
("nc_ss")
1169 redef class AStringFormExpr
1170 redef fun decorate_tag
(v
, res
, token
)
1172 # Workaround to tag strings
1173 res
.classes
.remove
("nc_l")
1174 res
.add_class
("nc_s")
1179 redef fun decorate_tag
(v
, res
, token
)
1182 if t
== null then return null