highlight: extract HTML stuff from highlight into htmlight
[nit.git] / src / doc / commands / commands_model.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # Doc commands about a Model or a MEntity
16 #
17 # This module defines several commands to retrieve data about a Model and MEntities.
18 module commands_model
19
20 import commands_base
21
22 import model::model_collect
23 import modelize
24 import modelbuilder
25 import htmlight
26 import doc_down
27
28 # Retrieve the MDoc related to a MEntity
29 class CmdComment
30 super CmdEntity
31
32 # Allow fallback
33 #
34 # If `true`, the command uses `mdoc_or_fallback`.
35 # Default is `true`.
36 var fallback = true is optional, writable
37
38 # Retrieve the full documentation
39 #
40 # If `true`, retrieves the full documentation.
41 # If `false`, retrieves only the synopsis.
42 # Default is `true`.
43 #
44 # Since the rendering the final string (md, html...) depends on the kind of
45 # client, the handling of this option is delegated to submodules.
46 var full_doc = true is optional, writable
47
48 # Format to render the comment
49 #
50 # Can be one of `raw` or `html`.
51 # Default is `raw`.
52 var format = "raw" is optional, writable
53
54 # MDoc to return
55 var mdoc: nullable MDoc = null is optional, writable
56
57 # Same states than `CmdEntity::init_mentity`
58 #
59 # Plus returns `WarningNoMDoc` if no MDoc was found for the MEntity.
60 redef fun init_command do
61 var res = super
62 if not res isa CmdSuccess then return res
63 var mentity = self.mentity.as(not null)
64
65 if mdoc == null then
66 mdoc = if fallback then mentity.mdoc_or_fallback else mentity.mdoc
67 end
68 if mdoc == null then return new WarningNoMDoc(mentity)
69 return res
70 end
71
72 # Render `mdoc` depending on `full_doc` and `format`
73 fun render: nullable Writable do
74 var mdoc = self.mdoc
75 if mdoc == null then return null
76
77 if format == "html" then
78 if full_doc then return mdoc.html_documentation
79 return mdoc.html_synopsis
80 end
81 if full_doc then return mdoc.documentation
82 return mdoc.synopsis
83 end
84 end
85
86 # No MDoc for `mentity`
87 class WarningNoMDoc
88 super CmdWarning
89
90 # MEntity provided
91 var mentity: MEntity
92
93 redef fun to_s do return "No documentation for `{mentity.full_name}`."
94 end
95
96 # MEntity ancestors command
97 #
98 # Retrieve all the ancestors (direct and indirect) of a MEntity.
99 class CmdAncestors
100 super CmdEntityList
101
102 # Include direct parents in the ancestors list
103 #
104 # Default is `true`.
105 var parents = true is optional, writable
106
107 redef fun init_results do
108 if results != null then return new CmdSuccess
109
110 var res = super
111 if not res isa CmdSuccess then return res
112 var mentity = self.mentity.as(not null)
113
114 var ancestors = mentity.collect_ancestors(view).to_a
115 if parents then
116 results = ancestors
117 return res
118 end
119
120 var parents = mentity.collect_parents(view)
121 var mentities = new HashSet[MEntity]
122 for ancestor in ancestors do
123 if not parents.has(ancestor) then mentities.add ancestor
124 end
125 results = mentities.to_a
126 return res
127 end
128 end
129
130 # MEntity parents command
131 class CmdParents
132 super CmdEntityList
133
134 redef fun init_results do
135 if results != null then return new CmdSuccess
136
137 var res = super
138 if not res isa CmdSuccess then return res
139 var mentity = self.mentity.as(not null)
140
141 results = mentity.collect_parents(view).to_a
142 return res
143 end
144 end
145
146 # MEntity children command
147 class CmdChildren
148 super CmdEntityList
149
150 redef fun init_results do
151 if results != null then return new CmdSuccess
152
153 var res = super
154 if not res isa CmdSuccess then return res
155 var mentity = self.mentity.as(not null)
156
157 results = mentity.collect_children(view).to_a
158 return res
159 end
160 end
161
162 # MEntity descendants command
163 class CmdDescendants
164 super CmdEntityList
165
166 # Include direct children in the descendants list
167 #
168 # Default is `true`.
169 var children = true is optional, writable
170
171 redef fun init_results do
172 if results != null then return new CmdSuccess
173
174 var res = super
175 if not res isa CmdSuccess then return res
176 var mentity = self.mentity.as(not null)
177
178 var descendants = mentity.collect_descendants(view).to_a
179 if children then
180 results = descendants
181 return res
182 end
183
184 var children = mentity.collect_children(view)
185 var mentities = new HashSet[MEntity]
186 for descendant in descendants do
187 if not children.has(descendant) then mentities.add descendant
188 end
189 results = mentities.to_a
190 return res
191 end
192 end
193
194 # Linearization command
195 #
196 # Collects and linearizes definitions about an MEntity.
197 class CmdLinearization
198 super CmdEntityList
199
200 # Same states than `CmdEntity::init_mentity`
201 #
202 # Plus returns `WarningNoLinearization` if no linearization can be computed
203 # from the mentity.
204 redef fun init_results do
205 if results != null then return new CmdSuccess
206
207 var res = super
208 if not res isa CmdSuccess then return res
209 var mentity = self.mentity.as(not null)
210
211 sorter = null
212 results = mentity.collect_linearization(view.mainmodule)
213 if results == null then return new WarningNoLinearization(mentity)
214 return res
215 end
216 end
217
218 # No linearization computed for `mentity`.
219 class WarningNoLinearization
220 super CmdWarning
221
222 # MEntity provided
223 var mentity: MEntity
224
225 redef fun to_s do return "No linearization for `{mentity.full_name}`"
226 end
227
228 # A free text search command
229 class CmdSearch
230 super CmdEntities
231
232 # Free text command string
233 var query: nullable String = null is optional, writable
234
235 # Return states:
236 # * `CmdSuccess`: everything was ok;
237 # * `ErrorNoQuery`: no `query` provided.
238 redef fun init_results do
239 if results != null then return new CmdSuccess
240
241 var res = super
242 if not res isa CmdSuccess then return res
243
244 var query = self.query
245 if query == null then return new ErrorNoQuery
246 sorter = null
247 results = view.find(query)
248 return res
249 end
250 end
251
252 # No query string given
253 class ErrorNoQuery
254 super CmdError
255
256 redef fun to_s do return "Missing search string"
257 end
258
259 # MEntity feature list
260 #
261 # Mostly a list of mentities defined in `mentity`.
262 class CmdFeatures
263 super CmdEntityList
264
265 # Same as `CmdEntity::init_mentity`
266 #
267 # Plus `WarningNoFeatures` if no features are found for `mentity`.
268 redef fun init_results do
269 if results != null then return new CmdSuccess
270
271 var res = super
272 if not res isa CmdSuccess then return res
273 var mentity = self.mentity.as(not null)
274
275 var mentities = new Array[MEntity]
276 if mentity isa MPackage then
277 mentities.add_all mentity.collect_mgroups(view)
278 mentities.add_all mentity.collect_mmodules(view)
279 else if mentity isa MGroup then
280 mentities.add_all mentity.collect_mgroups(view)
281 mentities.add_all mentity.collect_mmodules(view)
282 else if mentity isa MModule then
283 mentities.add_all mentity.collect_local_mclassdefs(view)
284 else if mentity isa MClass then
285 mentities.add_all mentity.collect_intro_mproperties(view)
286 mentities.add_all mentity.collect_redef_mpropdefs(view)
287 else if mentity isa MClassDef then
288 mentities.add_all mentity.collect_intro_mpropdefs(view)
289 mentities.add_all mentity.collect_redef_mpropdefs(view)
290 else if mentity isa MProperty then
291 mentities.add_all mentity.collect_mpropdefs(view)
292 else
293 return new WarningNoFeatures(mentity)
294 end
295 self.results = mentities
296 return res
297 end
298 end
299
300 # TODO remove once the filters/sorters are merged
301 class CmdIntros
302 super CmdEntityList
303
304 redef fun init_results do
305 if results != null then return new CmdSuccess
306
307 var res = super
308 if not res isa CmdSuccess then return res
309 var mentity = self.mentity.as(not null)
310
311 if mentity isa MModule then
312 var mentities = mentity.collect_intro_mclasses(view).to_a
313 self.results = mentities
314 else if mentity isa MClass then
315 var mentities = mentity.collect_intro_mproperties(view).to_a
316 self.results = mentities
317 else if mentity isa MClassDef then
318 var mentities = mentity.collect_intro_mpropdefs(view).to_a
319 view.mainmodule.linearize_mpropdefs(mentities)
320 self.results = mentities
321 else
322 return new WarningNoFeatures(mentity)
323 end
324 return res
325 end
326 end
327
328 # TODO remove once the filters/sorters are merged
329 class CmdRedefs
330 super CmdEntityList
331
332 redef fun init_command do
333 if results != null then return new CmdSuccess
334
335 var res = super
336 if not res isa CmdSuccess then return res
337 var mentity = self.mentity.as(not null)
338
339 if mentity isa MModule then
340 var mentities = mentity.collect_redef_mclasses(view).to_a
341 self.results = mentities
342 else if mentity isa MClass then
343 var mentities = mentity.collect_redef_mproperties(view).to_a
344 self.results = mentities
345 else if mentity isa MClassDef then
346 var mentities = mentity.collect_redef_mpropdefs(view).to_a
347 view.mainmodule.linearize_mpropdefs(mentities)
348 self.results = mentities
349 else
350 return new WarningNoFeatures(mentity)
351 end
352 return res
353 end
354 end
355
356 # TODO remove once the filters/sorters are merged
357 class CmdAllProps
358 super CmdEntityList
359
360 redef fun init_results do
361 if results != null then return new CmdSuccess
362
363 var res = super
364 if not res isa CmdSuccess then return res
365 var mentity = self.mentity.as(not null)
366
367 if mentity isa MClass then
368 results = mentity.collect_accessible_mproperties(view).to_a
369 else
370 return new WarningNoFeatures(mentity)
371 end
372 return res
373 end
374 end
375
376 # No feature list for `mentity`
377 class WarningNoFeatures
378 super CmdWarning
379
380 # MEntity provided
381 var mentity: MEntity
382
383 redef fun to_s do return "No features for `{mentity.full_name}`"
384 end
385
386 # Cmd that finds the source code related to an `mentity`
387 class CmdCode
388 super CmdEntity
389
390 autoinit(view, modelbuilder, mentity, mentity_name, format)
391
392 # ModelBuilder used to get AST nodes
393 var modelbuilder: ModelBuilder
394
395 # AST node to return
396 var node: nullable ANode = null is optional, writable
397
398 # Rendering format
399 #
400 # Set the output format for this piece of code.
401 # Can be "raw" or "html".
402 # Default is "raw".
403 #
404 # This format can be different than the format used in the command response.
405 # For example you can choose to render code as HTML inside a JSON object response.
406 # Another example is to render raw format to put into a HTML code tag.
407 var format = "raw" is optional, writable
408
409 # Same as `CmdEntity::init_mentity`
410 #
411 # Plus `WarningNoCode` if no code/AST node is found for `mentity`.
412 redef fun init_command do
413 if node != null then return new CmdSuccess
414
415 var res = super
416 if not res isa CmdSuccess then return res
417 var mentity = self.mentity.as(not null)
418
419 if mentity isa MClass then mentity = mentity.intro
420 if mentity isa MProperty then mentity = mentity.intro
421 node = modelbuilder.mentity2node(mentity)
422 if node == null then return new WarningNoCode(mentity)
423 return res
424 end
425
426 # Render `node` depending on the selected `format`
427 fun render: nullable Writable do
428 var node = self.node
429 if node == null then return null
430 if format == "html" then
431 var hl = new HtmlightVisitor
432 hl.highlight_node node
433 return hl.html
434 end
435 # TODO make a raw visitor
436 return node.to_s
437 end
438 end
439
440 # No code for `mentity`
441 class WarningNoCode
442 super CmdWarning
443
444 # MEntity provided
445 var mentity: MEntity
446
447 redef fun to_s do return "No code for `{mentity.full_name}`"
448 end
449
450 # Model commands
451
452 # A command that returns a list of all mentities in a model
453 class CmdModelEntities
454 super CmdEntities
455
456 # Kind of mentities to be returned.
457 #
458 # Value must be one of "packages", "groups", "modules", "classes", "classdefs",
459 # "properties", "propdefs" or "all".
460 #
461 # Default is "all".
462 var kind = "all" is optional, writable
463
464 # Default limit is `10`
465 redef var limit = 10
466
467 redef fun init_results do
468 if results != null then return new CmdSuccess
469
470 var res = super
471 if not res isa CmdSuccess then return res
472
473 var mentities = new Array[MEntity]
474 if kind == "packages" then
475 mentities = view.mpackages.to_a
476 else if kind == "groups" then
477 mentities = view.mgroups.to_a
478 else if kind == "modules" then
479 mentities = view.mmodules.to_a
480 else if kind == "classes" then
481 mentities = view.mclasses.to_a
482 else if kind == "classdefs" then
483 mentities = view.mclassdefs.to_a
484 else if kind == "properties" then
485 mentities = view.mproperties.to_a
486 else if kind == "propdefs" then
487 mentities = view.mpropdefs.to_a
488 else
489 mentities = view.mentities.to_a
490 end
491 results = mentities
492 return res
493 end
494 end
495
496 # A command that returns a random list of mentities from a model
497 class CmdRandomEntities
498 super CmdModelEntities
499
500 # Always return `CmdSuccess`
501 redef fun init_results do
502 if results != null then return new CmdSuccess
503 var res = super
504 if not res isa CmdSuccess then return res
505 randomize
506 return res
507 end
508
509 # Randomize mentities order
510 fun randomize do
511 var results = self.results
512 if results == null then return
513 results.shuffle
514 end
515 end