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
28 # Retrieve the MDoc related to a MEntity
34 # If `true`, the command uses `mdoc_or_fallback`.
36 var fallback
= true is optional
, writable
38 # Retrieve the full documentation
40 # If `true`, retrieves the full documentation.
41 # If `false`, retrieves only the synopsis.
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
48 # Format to render the comment
50 # Can be one of `raw` or `html`.
52 var format
= "raw" is optional
, writable
55 var mdoc
: nullable MDoc = null is optional
, writable
57 # Same states than `CmdEntity::init_mentity`
59 # Plus returns `WarningNoMDoc` if no MDoc was found for the MEntity.
60 redef fun init_command
do
62 if not res
isa CmdSuccess then return res
63 var mentity
= self.mentity
.as(not null)
66 mdoc
= if fallback
then mentity
.mdoc_or_fallback
else mentity
.mdoc
68 if mdoc
== null then return new WarningNoMDoc(mentity
)
72 # Render `mdoc` depending on `full_doc` and `format`
73 fun render_comment
: nullable Writable do
75 if mdoc
== null then return null
77 if format
== "html" then
78 if full_doc
then return mdoc
.html_documentation
79 return mdoc
.html_synopsis
81 if full_doc
then return mdoc
.documentation
86 # No MDoc for `mentity`
93 redef fun to_s
do return "No documentation for `{mentity.full_name}`."
96 # Get the link to a MEntity API documentation
100 # The link text to display
101 var text
: nullable String = null is optional
, writable
103 # The link title to display when the link is hovered
104 var title
: nullable String = null is optional
, writable
106 redef fun init_command
do
108 if not res
isa CmdSuccess then return res
109 var mentity
= self.mentity
.as(not null)
114 if title
== null then
115 var mdoc
= mentity
.mdoc_or_fallback
117 title
= mdoc
.synopsis
124 # An abstract inheritance command
126 # For things like ancestors, parents, children and descendants.
127 abstract class CmdInheritance
130 autoinit
(model
, mainmodule
, filter
, mentity
, mentity_name
, limit
, page
, count
, max
)
132 # Mainmodule for class linearization
133 var mainmodule
: MModule
136 # MEntity ancestors command
138 # Retrieve all the ancestors (direct and indirect) of a MEntity.
142 # Include direct parents in the ancestors list
145 var parents
= true is optional
, writable
147 redef fun init_results
do
148 if results
!= null then return new CmdSuccess
151 if not res
isa CmdSuccess then return res
152 var mentity
= self.mentity
.as(not null)
154 var ancestors
= mentity
.collect_ancestors
(mainmodule
, filter
).to_a
160 var parents
= mentity
.collect_parents
(mainmodule
, filter
)
161 var mentities
= new HashSet[MEntity]
162 for ancestor
in ancestors
do
163 if not parents
.has
(ancestor
) then mentities
.add ancestor
165 results
= mentities
.to_a
170 # MEntity parents command
174 redef fun init_results
do
175 if results
!= null then return new CmdSuccess
178 if not res
isa CmdSuccess then return res
179 var mentity
= self.mentity
.as(not null)
181 results
= mentity
.collect_parents
(mainmodule
, filter
).to_a
186 # MEntity children command
190 redef fun init_results
do
191 if results
!= null then return new CmdSuccess
194 if not res
isa CmdSuccess then return res
195 var mentity
= self.mentity
.as(not null)
197 results
= mentity
.collect_children
(mainmodule
, filter
).to_a
202 # MEntity descendants command
206 # Include direct children in the descendants list
209 var children
= true is optional
, writable
211 redef fun init_results
do
212 if results
!= null then return new CmdSuccess
215 if not res
isa CmdSuccess then return res
216 var mentity
= self.mentity
.as(not null)
218 var descendants
= mentity
.collect_descendants
(mainmodule
, filter
).to_a
220 results
= descendants
224 var children
= mentity
.collect_children
(mainmodule
, filter
)
225 var mentities
= new HashSet[MEntity]
226 for descendant
in descendants
do
227 if not children
.has
(descendant
) then mentities
.add descendant
229 results
= mentities
.to_a
234 # Linearization command
236 # Collects and linearizes definitions about an MEntity.
237 class CmdLinearization
240 # Same states than `CmdEntity::init_mentity`
242 # Plus returns `WarningNoLinearization` if no linearization can be computed
244 redef fun init_results
do
245 if results
!= null then return new CmdSuccess
248 if not res
isa CmdSuccess then return res
249 var mentity
= self.mentity
.as(not null)
252 results
= mentity
.collect_linearization
(mainmodule
)
253 if results
== null then return new WarningNoLinearization(mentity
)
258 # No linearization computed for `mentity`.
259 class WarningNoLinearization
265 redef fun to_s
do return "No linearization for `{mentity.full_name}`"
268 # A free text search command
272 # Free text command string
273 var query
: nullable String = null is optional
, writable
276 # * `CmdSuccess`: everything was ok;
277 # * `ErrorNoQuery`: no `query` provided.
278 redef fun init_results
do
279 if results
!= null then return new CmdSuccess
282 if not res
isa CmdSuccess then return res
284 var query
= self.query
285 if query
== null then return new ErrorNoQuery
287 results
= model
.find
(query
)
292 # No query string given
296 redef fun to_s
do return "Missing search string"
299 # MEntity feature list
301 # Mostly a list of mentities defined in `mentity`.
305 # Same as `CmdEntity::init_mentity`
307 # Plus `WarningNoFeatures` if no features are found for `mentity`.
308 redef fun init_results
do
309 if results
!= null then return new CmdSuccess
312 if not res
isa CmdSuccess then return res
313 var mentity
= self.mentity
.as(not null)
315 var mentities
= new Array[MEntity]
316 if mentity
isa MPackage then
317 mentities
.add_all mentity
.collect_mgroups
(filter
)
318 mentities
.add_all mentity
.collect_mmodules
(filter
)
319 else if mentity
isa MGroup then
320 mentities
.add_all mentity
.collect_mgroups
(filter
)
321 mentities
.add_all mentity
.collect_mmodules
(filter
)
322 else if mentity
isa MModule then
323 mentities
.add_all mentity
.collect_local_mclassdefs
(filter
)
324 else if mentity
isa MClass then
325 mentities
.add_all mentity
.collect_intro_mproperties
(filter
)
326 mentities
.add_all mentity
.collect_redef_mpropdefs
(filter
)
327 else if mentity
isa MClassDef then
328 mentities
.add_all mentity
.collect_intro_mpropdefs
(filter
)
329 mentities
.add_all mentity
.collect_redef_mpropdefs
(filter
)
330 else if mentity
isa MProperty then
331 mentities
.add_all mentity
.collect_mpropdefs
(filter
)
333 return new WarningNoFeatures(mentity
)
335 self.results
= mentities
340 # TODO remove once the filters/sorters are merged
344 redef fun init_results
do
345 if results
!= null then return new CmdSuccess
348 if not res
isa CmdSuccess then return res
349 var mentity
= self.mentity
.as(not null)
351 if mentity
isa MModule then
352 var mentities
= mentity
.collect_intro_mclasses
(filter
).to_a
353 self.results
= mentities
354 else if mentity
isa MClass then
355 var mentities
= mentity
.collect_intro_mproperties
(filter
).to_a
356 self.results
= mentities
357 else if mentity
isa MClassDef then
358 var mentities
= mentity
.collect_intro_mpropdefs
(filter
).to_a
359 mainmodule
.linearize_mpropdefs
(mentities
)
360 self.results
= mentities
362 return new WarningNoFeatures(mentity
)
368 # TODO remove once the filters/sorters are merged
372 redef fun init_command
do
373 if results
!= null then return new CmdSuccess
376 if not res
isa CmdSuccess then return res
377 var mentity
= self.mentity
.as(not null)
379 if mentity
isa MModule then
380 var mentities
= mentity
.collect_redef_mclasses
(filter
).to_a
381 self.results
= mentities
382 else if mentity
isa MClass then
383 var mentities
= mentity
.collect_redef_mproperties
(filter
).to_a
384 self.results
= mentities
385 else if mentity
isa MClassDef then
386 var mentities
= mentity
.collect_redef_mpropdefs
(filter
).to_a
387 mainmodule
.linearize_mpropdefs
(mentities
)
388 self.results
= mentities
390 return new WarningNoFeatures(mentity
)
396 # TODO remove once the filters/sorters are merged
400 redef fun init_results
do
401 if results
!= null then return new CmdSuccess
404 if not res
isa CmdSuccess then return res
405 var mentity
= self.mentity
.as(not null)
407 if mentity
isa MClass then
408 results
= mentity
.collect_accessible_mproperties
(mainmodule
, filter
).to_a
410 return new WarningNoFeatures(mentity
)
416 # No feature list for `mentity`
417 class WarningNoFeatures
423 redef fun to_s
do return "No features for `{mentity.full_name}`"
426 # Abstract command that returns source-code pieces
427 abstract class CmdCode
430 autoinit
(model
, modelbuilder
, filter
, format
)
432 # ModelBuilder used to get AST nodes
433 var modelbuilder
: ModelBuilder
437 # Set the output format for this piece of code.
438 # Can be "raw", "html" or "ansi".
441 # This format can be different than the format used in the command response.
442 # For example you can choose to render code as HTML inside a JSON object response.
443 # Another example is to render raw format to put into a HTML code tag.
444 var format
= "raw" is optional
, writable
446 # Render `node` depending on the selected `format`
447 fun render_code
(node
: nullable ANode): nullable Writable do
448 if node
== null then return null
449 if format
== "html" then
450 var hl
= new HtmlightVisitor
451 hl
.highlight_node node
453 else if format
== "ansi" then
454 var hl
= new AnsiHighlightVisitor
455 hl
.highlight_node node
458 return node
.location
.text
462 # Cmd that finds the source code related to an `mentity`
467 autoinit
(model
, modelbuilder
, filter
, mentity
, mentity_name
, format
)
470 var node
: nullable ANode = null is optional
, writable
472 # Same as `CmdEntity::init_mentity`
474 # Plus `WarningNoCode` if no code/AST node is found for `mentity`.
475 redef fun init_command
do
476 if node
!= null then return new CmdSuccess
479 if not res
isa CmdSuccess then return res
480 var mentity
= self.mentity
.as(not null)
482 if mentity
isa MClass then mentity
= mentity
.intro
483 if mentity
isa MProperty then mentity
= mentity
.intro
484 node
= modelbuilder
.mentity2node
(mentity
)
485 if node
== null then return new WarningNoCode(mentity
)
490 # No code for `mentity`
497 redef fun to_s
do return "No code for `{mentity.full_name}`"
502 # A command that returns a list of all mentities in a model
503 class CmdModelEntities
506 # Kind of mentities to be returned.
508 # Value must be one of "packages", "groups", "modules", "classes", "classdefs",
509 # "properties", "propdefs" or "all".
512 var kind
= "all" is optional
, writable
514 # Default limit is `10`
517 redef fun init_results
do
518 if results
!= null then return new CmdSuccess
521 if not res
isa CmdSuccess then return res
523 var mentities
= new Array[MEntity]
524 if kind
== "packages" then
525 mentities
= model
.collect_mpackages
(filter
).to_a
526 else if kind
== "groups" then
527 mentities
= model
.collect_mgroups
(filter
).to_a
528 else if kind
== "modules" then
529 mentities
= model
.collect_mmodules
(filter
).to_a
530 else if kind
== "classes" then
531 mentities
= model
.collect_mclasses
(filter
).to_a
532 else if kind
== "classdefs" then
533 mentities
= model
.collect_mclassdefs
(filter
).to_a
534 else if kind
== "properties" then
535 mentities
= model
.collect_mproperties
(filter
).to_a
536 else if kind
== "propdefs" then
537 mentities
= model
.collect_mpropdefs
(filter
).to_a
539 mentities
= model
.collect_mentities
(filter
).to_a
546 # A command that returns a random list of mentities from a model
547 class CmdRandomEntities
548 super CmdModelEntities
550 # Always return `CmdSuccess`
551 redef fun init_results
do
552 if results
!= null then return new CmdSuccess
554 if not res
isa CmdSuccess then return res
559 # Randomize mentities order
561 var results
= self.results
562 if results
== null then return