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 # Nitdoc specific Markdown format handling for Nitweb
19 intrude import doc_down
20 intrude import markdown
::wikilinks
22 import model
::model_index
24 redef class NitwebConfig
25 # Specific Markdown processor to use within Nitweb
26 var md_processor
: MarkdownProcessor is lazy
do
27 var proc
= new MarkdownProcessor
28 proc
.emitter
.decorator
= new NitwebDecorator(view
, modelbuilder
)
36 use
("/docdown/", new APIDocdown(config
))
40 # Docdown handler accept docdown as POST data and render it as HTML
44 redef fun post
(req
, res
) do
45 res
.html config
.md_processor
.process
(req
.body
)
49 # Specific Markdown decorator for Nitweb
51 # We reuse all the implementation of the NitdocDecorator and add the wikilinks handling.
55 # View used by wikilink commands to find model entities
58 # Modelbuilder used to access code
59 var modelbuilder
: ModelBuilder
61 redef fun add_wikilink
(v
, token
) do
63 if link
== null then return
64 var cmd
= new DocCommand(link
.write_to_string
)
65 cmd
.render
(v
, token
, view
)
69 # Same as `InlineDecorator` but with wikilink commands handling
70 class NitwebInlineDecorator
73 # View used by wikilink commands to find model entities
76 # Modelbuilder used to access code
77 var modelbuilder
: ModelBuilder
79 redef fun add_wikilink
(v
, token
) do
81 if link
== null then return
82 var cmd
= new DocCommand(link
.write_to_string
)
83 cmd
.render
(v
, token
, view
)
87 redef interface DocCommand
89 # Emit the HTML related to the execution of this doc command
90 fun render
(v
: MarkdownEmitter, token
: TokenWikiLink, model
: ModelView) do
91 write_error
(v
, "Not yet implemented command `{token.link or else "null"}`")
94 # Find the MEntity that matches `name`.
96 # Write an error if the entity is not found
97 fun find_mentity
(v
: MarkdownEmitter, model
: ModelView, name
: nullable String): nullable MEntity do
99 write_error
(v
, "No MEntity found")
102 # Lookup by full name
103 var mentity
= model
.mentity_by_full_name
(name
)
104 if mentity
!= null then return mentity
106 var mentities
= model
.mentities_by_name
(name
)
107 if mentities
.is_empty
then
108 var suggest
= model
.find
(name
, 3)
110 msg
.append
"No MEntity found for name `{name}`"
111 if suggest
.not_empty
then
112 msg
.append
" (suggestions: "
115 msg
.append
"`{s.full_name}`"
116 if i
< suggest
.length
- 1 then msg
.append
", "
121 write_error
(v
, msg
.write_to_string
)
123 else if mentities
.length
> 1 then
125 msg
.append
"Conflicts for name `{name}`"
126 msg
.append
" (conflicts: "
128 for s
in mentities
do
129 msg
.append
"`{s.full_name}`"
130 if i
< mentities
.length
- 1 then msg
.append
", "
134 write_warning
(v
, msg
.write_to_string
)
136 return mentities
.first
139 # Write a warning in the output
140 fun write_warning
(v
: MarkdownEmitter, text
: String) do
141 v
.emit_text
"<p class='text-warning'>Warning: {text}</p>"
144 # Write an error in the output
145 fun write_error
(v
: MarkdownEmitter, text
: String) do
146 v
.emit_text
"<p class='text-danger'>Error: {text}</p>"
149 # Write a link to a mentity in the output
150 fun write_mentity_link
(v
: MarkdownEmitter, mentity
: MEntity) do
151 var link
= mentity
.web_url
152 var name
= mentity
.name
153 var mdoc
= mentity
.mdoc_or_fallback
155 if mdoc
!= null then comment
= mdoc
.synopsis
156 v
.decorator
.add_link
(v
, link
, name
, comment
)
160 redef class UnknownCommand
161 redef fun render
(v
, token
, model
) do
162 var link
= token
.link
164 write_error
(v
, "Empty command")
167 var full_name
= link
.write_to_string
168 var mentity
= find_mentity
(v
, model
, full_name
)
169 if mentity
== null then return
170 write_mentity_link
(v
, mentity
)
174 redef class ArticleCommand
175 redef fun render
(v
, token
, model
) do
176 if args
.is_empty
then
177 write_error
(v
, "Expected one arg: the MEntity name")
180 var name
= args
.first
181 var mentity
= find_mentity
(v
, model
, name
)
182 if mentity
== null then return
183 var mdoc
= mentity
.mdoc_or_fallback
185 write_warning
(v
, "No MDoc for mentity `{name}`")
189 write_mentity_link
(v
, mentity
)
191 v
.emit_text mdoc
.synopsis
193 v
.add v
.processor
.process
(mdoc
.comment
).write_to_string
197 redef class CommentCommand
198 redef fun render
(v
, token
, model
) do
199 if args
.is_empty
then
200 write_error
(v
, "Expected one arg: the MEntity name")
203 var name
= args
.first
204 var mentity
= find_mentity
(v
, model
, name
)
205 if mentity
== null then return
206 var mdoc
= mentity
.mdoc_or_fallback
208 write_warning
(v
, "No MDoc for mentity `{name}`")
211 v
.add v
.processor
.process
(mdoc
.comment
).write_to_string
215 redef class ListCommand
216 redef fun render
(v
, token
, model
) do
217 if args
.is_empty
then
218 write_error
(v
, "Expected one arg: the MEntity name")
221 var name
= args
.first
222 var mentity
= find_mentity
(v
, model
, name
)
223 if mentity
== null then return
224 if mentity
isa MPackage then
225 write_list
(v
, mentity
.mgroups
)
226 else if mentity
isa MGroup then
227 var res
= new Array[MEntity]
228 res
.add_all mentity
.in_nesting
.smallers
229 res
.add_all mentity
.mmodules
231 else if mentity
isa MModule then
232 write_list
(v
, mentity
.mclassdefs
)
233 else if mentity
isa MClass then
234 write_list
(v
, mentity
.collect_intro_mproperties
(model
))
235 else if mentity
isa MClassDef then
236 write_list
(v
, mentity
.mpropdefs
)
237 else if mentity
isa MProperty then
238 write_list
(v
, mentity
.mpropdefs
)
240 write_error
(v
, "No list found for name `{name}`")
244 # Write a mentity list in the output
245 fun write_list
(v
: MarkdownEmitter, mentities
: Collection[MEntity]) do
247 for mentity
in mentities
do
248 var mdoc
= mentity
.mdoc_or_fallback
250 write_mentity_link
(v
, mentity
)
253 v
.emit_text mdoc
.synopsis
261 redef class CodeCommand
262 redef fun render
(v
, token
, model
) do
263 if args
.is_empty
then
264 write_error
(v
, "Expected one arg: the MEntity name")
267 var name
= args
.first
268 var mentity
= find_mentity
(v
, model
, name
)
269 if mentity
== null then return
270 if mentity
isa MClass then mentity
= mentity
.intro
271 if mentity
isa MProperty then mentity
= mentity
.intro
272 var source
= render_source
(mentity
, v
.decorator
.as(NitwebDecorator).modelbuilder
)
273 if source
== null then
274 write_error
(v
, "No source for MEntity `{name}`")
282 # Highlight `mentity` source code.
283 private fun render_source
(mentity
: MEntity, modelbuilder
: ModelBuilder): nullable HTMLTag do
284 var node
= modelbuilder
.mentity2node
(mentity
)
285 if node
== null then return null
286 var hl
= new HighlightVisitor
292 redef class GraphCommand
293 redef fun render
(v
, token
, model
) do
294 if args
.is_empty
then
295 write_error
(v
, "Expected one arg: the MEntity name")
298 var name
= args
.first
299 var mentity
= find_mentity
(v
, model
, name
)
300 if mentity
== null then return
301 var g
= new InheritanceGraph(mentity
, model
)
302 v
.add g
.draw
(3, 3).to_svg