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 # MEntity ancestors command
98 # Retrieve all the ancestors (direct and indirect) of a MEntity.
102 # Include direct parents in the ancestors list
105 var parents
= true is optional
, writable
107 redef fun init_results
do
108 if results
!= null then return new CmdSuccess
111 if not res
isa CmdSuccess then return res
112 var mentity
= self.mentity
.as(not null)
114 var ancestors
= mentity
.collect_ancestors
(view
).to_a
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
125 results
= mentities
.to_a
130 # MEntity parents command
134 redef fun init_results
do
135 if results
!= null then return new CmdSuccess
138 if not res
isa CmdSuccess then return res
139 var mentity
= self.mentity
.as(not null)
141 results
= mentity
.collect_parents
(view
).to_a
146 # MEntity children command
150 redef fun init_results
do
151 if results
!= null then return new CmdSuccess
154 if not res
isa CmdSuccess then return res
155 var mentity
= self.mentity
.as(not null)
157 results
= mentity
.collect_children
(view
).to_a
162 # MEntity descendants command
166 # Include direct children in the descendants list
169 var children
= true is optional
, writable
171 redef fun init_results
do
172 if results
!= null then return new CmdSuccess
175 if not res
isa CmdSuccess then return res
176 var mentity
= self.mentity
.as(not null)
178 var descendants
= mentity
.collect_descendants
(view
).to_a
180 results
= descendants
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
189 results
= mentities
.to_a
194 # Linearization command
196 # Collects and linearizes definitions about an MEntity.
197 class CmdLinearization
200 # Same states than `CmdEntity::init_mentity`
202 # Plus returns `WarningNoLinearization` if no linearization can be computed
204 redef fun init_results
do
205 if results
!= null then return new CmdSuccess
208 if not res
isa CmdSuccess then return res
209 var mentity
= self.mentity
.as(not null)
212 results
= mentity
.collect_linearization
(view
.mainmodule
)
213 if results
== null then return new WarningNoLinearization(mentity
)
218 # No linearization computed for `mentity`.
219 class WarningNoLinearization
225 redef fun to_s
do return "No linearization for `{mentity.full_name}`"
228 # A free text search command
232 # Free text command string
233 var query
: nullable String = null is optional
, writable
236 # * `CmdSuccess`: everything was ok;
237 # * `ErrorNoQuery`: no `query` provided.
238 redef fun init_results
do
239 if results
!= null then return new CmdSuccess
242 if not res
isa CmdSuccess then return res
244 var query
= self.query
245 if query
== null then return new ErrorNoQuery
247 results
= view
.find
(query
)
252 # No query string given
256 redef fun to_s
do return "Missing search string"
259 # MEntity feature list
261 # Mostly a list of mentities defined in `mentity`.
265 # Same as `CmdEntity::init_mentity`
267 # Plus `WarningNoFeatures` if no features are found for `mentity`.
268 redef fun init_results
do
269 if results
!= null then return new CmdSuccess
272 if not res
isa CmdSuccess then return res
273 var mentity
= self.mentity
.as(not null)
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
)
293 return new WarningNoFeatures(mentity
)
295 self.results
= mentities
300 # TODO remove once the filters/sorters are merged
304 redef fun init_results
do
305 if results
!= null then return new CmdSuccess
308 if not res
isa CmdSuccess then return res
309 var mentity
= self.mentity
.as(not null)
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
322 return new WarningNoFeatures(mentity
)
328 # TODO remove once the filters/sorters are merged
332 redef fun init_command
do
333 if results
!= null then return new CmdSuccess
336 if not res
isa CmdSuccess then return res
337 var mentity
= self.mentity
.as(not null)
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
350 return new WarningNoFeatures(mentity
)
356 # TODO remove once the filters/sorters are merged
360 redef fun init_results
do
361 if results
!= null then return new CmdSuccess
364 if not res
isa CmdSuccess then return res
365 var mentity
= self.mentity
.as(not null)
367 if mentity
isa MClass then
368 results
= mentity
.collect_accessible_mproperties
(view
).to_a
370 return new WarningNoFeatures(mentity
)
376 # No feature list for `mentity`
377 class WarningNoFeatures
383 redef fun to_s
do return "No features for `{mentity.full_name}`"
386 # Abstract command that returns source-code pieces
387 abstract class CmdCode
390 autoinit
(view
, modelbuilder
, format
)
392 # ModelBuilder used to get AST nodes
393 var modelbuilder
: ModelBuilder
397 # Set the output format for this piece of code.
398 # Can be "raw", "html" or "ansi".
401 # This format can be different than the format used in the command response.
402 # For example you can choose to render code as HTML inside a JSON object response.
403 # Another example is to render raw format to put into a HTML code tag.
404 var format
= "raw" is optional
, writable
406 # Render `node` depending on the selected `format`
407 fun render_code
(node
: nullable ANode): nullable Writable do
408 if node
== null then return null
409 if format
== "html" then
410 var hl
= new HtmlightVisitor
411 hl
.highlight_node node
413 else if format
== "ansi" then
414 var hl
= new AnsiHighlightVisitor
415 hl
.highlight_node node
418 return node
.location
.text
422 # Cmd that finds the source code related to an `mentity`
427 autoinit
(view
, modelbuilder
, mentity
, mentity_name
, format
)
430 var node
: nullable ANode = null is optional
, writable
432 # Same as `CmdEntity::init_mentity`
434 # Plus `WarningNoCode` if no code/AST node is found for `mentity`.
435 redef fun init_command
do
436 if node
!= null then return new CmdSuccess
439 if not res
isa CmdSuccess then return res
440 var mentity
= self.mentity
.as(not null)
442 if mentity
isa MClass then mentity
= mentity
.intro
443 if mentity
isa MProperty then mentity
= mentity
.intro
444 node
= modelbuilder
.mentity2node
(mentity
)
445 if node
== null then return new WarningNoCode(mentity
)
450 # No code for `mentity`
457 redef fun to_s
do return "No code for `{mentity.full_name}`"
462 # A command that returns a list of all mentities in a model
463 class CmdModelEntities
466 # Kind of mentities to be returned.
468 # Value must be one of "packages", "groups", "modules", "classes", "classdefs",
469 # "properties", "propdefs" or "all".
472 var kind
= "all" is optional
, writable
474 # Default limit is `10`
477 redef fun init_results
do
478 if results
!= null then return new CmdSuccess
481 if not res
isa CmdSuccess then return res
483 var mentities
= new Array[MEntity]
484 if kind
== "packages" then
485 mentities
= view
.mpackages
.to_a
486 else if kind
== "groups" then
487 mentities
= view
.mgroups
.to_a
488 else if kind
== "modules" then
489 mentities
= view
.mmodules
.to_a
490 else if kind
== "classes" then
491 mentities
= view
.mclasses
.to_a
492 else if kind
== "classdefs" then
493 mentities
= view
.mclassdefs
.to_a
494 else if kind
== "properties" then
495 mentities
= view
.mproperties
.to_a
496 else if kind
== "propdefs" then
497 mentities
= view
.mpropdefs
.to_a
499 mentities
= view
.mentities
.to_a
506 # A command that returns a random list of mentities from a model
507 class CmdRandomEntities
508 super CmdModelEntities
510 # Always return `CmdSuccess`
511 redef fun init_results
do
512 if results
!= null then return new CmdSuccess
514 if not res
isa CmdSuccess then return res
519 # Randomize mentities order
521 var results
= self.results
522 if results
== null then return