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 # Doc commands about a Model or a MEntity
17 # This module defines several commands to retrieve data about a Model and MEntities.
22 import model
::model_collect
27 # Retrieve the MDoc related to a MEntity
33 # If `true`, the command uses `mdoc_or_fallback`.
35 var fallback
= true is optional
, writable
37 # Retrieve the full documentation
39 # If `true`, retrieves the full documentation.
40 # If `false`, retrieves only the synopsis.
43 # Since the rendering the final string (md, html...) depends on the kind of
44 # client, the handling of this option is delegated to submodules.
45 var full_doc
= true is optional
, writable
47 # Format to render the comment
49 # Can be one of `raw`, `html` or `md`.
51 var format
= "raw" is optional
, writable
54 var mdoc
: nullable MDoc = null is optional
, writable
56 # Same states than `CmdEntity::init_mentity`
58 # Plus returns `WarningNoMDoc` if no MDoc was found for the MEntity.
59 redef fun init_command
do
61 if not res
isa CmdSuccess then return res
62 var mentity
= self.mentity
.as(not null)
65 mdoc
= if fallback
then mentity
.mdoc_or_fallback
else mentity
.mdoc
67 if mdoc
== null then return new WarningNoMDoc(mentity
)
71 # Render `mdoc` depending on `full_doc` and `format`
72 fun render_comment
: nullable Writable do
74 if mdoc
== null then return null
76 if full_doc
then return mdoc
.documentation
81 # No MDoc for `mentity`
88 redef fun to_s
do return "No documentation for `{mentity.full_name}`."
91 # Get the link to a MEntity API documentation
95 # The link text to display
96 var text
: nullable String = null is optional
, writable
98 # The link title to display when the link is hovered
99 var title
: nullable String = null is optional
, writable
101 redef fun init_command
do
103 if not res
isa CmdSuccess then return res
104 var mentity
= self.mentity
.as(not null)
109 if title
== null then
110 var mdoc
= mentity
.mdoc_or_fallback
112 title
= mdoc
.synopsis
119 # An abstract inheritance command
121 # For things like ancestors, parents, children and descendants.
122 abstract class CmdInheritance
125 autoinit
(model
, mainmodule
, filter
, mentity
, mentity_name
, limit
, page
, count
, max
)
127 # Mainmodule for class linearization
128 var mainmodule
: MModule
131 # MEntity ancestors command
133 # Retrieve all the ancestors (direct and indirect) of a MEntity.
137 # Include direct parents in the ancestors list
140 var parents
= true is optional
, writable
142 redef fun init_results
do
143 if results
!= null then return new CmdSuccess
146 if not res
isa CmdSuccess then return res
147 var mentity
= self.mentity
.as(not null)
149 var ancestors
= mentity
.collect_ancestors
(mainmodule
, filter
).to_a
155 var parents
= mentity
.collect_parents
(mainmodule
, filter
)
156 var mentities
= new HashSet[MEntity]
157 for ancestor
in ancestors
do
158 if not parents
.has
(ancestor
) then mentities
.add ancestor
160 results
= mentities
.to_a
165 # MEntity parents command
169 redef fun init_results
do
170 if results
!= null then return new CmdSuccess
173 if not res
isa CmdSuccess then return res
174 var mentity
= self.mentity
.as(not null)
176 results
= mentity
.collect_parents
(mainmodule
, filter
).to_a
181 # MEntity children command
185 redef fun init_results
do
186 if results
!= null then return new CmdSuccess
189 if not res
isa CmdSuccess then return res
190 var mentity
= self.mentity
.as(not null)
192 results
= mentity
.collect_children
(mainmodule
, filter
).to_a
197 # MEntity descendants command
201 # Include direct children in the descendants list
204 var children
= true is optional
, writable
206 redef fun init_results
do
207 if results
!= null then return new CmdSuccess
210 if not res
isa CmdSuccess then return res
211 var mentity
= self.mentity
.as(not null)
213 var descendants
= mentity
.collect_descendants
(mainmodule
, filter
).to_a
215 results
= descendants
219 var children
= mentity
.collect_children
(mainmodule
, filter
)
220 var mentities
= new HashSet[MEntity]
221 for descendant
in descendants
do
222 if not children
.has
(descendant
) then mentities
.add descendant
224 results
= mentities
.to_a
229 # Linearization command
231 # Collects and linearizes definitions about an MEntity.
232 class CmdLinearization
235 # Same states than `CmdEntity::init_mentity`
237 # Plus returns `WarningNoLinearization` if no linearization can be computed
239 redef fun init_results
do
240 if results
!= null then return new CmdSuccess
243 if not res
isa CmdSuccess then return res
244 var mentity
= self.mentity
.as(not null)
247 results
= mentity
.collect_linearization
(mainmodule
)
248 if results
== null then return new WarningNoLinearization(mentity
)
253 # No linearization computed for `mentity`.
254 class WarningNoLinearization
260 redef fun to_s
do return "No linearization for `{mentity.full_name}`"
263 # A free text search command
267 # Free text command string
268 var query
: nullable String = null is optional
, writable
271 # * `CmdSuccess`: everything was ok;
272 # * `ErrorNoQuery`: no `query` provided.
273 redef fun init_results
do
274 if results
!= null then return new CmdSuccess
277 if not res
isa CmdSuccess then return res
279 var query
= self.query
280 if query
== null then return new ErrorNoQuery
282 results
= model
.find
(query
)
287 # No query string given
291 redef fun to_s
do return "Missing search string"
294 # MEntity feature list
296 # Mostly a list of mentities defined in `mentity`.
300 # Same as `CmdEntity::init_mentity`
302 # Plus `WarningNoFeatures` if no features are found for `mentity`.
303 redef fun init_results
do
304 if results
!= null then return new CmdSuccess
307 if not res
isa CmdSuccess then return res
308 var mentity
= self.mentity
.as(not null)
310 var mentities
= new Array[MEntity]
311 if mentity
isa MPackage then
312 mentities
.add_all mentity
.collect_mgroups
(filter
)
313 mentities
.add_all mentity
.collect_mmodules
(filter
)
314 else if mentity
isa MGroup then
315 mentities
.add_all mentity
.collect_mgroups
(filter
)
316 mentities
.add_all mentity
.collect_mmodules
(filter
)
317 else if mentity
isa MModule then
318 mentities
.add_all mentity
.collect_local_mclassdefs
(filter
)
319 else if mentity
isa MClass then
320 mentities
.add_all mentity
.collect_intro_mproperties
(filter
)
321 mentities
.add_all mentity
.collect_redef_mpropdefs
(filter
)
322 else if mentity
isa MClassDef then
323 mentities
.add_all mentity
.collect_intro_mpropdefs
(filter
)
324 mentities
.add_all mentity
.collect_redef_mpropdefs
(filter
)
325 else if mentity
isa MProperty then
326 mentities
.add_all mentity
.collect_mpropdefs
(filter
)
328 return new WarningNoFeatures(mentity
)
330 self.results
= mentities
335 # TODO remove once the filters/sorters are merged
339 redef fun init_results
do
340 if results
!= null then return new CmdSuccess
343 if not res
isa CmdSuccess then return res
344 var mentity
= self.mentity
.as(not null)
346 if mentity
isa MModule then
347 var mentities
= mentity
.collect_intro_mclasses
(filter
).to_a
348 self.results
= mentities
349 else if mentity
isa MClass then
350 var mentities
= mentity
.collect_intro_mproperties
(filter
).to_a
351 self.results
= mentities
352 else if mentity
isa MClassDef then
353 var mentities
= mentity
.collect_intro_mpropdefs
(filter
).to_a
354 mainmodule
.linearize_mpropdefs
(mentities
)
355 self.results
= mentities
357 return new WarningNoFeatures(mentity
)
363 # TODO remove once the filters/sorters are merged
367 redef fun init_results
do
368 if results
!= null then return new CmdSuccess
371 if not res
isa CmdSuccess then return res
372 var mentity
= self.mentity
.as(not null)
374 if mentity
isa MModule then
375 var mentities
= mentity
.collect_redef_mclassdefs
(filter
).to_a
376 self.results
= mentities
377 else if mentity
isa MClass then
378 var mentities
= mentity
.collect_redef_mpropdefs
(filter
).to_a
379 self.results
= mentities
380 else if mentity
isa MClassDef then
381 var mentities
= mentity
.collect_redef_mpropdefs
(filter
).to_a
382 mainmodule
.linearize_mpropdefs
(mentities
)
383 self.results
= mentities
385 return new WarningNoFeatures(mentity
)
391 # TODO remove once the filters/sorters are merged
395 redef fun init_results
do
396 if results
!= null then return new CmdSuccess
399 if not res
isa CmdSuccess then return res
400 var mentity
= self.mentity
.as(not null)
402 if mentity
isa MClass then
403 results
= mentity
.collect_accessible_mproperties
(mainmodule
, filter
).to_a
405 return new WarningNoFeatures(mentity
)
411 # No feature list for `mentity`
412 class WarningNoFeatures
418 redef fun to_s
do return "No features for `{mentity.full_name}`"
421 # Abstract command that returns source-code pieces
422 abstract class CmdCode
425 autoinit
(model
, modelbuilder
, filter
, format
)
427 # ModelBuilder used to get AST nodes
428 var modelbuilder
: ModelBuilder
432 # Set the output format for this piece of code.
433 # Can be "raw", "html" or "ansi".
436 # This format can be different than the format used in the command response.
437 # For example you can choose to render code as HTML inside a JSON object response.
438 # Another example is to render raw format to put into a HTML code tag.
439 var format
= "raw" is optional
, writable
441 # Render `node` depending on the selected `format`
442 fun render_code
(node
: nullable ANode): nullable Writable do
443 if node
== null then return null
444 if format
== "html" then
445 var hl
= new CmdHtmlightVisitor
446 hl
.show_infobox
= false
447 hl
.highlight_node node
449 else if format
== "ansi" then
450 var hl
= new AnsiHighlightVisitor
451 hl
.highlight_node node
454 return node
.location
.text
458 # Custom HtmlightVisitor for commands
460 # We create a new subclass so its behavior can be refined in clients without
461 # breaking the main implementation.
462 class CmdHtmlightVisitor
463 super HtmlightVisitor
466 # Cmd that finds the source code related to an `mentity`
471 autoinit
(model
, modelbuilder
, filter
, mentity
, mentity_name
, format
)
474 var node
: nullable ANode = null is optional
, writable
476 # Same as `CmdEntity::init_mentity`
478 # Plus `WarningNoCode` if no code/AST node is found for `mentity`.
479 redef fun init_command
do
480 if node
!= null then return new CmdSuccess
483 if not res
isa CmdSuccess then return res
484 var mentity
= self.mentity
.as(not null)
486 if mentity
isa MClass then mentity
= mentity
.intro
487 if mentity
isa MProperty then mentity
= mentity
.intro
488 node
= modelbuilder
.mentity2node
(mentity
)
489 if node
== null then return new WarningNoCode(mentity
)
494 # No code for `mentity`
501 redef fun to_s
do return "No code for `{mentity.full_name}`"
506 # A command that returns a list of all mentities in a model
507 class CmdModelEntities
510 # Kind of mentities to be returned.
512 # Value must be one of "packages", "groups", "modules", "classes", "classdefs",
513 # "properties", "propdefs" or "all".
516 var kind
= "all" is optional
, writable
518 # Default limit is `10`
521 redef fun init_results
do
522 if results
!= null then return new CmdSuccess
525 if not res
isa CmdSuccess then return res
527 var mentities
= new Array[MEntity]
528 if kind
== "packages" then
529 mentities
= model
.collect_mpackages
(filter
).to_a
530 else if kind
== "groups" then
531 mentities
= model
.collect_mgroups
(filter
).to_a
532 else if kind
== "modules" then
533 mentities
= model
.collect_mmodules
(filter
).to_a
534 else if kind
== "classes" then
535 mentities
= model
.collect_mclasses
(filter
).to_a
536 else if kind
== "classdefs" then
537 mentities
= model
.collect_mclassdefs
(filter
).to_a
538 else if kind
== "properties" then
539 mentities
= model
.collect_mproperties
(filter
).to_a
540 else if kind
== "propdefs" then
541 mentities
= model
.collect_mpropdefs
(filter
).to_a
543 mentities
= model
.collect_mentities
(filter
).to_a
550 # A command that returns a random list of mentities from a model
551 class CmdRandomEntities
552 super CmdModelEntities
554 # Always return `CmdSuccess`
555 redef fun init_results
do
556 if results
!= null then return new CmdSuccess
558 if not res
isa CmdSuccess then return res
563 # Randomize mentities order
565 var results
= self.results
566 if results
== null then return