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 # Translate mentities to html blocks.
18 import model
::model_collect
23 import html
::bootstrap
24 private import parser_util
28 # The MEntity unique ID in the HTML output
29 var html_id
: String is lazy
do return full_name
.to_cmangle
31 # The MEntity URL in the HTML output
33 # You MUST redefine this method.
34 # Depending on your implementation, this URL can be a page URL or an anchor.
35 var html_url
: String is lazy
do return html_id
37 # The MEntity name escaped for HTML
38 var html_name
: String is lazy
do return name
.html_escape
40 # The MEntity `full_name` escaped for HTML
41 var html_full_name
: String is lazy
do return full_name
.html_escape
43 # Link to the MEntity in the HTML output
45 # You should redefine this method depending on the organization or your
47 fun html_link
(text
, title
: nullable String): Link do
51 var mdoc
= self.mdoc_or_fallback
52 if title
== null and mdoc
!= null then
55 return new Link(html_url
, text
, title
)
58 # Returns the complete MEntity declaration decorated with HTML
61 # * MPackage: `package foo`
62 # * MGroup: `group foo`
63 # * MModule: `module foo`
64 # * MClass: `private abstract class Foo[E: Object]`
65 # * MClassDef: `redef class Foo[E]`
66 # * MProperty: `private fun foo(e: Object): Int`
67 # * MPropdef: `redef fun foo(e)`
68 fun html_declaration
: Template do
69 var tpl
= new Template
70 tpl
.add
"<span class='signature'>"
71 for modifier
in collect_modifiers
do
72 tpl
.add
"<span class='modifier'>{modifier}</span> "
74 tpl
.add
"<span class='name'>{html_link.write_to_string}</span>"
75 tpl
.add html_signature
(false)
80 # Returns the MEntity signature decorated with HTML
82 # This function only returns the parenthesis and return types.
83 # See `html_declaration` for the full declaration including modifiers and name.
84 fun html_signature
(short
: nullable Bool): Template do return new Template
86 # Returns `full_name` decorated with HTML links
87 fun html_namespace
: Template is abstract
89 # An icon representative of the mentity
90 fun html_icon
: BSIcon do return new BSIcon("tag", ["text-muted"])
92 # CSS classes used to decorate `self`
94 # Mainly used for icons.
95 var css_classes
: Array[String] = collect_modifiers
is lazy
99 redef fun html_namespace
do return html_link
100 redef fun html_icon
do return new BSIcon("book", ["text-muted"])
101 redef var css_classes
= ["public"]
105 redef fun html_icon
do return new BSIcon("folder-close", ["text-muted"])
107 redef fun html_namespace
do
108 var tpl
= new Template
109 var parent
= self.parent
110 if parent
!= null then
111 tpl
.add parent
.html_namespace
120 redef fun html_icon
do return new BSIcon("file", ["text-muted"])
122 redef fun html_namespace
do
123 var mpackage
= self.mpackage
124 var tpl
= new Template
125 if mpackage
!= null then
126 tpl
.add mpackage
.html_namespace
135 redef fun html_icon
do return new BSIcon("stop", css_classes
)
136 redef fun html_signature
(short
) do return intro
.html_signature
(short
)
137 redef fun css_classes
do return super + [visibility
.to_s
]
139 redef fun html_namespace
do
140 var mgroup
= intro_mmodule
.mgroup
141 var tpl
= new Template
142 if mgroup
!= null then
143 tpl
.add mgroup
.mpackage
.html_namespace
153 redef class MClassDef
154 redef fun css_classes
do return super + mclass
.css_classes
156 redef fun html_namespace
do
157 var tpl
= new Template
158 var mpackage
= mmodule
.mpackage
159 if mpackage
!= null and is_intro
then
161 tpl
.add mpackage
.html_namespace
164 tpl
.add mmodule
.html_namespace
166 var intro_mpackage
= mclass
.intro
.mmodule
.mpackage
167 if intro_mpackage
!= null and mpackage
!= intro_mpackage
then
168 tpl
.add intro_mpackage
.html_namespace
173 tpl
.add mmodule
.html_namespace
180 redef fun html_icon
do
182 return new BSIcon("plus", css_classes
)
184 return new BSIcon("asterisk", css_classes
)
187 redef fun html_signature
(short
) do
188 var tpl
= new Template
189 var mparameters
= mclass
.mparameters
190 if not mparameters
.is_empty
then
192 for i
in [0..mparameters
.length
[ do
193 tpl
.add mparameters
[i
].html_name
194 if short
== null or not short
then
196 tpl
.add bound_mtype
.arguments
[i
].html_signature
(short
)
198 if i
< mparameters
.length
- 1 then tpl
.add
", "
206 redef class MProperty
207 redef fun html_declaration
do return intro
.html_declaration
208 redef fun html_signature
(short
) do return intro
.html_signature
(short
)
209 redef fun html_icon
do return new BSIcon("tag", css_classes
)
210 redef fun css_classes
do return super + [visibility
.to_s
]
212 redef fun html_namespace
do
213 var tpl
= new Template
214 tpl
.add intro_mclassdef
.mclass
.html_namespace
216 tpl
.add intro
.html_link
222 redef fun css_classes
do return super + mproperty
.css_classes
224 redef fun html_namespace
do
225 var tpl
= new Template
226 tpl
.add mclassdef
.html_namespace
232 redef fun html_icon
do
234 return new BSIcon("plus", css_classes
)
236 return new BSIcon("asterisk", css_classes
)
240 redef class MAttributeDef
241 redef fun html_signature
(short
) do
242 var static_mtype
= self.static_mtype
243 var tpl
= new Template
244 if static_mtype
!= null then
246 tpl
.add static_mtype
.html_signature
(short
)
252 redef class MMethodDef
253 redef fun html_signature
(short
) do
254 var new_msignature
= self.new_msignature
255 if mproperty
.is_root_init
and new_msignature
!= null then
256 return new_msignature
.html_signature
(short
)
258 var msignature
= self.msignature
259 if msignature
== null then return new Template
260 return msignature
.html_signature
(short
)
264 redef class MVirtualTypeProp
265 redef fun html_link
(text
, title
) do return mvirtualtype
.html_link
(text
, title
)
268 redef class MVirtualTypeDef
269 redef fun html_signature
(short
) do
270 var bound
= self.bound
271 var tpl
= new Template
272 if bound
== null then return tpl
274 tpl
.add bound
.html_signature
(short
)
280 redef fun html_signature
(short
) do return html_link
283 redef class MClassType
284 redef fun html_link
(text
, title
) do return mclass
.html_link
(text
, title
)
287 redef class MNullableType
288 redef fun html_signature
(short
) do
289 var tpl
= new Template
291 tpl
.add mtype
.html_signature
(short
)
296 redef class MGenericType
297 redef fun html_signature
(short
) do
299 var tpl
= new Template
300 tpl
.add
new Link(lnk
.href
, mclass
.name
.html_escape
, lnk
.title
)
302 for i
in [0..arguments
.length
[ do
303 tpl
.add arguments
[i
].html_signature
(short
)
304 if i
< arguments
.length
- 1 then tpl
.add
", "
311 redef class MParameterType
312 redef fun html_link
(text
, title
) do
313 if text
== null then text
= name
314 if title
== null then title
= "formal type"
315 return new Link("{mclass.html_url}#FT_{name.to_cmangle}", text
, title
)
319 redef class MVirtualType
320 redef fun html_link
(text
, title
) do return mproperty
.intro
.html_link
(text
, title
)
323 redef class MSignature
324 redef fun html_signature
(short
) do
325 var tpl
= new Template
326 if not mparameters
.is_empty
then
328 for i
in [0..mparameters
.length
[ do
329 tpl
.add mparameters
[i
].html_signature
(short
)
330 if i
< mparameters
.length
- 1 then tpl
.add
", "
334 if short
== null or not short
then
335 var return_mtype
= self.return_mtype
336 if return_mtype
!= null then
338 tpl
.add return_mtype
.html_signature
(short
)
345 redef class MParameter
346 redef fun html_signature
(short
) do
347 var tpl
= new Template
349 if short
== null or not short
then
351 tpl
.add mtype
.html_signature
(short
)
353 if is_vararg
then tpl
.add
"..."
363 fun html_id
: String do return name
.to_cmangle
367 # Should be redefined in clients.
368 fun html_url
: String do return "person_{html_id}.html"
370 # Link to this person `html_url`
371 fun html_link
: Link do return new Link(html_url
, name
)
374 var tpl
= new Template
376 var gravatar
= self.gravatar
377 if gravatar
!= null then
378 tpl
.addn
"<img class='avatar' src='https://secure.gravatar.com/avatar/{gravatar}?size=14&default=retro' />"
382 return tpl
.write_to_string
390 private var markdown_proc
: MarkdownProcessor is lazy
, writable do
391 return original_mentity
.as(not null).model
.nitdoc_md_processor
394 private var inline_proc
: MarkdownProcessor is lazy
, writable do
395 return original_mentity
.as(not null).model
.nitdoc_inline_processor
398 # Renders the synopsis as a HTML comment block.
399 var html_synopsis
: Writable is lazy
do
400 var res
= new Template
401 var syn
= inline_proc
.process
(content
.first
)
402 res
.add
"<span class=\"synopsys nitdoc\
">{syn}</span>"
406 # Renders the comment without the synopsis as a HTML comment block.
407 var html_comment
: Writable is lazy
do
408 var lines
= content
.to_a
409 if not lines
.is_empty
then lines
.shift
410 return lines_to_html
(lines
)
413 # Renders the synopsis and the comment as a HTML comment block.
414 var html_documentation
: Writable is lazy
do return lines_to_html
(content
.to_a
)
416 # Renders markdown line as a HTML comment block.
417 private fun lines_to_html
(lines
: Array[String]): Writable do
418 var res
= new Template
419 var decorator
= markdown_proc
.decorator
.as(NitdocDecorator)
420 decorator
.current_mdoc
= self
421 res
.add
"<div class=\"nitdoc\
">"
422 # do not use DocUnit as synopsys
423 if not lines
.is_empty
then
424 if not lines
.first
.has_prefix
(" ") and
425 not lines
.first
.has_prefix
("\t") then
427 var syn
= inline_proc
.process
(lines
.shift
)
428 res
.add
"<h1 class=\"synopsys\
">{syn}</h1>"
431 # check for annotations
432 for i
in [0 .. lines
.length
[ do
434 if line
.to_upper
.has_prefix
("ENSURE") or line
.to_upper
.has_prefix
("REQUIRE") then
435 var html
= inline_proc
.process
(line
)
436 lines
[i
] = "<p class=\"contract\
">{html}</p>"
437 else if line
.to_upper
.has_prefix
("TODO") or line
.to_upper
.has_prefix
("FIXME") then
438 var html
= inline_proc
.process
(line
)
439 lines
[i
] = "<p class=\"todo\
">{html}</p>"
443 res
.add markdown_proc
.process
(lines
.join
("\n"))
445 decorator
.current_mdoc
= null
450 # The specific markdown decorator used internally to process MDoc object.
452 # You should use the various methods of `MDoc` like `MDoc::html_documentation`
454 # The class is public so specific behavior can be plugged on it.
455 class NitdocDecorator
458 private var toolcontext
= new ToolContext
460 # The currently processed mdoc.
462 # Unfortunately, this seems to be the simpler way to get the currently processed `MDoc` object.
463 var current_mdoc
: nullable MDoc = null
465 redef fun add_code
(v
, block
) do
466 var meta
= block
.meta
or else "nit"
468 # Do not try to highlight non-nit code.
469 if meta
!= "nit" and meta
!= "nitish" then
470 v
.add
"<pre class=\"{meta}\
"><code>"
472 v
.add
"</code></pre>\n"
476 var code
= block
.raw_content
477 var ast
= toolcontext
.parse_something
(code
)
478 if ast
isa AError then
479 v
.add
"<pre class=\"{meta}\
"><code>"
481 v
.add
"</code></pre>\n"
484 v
.add
"<pre class=\"nitcode\
"><code>"
485 var hl
= new HtmlightVisitor
486 hl
.line_id_prefix
= ""
487 hl
.highlight_node
(ast
)
489 v
.add
"</code></pre>\n"
492 redef fun add_span_code
(v
, text
, from
, to
) do
494 var code
= code_from_text
(text
, from
, to
)
495 var ast
= toolcontext
.parse_something
(code
)
497 if ast
isa AError then
498 v
.add
"<code class=\"rawcode\
">"
499 append_code
(v
, text
, from
, to
)
501 v
.add
"<code class=\"nitcode\
">"
502 var hl
= new HtmlightVisitor
503 hl
.line_id_prefix
= ""
504 hl
.highlight_node
(ast
)
510 private fun code_from_text
(buffer
: Text, from
, to
: Int): String do
511 var out
= new FlatBuffer
512 for i
in [from
..to
[ do out
.add buffer
[i
]
513 return out
.write_to_string
517 # Decorator for span elements.
519 # Because inline comments can appear as span elements,
520 # InlineDecorator do not decorate things like paragraphs or headers.
521 class InlineDecorator
522 super NitdocDecorator
524 redef fun add_paragraph
(v
, block
) do
528 redef fun add_headline
(v
, block
) do
530 var line
= block
.block
.first_line
531 if line
== null then return
533 var id
= strip_id
(txt
)
534 var lvl
= block
.depth
535 headlines
[id
] = new HeadLine(id
, txt
, lvl
)
540 redef fun add_code
(v
, block
) do
542 var ast
= toolcontext
.parse_something
(block
.block
.text
.to_s
)
543 if ast
isa AError then
549 v
.add
"<code class=\"nitcode\
">"
550 var hl
= new HtmlightVisitor
551 hl
.highlight_node
(ast
)
558 # Get a markdown processor for Nitdoc comments.
559 var nitdoc_md_processor
: MarkdownProcessor is lazy
, writable do
560 var proc
= new MarkdownProcessor
561 proc
.decorator
= new NitdocDecorator
565 # Get a markdown inline processor for Nitdoc comments.
567 # This processor is specificaly designed to inlinable doc elements like synopsys.
568 var nitdoc_inline_processor
: MarkdownProcessor is lazy
, writable do
569 var proc
= new MarkdownProcessor
570 proc
.decorator
= new InlineDecorator