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 with HTML
23 # A standalone highlighted piece of code
27 # The highlighter used
28 var hl
: HtmlightVisitor
33 # The pseudo source-file
34 var source
: SourceFile
36 # JavaScript code to update an existing codemirror editor.
37 fun code_mirror_update
: Template
40 var res
= new Template
42 function nitmessage() {
43 editor.operation(function(){
44 for (var i = 0; i < widgets.length; ++i)
45 editor.removeLineWidget(widgets[i]);
49 for m
in source
.messages
do
51 var l = document.createElement("div");
52 l.className = "lint-error"
53 l.innerHTML = "<span class='glyphicon glyphicon-warning-sign lint-error-icon'></span> {{{m.text.html_escape}}}";
54 var w = editor.addLineWidget({{{m.location.line_start-1}}}, l);
62 redef fun core_serialize_to
(v
)
64 v
.serialize_attribute
("code", hl
.html
.write_to_string
)
65 var msgs
= new Array[Map[String, Serializable]]
66 for m
in source
.messages
do
67 var o
= new Map[String, Serializable]
69 o
["line"] = m
.location
.line_start-1
72 v
.serialize_attribute
("messages", msgs
)
76 # Visitor used to produce a HTML tree based on a AST on a `Source`
78 super AbstractHighlightVisitor
80 # The root of the HTML hierarchy
81 var html
= new HTMLTag("span")
83 # Should the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
85 # Used to have a really huge and verbose HTML (mainly for debug)
86 var with_ast
= false is writable
88 # Prefixes used in generated IDs for line `<span>` elements.
89 # Useful if more than one highlighted code is present in the same HTML document.
91 # If set to the empty string, id for lines are disabled.
93 # Is `"L"` by default.
94 var line_id_prefix
= "L" is writable
96 # When highlighting a node, attach a full popupable infobox, if any.
98 # If `false`, only a simple `title` tooltip is used.
101 var show_infobox
= true is writable
103 # A reference to an entity used in generated `<a>` elements.
105 # It is used to refer to some specific entities when generating links.
106 # If `null` is returned, then no link are generated and `<a>` elements become `<span>`.
108 # By default, `null` is returned.
109 # Clients are therefore encouraged to redefine the method in a subclass to control where entities should link to.
110 fun hrefto
(entity
: MEntity): nullable String do return null
114 html
.add_class
("nitcode")
117 private fun full_tag
(anode
: ANode): nullable HTMLTag
119 var tag
= anode
.make_tag
(self)
120 if tag
== null then return null
121 var infobox
= anode
.infobox
(self)
122 if infobox
== null and anode
isa Token then
123 var pa
= anode
.parent
125 infobox
= pa
.decorate_tag
(self, tag
, anode
)
128 if infobox
!= null and not show_infobox
then
129 var href
= infobox
.href
131 # If there is an href, we inject a link around
132 var tag2
= new HTMLTag("a")
135 tag
.attr
("href", href
)
137 tag
.attr
("title", infobox
.title
)
138 tag
.classes
.add
"titled"
141 var messages
= anode
.location
.messages
142 if messages
!= null and show_messages
then
143 tag
.css
("border-bottom", "solid 2px red")
144 if infobox
== null then
145 infobox
= new HInfoBox(self, "Messages")
147 var c
= infobox
.new_dropdown
("{messages.length} message(s)", "")
149 c
.open
("li").append
(m
.text
)
152 if infobox
!= null then
153 tag
.attach_infobox
(infobox
)
158 # Low-level highlighting between 2 tokens
159 redef fun do_highlight
(first_token
, last_token
)
161 var stack2
= new Array[HTMLTag]
162 var stack
= new Array[Prod]
164 var c
: nullable Token = first_token
168 # Handle start of line
169 var cline
= c
.location
.line_start
170 if cline
!= line
then
171 # Handle starting block productions,
172 # Because c could be a detached token, get prods in
173 # the first AST token
174 var c0
= c
.first_token_in_line
176 if c0
!= null then starting
= c0
.starting_prods
177 if starting
!= null then for p
in starting
do
178 if not p
.is_block
then continue
179 var tag
= full_tag
(p
)
180 if tag
== null then continue
181 tag
.add_class
("foldable")
188 # Add a div for the whole line
189 var tag
= new HTMLTag("span")
190 var p
= line_id_prefix
191 if p
!= "" then tag
.attrs
["id"] = "{p}{cline}"
192 tag
.classes
.add
"line"
199 # Add the blank, verbatim
200 html
.add_raw_html c
.blank_before
202 # Handle starting span production
203 starting
= c
.starting_prods
204 if starting
!= null then for p
in starting
do
205 if not p
.is_span
then continue
206 var tag
= full_tag
(p
)
207 if tag
== null then continue
218 var tag
= full_tag
(c
)
219 if tag
!= null then html
.add tag
222 # Handle ending span productions
223 var ending
= c
.ending_prods
224 if ending
!= null then for p
in ending
do
225 if not p
.is_span
then continue
226 if stack
.is_empty
or p
!= stack
.last
then continue
231 # Handle end of line and end of file
233 if c
== last_token
then n
= null
234 if n
== null or n
.location
.line_start
!= line
then
235 # closes the line div
238 # close the block production divs
239 var c0
= c
.last_token_in_line
241 if c0
!= null then ending
= c0
.ending_prods
242 if ending
!= null then for p
in ending
do
243 if not p
.is_block
then continue
244 if stack
.is_empty
or p
!= stack
.last
then continue
252 if not stack2
.is_empty
then html
= stack2
.first
255 # Return a default CSS content related to CSS classes used in the `html` tree.
256 # Could be inlined in the `.html` file of saved as a specific `.css` file.
257 fun css_content
: String
260 .nitcode a { color: inherit; cursor:pointer; }
261 .nitcode .titled:hover { text-decoration: underline; } /* underline titles */
262 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
263 .nitcode .foldable { display: block } /* for block productions*/
264 .nitcode .line{ display: block } /* for lines */
265 .nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
266 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
267 /* lexical raw tokens. independent of usage or semantic: */
268 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
269 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
270 .nitcode .nc_k { font-weight: bold; } /* keyword */
271 .nitcode .nc_o {} /* operator */
272 .nitcode .nc_i {} /* standard identifier */
273 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
274 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
275 .nitcode .nc_l { color: #009999; } /* char and number literal */
276 .nitcode .nc_s { color: #8F1546; } /* string literal */
277 /* syntactic token usage. added because of their position in the AST */
278 .nitcode .nc_ast { color: blue; } /* assert label */
279 .nitcode .nc_la { color: blue; } /* break/continue label */
280 .nitcode .nc_m { color: #445588; } /* module name */
281 /* syntactic groups */
282 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
283 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
284 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
285 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
286 .nitcode .nc_cdef {} /* A whole class definition */
287 .nitcode .nc_pdef {} /* A whole property definition */
288 /* semantic token usage */
289 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
290 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
292 .nitcode .nc_error { border: 1px red solid;} /* not used */
293 .popover { max-width: 800px !important; }
297 # Additional content to inject in the <head> tag
298 # Note: does not include `css_content`; handle it yourself.
299 fun head_content
: String
301 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
304 # Additional content to inject just before the closing </body> tag
305 fun foot_content
: String
308 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
309 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
310 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
313 # Fully process `content` as a Nit source file.
315 # Set `print_errors = true` to print errors in the code to the console.
316 fun highlightcode
(content
: String, print_errors
: nullable Bool): HLCode
318 # Prepare a stand-alone tool context
319 var tc
= new ToolContext
320 tc
.nit_dir
= tc
.locate_nit_dir
# still use the common lib to have core
321 tc
.keep_going
= true # no exit, obviously
322 if print_errors
!= true then tc
.opt_warn
.value
= -1 # no output
324 # Prepare an stand-alone model and model builder.
325 # Unfortunately, models are enclosing and append-only.
326 # There is no way (yet?) to have a shared module `core` with
327 # isolated and throwable user modules.
328 var model
= new Model
329 var mb
= new ModelBuilder(model
, tc
)
332 var source
= new SourceFile.from_string
("", content
+ "\n")
333 var lexer
= new Lexer(source
)
334 var parser
= new Parser(lexer
)
335 var tree
= parser
.parse
337 var hlcode
= new HLCode(self, content
, source
)
341 if eof
isa AError then
342 mb
.error
(eof
, eof
.message
)
343 highlight_source
(source
)
346 var amodule
= tree
.n_base
.as(not null)
348 # Load the AST as a module in the model
350 mb
.load_rt_module
(null, amodule
, "")
353 # Highlight the processed module
354 highlight_node
(amodule
)
360 # Attach the infobox to the node by using BootStrap popover
361 fun attach_infobox
(infobox
: HInfoBox)
363 classes
.add
("popupable")
364 attrs
["title"] = infobox
.title
365 var href
= infobox
.href
367 attrs
["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
369 attrs
["data-content"] = infobox
.content
.write_to_string
370 attrs
["data-toggle"] = "popover"
375 # A generic information container that can be used to decorate AST entities
377 # The visitor used for contextualisation, if needed
378 var visitor
: HtmlightVisitor
380 # A short title for the AST element
383 # The primary link where the entity points
385 var href
: nullable String = null
387 # The content of the popuped infobox
388 var content
= new HTMLTag("div")
390 # Append a new field in the popuped infobox
391 fun new_field
(title
: String): HTMLTag
393 content
.open
("b").text
(title
)
395 var res
= content
.open
("span")
400 # Append a new dropdown in the popuped content
401 fun new_dropdown
(title
, text
: String, text_is_html
: nullable Bool): HTMLTag
403 content
.add_raw_html
"""<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
404 content
.append
(title
)
405 content
.add_raw_html
"</b> "
406 if text_is_html
== true then
407 content
.add_raw_html
(text
)
408 else content
.append
(text
)
409 content
.add_raw_html
"""<span class="caret"></span></a>"""
410 var res
= content
.open
("ul").add_class
("dropdown-menu").attr
("role", "menu").attr
("aria-labelledby", "dLabel")
411 content
.add_raw_html
"</div>"
418 # Model entity or whatever that can produce an infobox
419 interface HInfoBoxable
420 # An new infobox documenting the entity
421 fun infobox
(v
: HtmlightVisitor): HInfoBox is abstract
425 # Append an entry for the doc in the given infobox
426 fun fill_infobox
(res
: HInfoBox)
428 if content
.length
< 2 then
429 res
.new_field
("doc").text
(content
.first
)
432 var c
= res
.new_dropdown
("doc", content
.first
)
433 for x
in content
.iterator
.skip_head
(1) do
435 c
.add_raw_html
"<br>"
443 # A HTML version of `to_s` with hyper-links.
445 # By default, `linkto_text(v, to_s)` is used, c.f. see `linkto_text`.
447 # For some complex entities, like generic types, multiple `<a>` and `<span>` elements can be generated.
448 # E.g. `Array[Int]` might become `<a>Array</a>[<a>Int</a>]` with the correct `href` attributes
449 # provided by `v.hrefto`.
450 fun linkto
(v
: HtmlightVisitor): HTMLTag do return linkto_text
(v
, to_s
)
452 # Link to the `self` with a specific text.
454 # The whole text is linked with a single `<a>` element.
456 # The `href` used is provided by `v.hrefto`.
457 # If `href` is null then a `<span>` element is used instead of `<a>`.
458 fun linkto_text
(v
: HtmlightVisitor, text
: String): HTMLTag
460 var href
= v
.hrefto
(self)
462 return (new HTMLTag("span")).text
(text
)
464 return (new HTMLTag("a")).attr
("href", href
).text
(text
)
467 # Append an entry for the doc in the given infobox
468 private fun add_doc_to_infobox
(res
: HInfoBox)
470 var mdoc
= mdoc_or_fallback
471 if mdoc
!= null then mdoc
.fill_infobox
(res
)
478 var res
= new HInfoBox(v
, "module {name}")
479 res
.href
= v
.hrefto
(self)
480 if not v
.show_infobox
then return res
481 res
.new_field
("module").add
(linkto
(v
))
482 add_doc_to_infobox
(res
)
483 if in_importation
.greaters
.length
> 1 then
484 var c
= res
.new_dropdown
("imports", "{in_importation.greaters.length-1} modules")
485 for x
in in_importation
.greaters
do
486 if x
== self then continue
487 c
.open
("li").add x
.linkto
(v
)
493 redef fun linkto
(v
) do return linkto_text
(v
, name
)
496 redef class MClassDef
499 var res
= new HInfoBox(v
, "class {mclass.name}")
500 res
.href
= v
.hrefto
(self)
501 if not v
.show_infobox
then return res
503 res
.new_field
("class").text
(mclass
.name
)
505 res
.new_field
("redef class").text
(mclass
.name
)
506 res
.new_field
("intro").add mclass
.intro
.linkto_text
(v
, "in {mclass.intro_mmodule.to_s}")
508 add_doc_to_infobox
(res
)
510 var in_hierarchy
= self.in_hierarchy
511 if in_hierarchy
== null then return res
513 if in_hierarchy
.greaters
.length
> 1 then
514 var c
= res
.new_dropdown
("hier", "super-classes")
515 for x
in in_hierarchy
.greaters
do
516 if x
== self then continue
517 if not x
.is_intro
then continue
518 c
.open
("li").add x
.linkto
(v
)
521 if in_hierarchy
.smallers
.length
> 1 then
522 var c
= res
.new_dropdown
("hier", "sub-classes")
523 for x
in in_hierarchy
.smallers
do
524 if x
== self then continue
525 if not x
.is_intro
then continue
526 c
.open
("li").add x
.linkto
(v
)
529 if mclass
.mclassdefs
.length
> 1 then
530 var c
= res
.new_dropdown
("redefs", "refinements")
531 for x
in mclass
.mclassdefs
do
532 if x
== self then continue
533 c
.open
("li").add x
.linkto_text
(v
, "in {x.mmodule}")
543 var res
= new HInfoBox(v
, to_s
)
544 res
.href
= v
.hrefto
(self)
545 if not v
.show_infobox
then return res
546 if self isa MMethodDef then
547 var msignature
= self.msignature
548 if msignature
!= null then res
.new_field
("fun").append
(mproperty
.name
).add msignature
.linkto
(v
)
549 else if self isa MAttributeDef then
550 var static_mtype
= self.static_mtype
551 if static_mtype
!= null then res
.new_field
("fun").append
(mproperty
.name
).add static_mtype
.linkto
(v
)
552 else if self isa MVirtualTypeDef then
553 var bound
= self.bound
554 if bound
!= null then res
.new_field
("add").append
(mproperty
.name
).add bound
.linkto
(v
)
556 res
.new_field
("wat?").append
(mproperty
.name
)
561 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
563 add_doc_to_infobox
(res
)
564 if mproperty
.mpropdefs
.length
> 1 then
565 var c
= res
.new_dropdown
("redef", "redefinitions")
566 for x
in mproperty
.mpropdefs
do
567 c
.open
("li").add x
.linkto_text
(v
, "in {x.mclassdef}")
575 redef class MClassType
578 var res
= new HInfoBox(v
, to_s
)
579 res
.href
= v
.hrefto
(mclass
.intro
)
580 if not v
.show_infobox
then return res
581 res
.new_field
("class").add mclass
.intro
.linkto
(v
)
582 add_doc_to_infobox
(res
)
587 return mclass
.intro
.linkto
(v
)
590 redef class MVirtualType
593 var res
= new HInfoBox(v
, to_s
)
594 res
.href
= v
.hrefto
(mproperty
)
595 if not v
.show_infobox
then return res
597 res
.new_field
("virtual type").add p
.intro
.linkto
(v
)
598 add_doc_to_infobox
(res
)
603 return mproperty
.intro
.linkto
(v
)
606 redef class MParameterType
609 var res
= new HInfoBox(v
, to_s
)
610 if not v
.show_infobox
then return res
611 res
.new_field
("parameter type").append
("{name} from class ").add mclass
.intro
.linkto
(v
)
616 redef class MNullableType
619 return mtype
.infobox
(v
)
623 var res
= new HTMLTag("span")
624 res
.append
("nullable ").add
(mtype
.linkto
(v
))
629 redef class MNotNullType
632 return mtype
.infobox
(v
)
636 var res
= new HTMLTag("span")
637 res
.append
("not null ").add
(mtype
.linkto
(v
))
642 redef class MNullType
645 var res
= new HInfoBox(v
, to_s
)
650 var res
= new HTMLTag("span")
656 redef class MSignature
659 var res
= new HTMLTag("span")
661 if not mparameters
.is_empty
then
663 for p
in mparameters
do
671 res
.add p
.mtype
.linkto
(v
)
675 var ret
= return_mtype
678 res
.add ret
.linkto
(v
)
687 var res
= new HInfoBox(v
, "call {mpropdef}")
688 res
.href
= v
.hrefto
(mpropdef
)
689 if not v
.show_infobox
then return res
690 res
.new_field
("call").add
(mpropdef
.linkto
(v
)).add
(msignature
.linkto
(v
))
691 if mpropdef
.is_intro
then
693 res
.new_field
("intro").add mproperty
.intro
.linkto_text
(v
, "in {mproperty.intro.mclassdef}")
695 add_doc_to_infobox
(res
)
701 return mpropdef
.linkto
(v
)
709 var declared_type
= self.declared_type
710 if declared_type
== null then
711 var res
= new HInfoBox(v
, "{name}")
712 res
.new_field
("local var").append
("{name}")
715 var res
= new HInfoBox(v
, "{name}: {declared_type}")
716 res
.new_field
("local var").append
("{name}:").add
(declared_type
.linkto
(v
))
725 # Optionally creates a tag that encapsulate the AST element on HTML rendering
726 protected fun make_tag
(v
: HtmlightVisitor): nullable HTMLTag do return null
728 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
729 protected fun decorate_tag
(v
: HtmlightVisitor, res
: HTMLTag, token
: Token): nullable HInfoBox
731 #debug("no decoration for {token.inspect}")
732 #res.add_class("nc_error")
736 # Return a optional infobox
737 fun infobox
(v
: HtmlightVisitor): nullable HInfoBox do return null
740 redef class AQclassid
741 redef fun decorate_tag
(v
, res
, token
)
743 if token
!= n_id
then return null
744 var parent
= self.parent
745 if parent
== null then return null
746 return parent
.decorate_tag
(v
, res
, token
)
751 redef fun decorate_tag
(v
, res
, token
)
753 if token
!= n_id
then return null
754 var parent
= self.parent
755 if parent
== null then return null
756 return parent
.decorate_tag
(v
, res
, token
)
760 redef class AStdClassdef
761 redef fun make_tag
(v
)
763 var res
= new HTMLTag("span")
764 res
.add_class
("nc_cdef")
766 if md
!= null then res
.attr
("id", md
.to_s
)
769 redef fun decorate_tag
(v
, res
, token
)
771 if not token
isa TClassid then return null
772 res
.add_class
("nc_def")
775 if md
== null then return null
780 redef fun make_tag
(v
)
782 var res
= new HTMLTag("span")
783 res
.add_class
("nc_pdef")
788 res
.attr
("id", mpd
.to_s
)
790 if self isa AAttrPropdef then
792 if mpd
!= null then res
.add
(tag
(mpd
))
794 if mpd
!= null then res
.add
(tag
(mpd
))
799 private fun tag
(mpd
: MPropDef): HTMLTag
801 var a
= new HTMLTag("a")
802 a
.attr
("id", mpd
.to_s
)
808 # Produce an HTMLTag with the correct contents and CSS classes
809 # Subclasses can redefine it to decorate the tag
810 redef fun make_tag
(v
): HTMLTag
812 var res
= new HTMLTag("span")
818 redef class TokenKeyword
819 redef fun make_tag
(v
)
822 res
.add_class
("nc_k")
826 redef class TokenOperator
827 redef fun make_tag
(v
)
830 res
.add_class
("nc_o")
835 redef class AVarFormExpr
836 redef fun decorate_tag
(v
, res
, token
)
838 if token
!= n_id
then return null
839 var variable
= self.variable
840 if variable
== null then return null
841 res
.add_class
("nc_v")
842 return variable
.infobox
(v
)
846 redef class AVardeclExpr
847 redef fun decorate_tag
(v
, res
, token
)
849 if token
!= n_id
then return null
850 var variable
= self.variable
851 if variable
== null then return null
852 res
.add_class
("nc_v")
853 return variable
.infobox
(v
)
857 redef class AForGroup
858 redef fun decorate_tag
(v
, res
, token
)
860 if not token
isa TId then return null
862 if vs
== null then return null
863 res
.add_class
("nc_v")
864 var idx
= n_ids
.index_of
(token
)
865 var variable
= vs
[idx
]
866 return variable
.infobox
(v
)
871 redef fun decorate_tag
(v
, res
, token
)
873 if token
!= n_id
then return null
875 if mp
== null then return null
876 var variable
= self.variable
877 if variable
== null then return null
878 res
.add_class
("nc_v")
879 return variable
.infobox
(v
)
883 redef class AAssertExpr
884 redef fun decorate_tag
(v
, res
, token
)
886 if not token
isa TId then return null
887 res
.add_class
("nc_ast")
893 redef fun decorate_tag
(v
, res
, token
)
895 if not token
isa TId then return null
896 res
.add_class
("nc_la")
901 redef class ASendExpr
902 redef fun decorate_tag
(v
, res
, token
)
904 var callsite
= self.callsite
905 if callsite
== null then return null
906 return callsite
.infobox
(v
)
911 redef fun decorate_tag
(v
, res
, token
)
913 var callsite
= self.callsite
914 if callsite
== null then return null
915 return callsite
.infobox
(v
)
919 redef class AAssignOp
920 redef fun decorate_tag
(v
, res
, token
)
923 assert p
isa AReassignFormExpr
925 var callsite
= p
.reassign_callsite
926 if callsite
== null then return null
927 return callsite
.infobox
(v
)
931 redef class AModuleName
932 redef fun decorate_tag
(v
, res
, token
)
935 if p
== null then return null
936 return p
.decorate_tag
(v
, res
, token
)
940 redef class AModuledecl
941 redef fun decorate_tag
(v
, res
, token
)
943 if not token
isa TId then return null
944 res
.add_class
("nc_def")
945 res
.add_class
("nc_m")
949 if mm
== null then return null
954 redef class AStdImport
955 redef fun decorate_tag
(v
, res
, token
)
957 if not token
isa TId then return null
958 res
.add_class
("nc_m")
960 if mm
== null then return null
964 redef class AAttrPropdef
965 redef fun decorate_tag
(v
, res
, token
)
967 if not token
isa TId then return null
968 res
.add_class
("nc_def")
969 var mpd
: nullable MPropDef
971 if mpd
== null then mpd
= mpropdef
972 if mpd
== null then return null
973 return mpd
.infobox
(v
)
978 redef fun make_tag
(v
)
981 res
.add_class
("nc_i")
986 redef fun make_tag
(v
)
988 var res
= new HTMLTag("span")
989 res
.add_class
("nc_def")
992 redef fun decorate_tag
(v
, res
, token
)
995 # nothing to decorate
1000 if not p
isa AMethPropdef then return null
1001 var mpd
= p
.mpropdef
1002 if mpd
== null then return null
1003 return mpd
.infobox
(v
)
1007 redef fun make_tag
(v
)
1010 res
.add_class
("nc_a")
1014 redef class AAttrFormExpr
1015 redef fun decorate_tag
(v
, res
, token
)
1017 if not token
isa TAttrid then return null
1019 if p
== null then return null
1020 return p
.intro
.infobox
(v
)
1023 redef class TClassid
1024 redef fun make_tag
(v
)
1027 res
.add_class
("nc_t")
1032 redef fun decorate_tag
(v
, res
, token
)
1034 if not token
isa TClassid then return null
1036 if mt
== null then return null
1038 if mt
isa MFormalType then
1039 res
.add_class
("nc_vt")
1041 return mt
.infobox
(v
)
1044 redef class AFormaldef
1045 redef fun decorate_tag
(v
, res
, token
)
1047 if not token
isa TClassid then return null
1048 res
.add_class
("nc_vt")
1049 var mtype
= self.mtype
1050 if mtype
== null then return null
1051 return mtype
.infobox
(v
)
1054 redef class ATypePropdef
1055 redef fun decorate_tag
(v
, res
, token
)
1057 if not token
isa TClassid then return null
1058 res
.add_class
("nc_def")
1060 if md
== null then return null
1061 return md
.infobox
(v
)
1064 redef class TComment
1065 redef fun make_tag
(v
)
1069 res
.add_class
("nc_c")
1075 redef fun make_tag
(v
)
1077 var res
= new HTMLTag("span")
1078 res
.add_class
("nc_d")
1082 redef class TokenLiteral
1083 redef fun make_tag
(v
)
1086 res
.add_class
("nc_l")
1090 redef class ASuperstringExpr
1091 redef fun make_tag
(v
)
1093 var res
= new HTMLTag("span")
1094 res
.add_class
("nc_ss")
1098 redef class AStringFormExpr
1099 redef fun decorate_tag
(v
, res
, token
)
1101 # Workaround to tag strings
1102 res
.classes
.remove
("nc_l")
1103 res
.add_class
("nc_s")
1108 redef fun decorate_tag
(v
, res
, token
)
1111 if t
== null then return null