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
)
373 # Render `self` as HTML
374 fun to_html
: String do
375 var tpl
= new Template
377 var gravatar
= self.gravatar
378 if gravatar
!= null then
379 tpl
.addn
"<img class='avatar' src='https://secure.gravatar.com/avatar/{gravatar}?size=14&default=retro' />"
383 return tpl
.write_to_string
391 private var markdown_proc
: MarkdownProcessor is lazy
, writable do
392 return original_mentity
.as(not null).model
.nitdoc_md_processor
395 private var inline_proc
: MarkdownProcessor is lazy
, writable do
396 return original_mentity
.as(not null).model
.nitdoc_inline_processor
399 # Renders the synopsis as a HTML comment block.
400 var html_synopsis
: Writable is lazy
do
401 var res
= new Template
402 var syn
= inline_proc
.process
(content
.first
)
403 res
.add
"<span class=\"synopsys nitdoc\
">{syn}</span>"
407 # Renders the comment without the synopsis as a HTML comment block.
408 var html_comment
: Writable is lazy
do
409 var lines
= content
.to_a
410 if not lines
.is_empty
then lines
.shift
411 return lines_to_html
(lines
)
414 # Renders the synopsis and the comment as a HTML comment block.
415 var html_documentation
: Writable is lazy
do return lines_to_html
(content
.to_a
)
417 # Renders markdown line as a HTML comment block.
418 private fun lines_to_html
(lines
: Array[String]): Writable do
419 var res
= new Template
420 var decorator
= markdown_proc
.decorator
.as(NitdocDecorator)
421 decorator
.current_mdoc
= self
422 res
.add
"<div class=\"nitdoc\
">"
423 # do not use DocUnit as synopsys
424 if not lines
.is_empty
then
425 if not lines
.first
.has_prefix
(" ") and
426 not lines
.first
.has_prefix
("\t") then
428 var syn
= inline_proc
.process
(lines
.shift
)
429 res
.add
"<h1 class=\"synopsys\
">{syn}</h1>"
432 # check for annotations
433 for i
in [0 .. lines
.length
[ do
435 if line
.to_upper
.has_prefix
("ENSURE") or line
.to_upper
.has_prefix
("REQUIRE") then
436 var html
= inline_proc
.process
(line
)
437 lines
[i
] = "<p class=\"contract\
">{html}</p>"
438 else if line
.to_upper
.has_prefix
("TODO") or line
.to_upper
.has_prefix
("FIXME") then
439 var html
= inline_proc
.process
(line
)
440 lines
[i
] = "<p class=\"todo\
">{html}</p>"
444 res
.add markdown_proc
.process
(lines
.join
("\n"))
446 decorator
.current_mdoc
= null
451 # The specific markdown decorator used internally to process MDoc object.
453 # You should use the various methods of `MDoc` like `MDoc::html_documentation`
455 # The class is public so specific behavior can be plugged on it.
456 class NitdocDecorator
459 private var toolcontext
= new ToolContext
461 # The currently processed mdoc.
463 # Unfortunately, this seems to be the simpler way to get the currently processed `MDoc` object.
464 var current_mdoc
: nullable MDoc = null
466 redef fun add_code
(v
, block
) do
467 var meta
= block
.meta
or else "nit"
469 # Do not try to highlight non-nit code.
470 if meta
!= "nit" and meta
!= "nitish" then
471 v
.add
"<pre class=\"{meta}\
"><code>"
473 v
.add
"</code></pre>\n"
477 var code
= block
.raw_content
478 var ast
= toolcontext
.parse_something
(code
)
479 if ast
isa AError then
480 v
.add
"<pre class=\"{meta}\
"><code>"
482 v
.add
"</code></pre>\n"
485 v
.add
"<pre class=\"nitcode\
"><code>"
486 var hl
= new HtmlightVisitor
487 hl
.line_id_prefix
= ""
488 hl
.highlight_node
(ast
)
490 v
.add
"</code></pre>\n"
493 redef fun add_span_code
(v
, text
, from
, to
) do
495 var code
= code_from_text
(text
, from
, to
)
496 var ast
= toolcontext
.parse_something
(code
)
498 if ast
isa AError then
499 v
.add
"<code class=\"rawcode\
">"
500 append_code
(v
, text
, from
, to
)
502 v
.add
"<code class=\"nitcode\
">"
503 var hl
= new HtmlightVisitor
504 hl
.line_id_prefix
= ""
505 hl
.highlight_node
(ast
)
511 private fun code_from_text
(buffer
: Text, from
, to
: Int): String do
512 var out
= new FlatBuffer
513 for i
in [from
..to
[ do out
.add buffer
[i
]
514 return out
.write_to_string
518 # Decorator for span elements.
520 # Because inline comments can appear as span elements,
521 # InlineDecorator do not decorate things like paragraphs or headers.
522 class InlineDecorator
523 super NitdocDecorator
525 redef fun add_paragraph
(v
, block
) do
529 redef fun add_headline
(v
, block
) do
531 var line
= block
.block
.first_line
532 if line
== null then return
534 var id
= strip_id
(txt
)
535 var lvl
= block
.depth
536 headlines
[id
] = new HeadLine(id
, txt
, lvl
)
541 redef fun add_code
(v
, block
) do
543 var ast
= toolcontext
.parse_something
(block
.block
.text
.to_s
)
544 if ast
isa AError then
550 v
.add
"<code class=\"nitcode\
">"
551 var hl
= new HtmlightVisitor
552 hl
.highlight_node
(ast
)
559 # Get a markdown processor for Nitdoc comments.
560 var nitdoc_md_processor
: MarkdownProcessor is lazy
, writable do
561 var proc
= new MarkdownProcessor
562 proc
.decorator
= new NitdocDecorator
566 # Get a markdown inline processor for Nitdoc comments.
568 # This processor is specificaly designed to inlinable doc elements like synopsys.
569 var nitdoc_inline_processor
: MarkdownProcessor is lazy
, writable do
570 var proc
= new MarkdownProcessor
571 proc
.decorator
= new InlineDecorator