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 msignature
= self.msignature
255 if msignature
== null then return new Template
256 return msignature
.html_signature
(short
)
260 redef class MVirtualTypeProp
261 redef fun html_link
(text
, title
) do return mvirtualtype
.html_link
(text
, title
)
264 redef class MVirtualTypeDef
265 redef fun html_signature
(short
) do
266 var bound
= self.bound
267 var tpl
= new Template
268 if bound
== null then return tpl
270 tpl
.add bound
.html_signature
(short
)
276 redef fun html_signature
(short
) do return html_link
279 redef class MClassType
280 redef fun html_link
(text
, title
) do return mclass
.html_link
(text
, title
)
283 redef class MNullableType
284 redef fun html_signature
(short
) do
285 var tpl
= new Template
287 tpl
.add mtype
.html_signature
(short
)
292 redef class MGenericType
293 redef fun html_signature
(short
) do
295 var tpl
= new Template
296 tpl
.add
new Link(lnk
.href
, mclass
.name
.html_escape
, lnk
.title
)
298 for i
in [0..arguments
.length
[ do
299 tpl
.add arguments
[i
].html_signature
(short
)
300 if i
< arguments
.length
- 1 then tpl
.add
", "
307 redef class MParameterType
308 redef fun html_link
(text
, title
) do
309 if text
== null then text
= name
310 if title
== null then title
= "formal type"
311 return new Link("{mclass.html_url}#FT_{name.to_cmangle}", text
, title
)
315 redef class MVirtualType
316 redef fun html_link
(text
, title
) do return mproperty
.intro
.html_link
(text
, title
)
319 redef class MSignature
320 redef fun html_signature
(short
) do
321 var tpl
= new Template
322 if not mparameters
.is_empty
then
324 for i
in [0..mparameters
.length
[ do
325 tpl
.add mparameters
[i
].html_signature
(short
)
326 if i
< mparameters
.length
- 1 then tpl
.add
", "
330 if short
== null or not short
then
331 var return_mtype
= self.return_mtype
332 if return_mtype
!= null then
334 tpl
.add return_mtype
.html_signature
(short
)
341 redef class MParameter
342 redef fun html_signature
(short
) do
343 var tpl
= new Template
345 if short
== null or not short
then
347 tpl
.add mtype
.html_signature
(short
)
349 if is_vararg
then tpl
.add
"..."
359 fun html_id
: String do return name
.to_cmangle
363 # Should be redefined in clients.
364 fun html_url
: String do return "person_{html_id}.html"
366 # Link to this person `html_url`
367 fun html_link
: Link do return new Link(html_url
, name
)
369 # Render `self` as HTML
370 fun to_html
: String do
371 var tpl
= new Template
373 var gravatar
= self.gravatar
374 if gravatar
!= null then
375 tpl
.addn
"<img class='avatar' src='https://secure.gravatar.com/avatar/{gravatar}?size=14&default=retro' />"
379 return tpl
.write_to_string
387 private var markdown_proc
: MarkdownProcessor is lazy
, writable do
388 return original_mentity
.as(not null).model
.nitdoc_md_processor
391 private var inline_proc
: MarkdownProcessor is lazy
, writable do
392 return original_mentity
.as(not null).model
.nitdoc_inline_processor
395 # Renders the synopsis as a HTML comment block.
396 var html_synopsis
: Writable is lazy
do
397 var res
= new Template
398 var syn
= inline_proc
.process
(content
.first
)
399 res
.add
"<span class=\"synopsis nitdoc\
">{syn}</span>"
403 # Renders the comment without the synopsis as a HTML comment block.
404 var html_comment
: Writable is lazy
do
405 var lines
= content
.to_a
406 if not lines
.is_empty
then lines
.shift
407 return lines_to_html
(lines
)
410 # Renders the synopsis and the comment as a HTML comment block.
411 var html_documentation
: Writable is lazy
do return lines_to_html
(content
.to_a
)
413 # Renders markdown line as a HTML comment block.
414 private fun lines_to_html
(lines
: Array[String]): Writable do
415 var res
= new Template
416 var decorator
= markdown_proc
.decorator
.as(NitdocDecorator)
417 decorator
.current_mdoc
= self
418 res
.add
"<div class=\"nitdoc\
">"
419 # do not use DocUnit as synopsis
420 if not lines
.is_empty
then
421 if not lines
.first
.has_prefix
(" ") and
422 not lines
.first
.has_prefix
("\t") then
424 var syn
= inline_proc
.process
(lines
.shift
)
425 res
.add
"<h1 class=\"synopsis\
">{syn}</h1>"
428 # check for annotations
429 for i
in [0 .. lines
.length
[ do
431 if line
.to_upper
.has_prefix
("ENSURE") or line
.to_upper
.has_prefix
("REQUIRE") then
432 var html
= inline_proc
.process
(line
)
433 lines
[i
] = "<p class=\"contract\
">{html}</p>"
434 else if line
.to_upper
.has_prefix
("TODO") or line
.to_upper
.has_prefix
("FIXME") then
435 var html
= inline_proc
.process
(line
)
436 lines
[i
] = "<p class=\"todo\
">{html}</p>"
440 res
.add markdown_proc
.process
(lines
.join
("\n"))
442 decorator
.current_mdoc
= null
447 # The specific markdown decorator used internally to process MDoc object.
449 # You should use the various methods of `MDoc` like `MDoc::html_documentation`
451 # The class is public so specific behavior can be plugged on it.
452 class NitdocDecorator
455 private var toolcontext
= new ToolContext
457 # The currently processed mdoc.
459 # Unfortunately, this seems to be the simpler way to get the currently processed `MDoc` object.
460 var current_mdoc
: nullable MDoc = null
462 redef fun add_code
(v
, block
) do
463 var meta
= block
.meta
or else "nit"
465 # Do not try to highlight non-nit code.
466 if meta
!= "nit" and meta
!= "nitish" then
467 v
.add
"<pre class=\"{meta}\
"><code>"
469 v
.add
"</code></pre>\n"
473 var code
= block
.raw_content
474 var ast
= toolcontext
.parse_something
(code
)
475 if ast
isa AError then
476 v
.add
"<pre class=\"{meta}\
"><code>"
478 v
.add
"</code></pre>\n"
481 v
.add
"<pre class=\"nitcode\
"><code>"
482 var hl
= new HtmlightVisitor
483 hl
.line_id_prefix
= ""
484 hl
.highlight_node
(ast
)
486 v
.add
"</code></pre>\n"
489 redef fun add_span_code
(v
, text
, from
, to
) do
491 var code
= code_from_text
(text
, from
, to
)
492 var ast
= toolcontext
.parse_something
(code
)
494 if ast
isa AError then
495 v
.add
"<code class=\"rawcode\
">"
496 append_code
(v
, text
, from
, to
)
498 v
.add
"<code class=\"nitcode\
">"
499 var hl
= new HtmlightVisitor
500 hl
.line_id_prefix
= ""
501 hl
.highlight_node
(ast
)
507 private fun code_from_text
(buffer
: Text, from
, to
: Int): String do
508 var out
= new FlatBuffer
509 for i
in [from
..to
[ do out
.add buffer
[i
]
510 return out
.write_to_string
514 # Decorator for span elements.
516 # Because inline comments can appear as span elements,
517 # InlineDecorator do not decorate things like paragraphs or headers.
518 class InlineDecorator
519 super NitdocDecorator
521 redef fun add_paragraph
(v
, block
) do
525 redef fun add_headline
(v
, block
) do
527 var line
= block
.block
.first_line
528 if line
== null then return
530 var id
= strip_id
(txt
)
531 var lvl
= block
.depth
532 headlines
[id
] = new HeadLine(id
, txt
, lvl
)
537 redef fun add_code
(v
, block
) do
539 var ast
= toolcontext
.parse_something
(block
.block
.text
.to_s
)
540 if ast
isa AError then
546 v
.add
"<code class=\"nitcode\
">"
547 var hl
= new HtmlightVisitor
548 hl
.highlight_node
(ast
)
555 # Get a markdown processor for Nitdoc comments.
556 var nitdoc_md_processor
: MarkdownProcessor is lazy
, writable do
557 var proc
= new MarkdownProcessor
558 proc
.decorator
= new NitdocDecorator
562 # Get a markdown inline processor for Nitdoc comments.
564 # This processor is specificaly designed to inlinable doc elements like synopsis.
565 var nitdoc_inline_processor
: MarkdownProcessor is lazy
, writable do
566 var proc
= new MarkdownProcessor
567 proc
.decorator
= new InlineDecorator