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 # MEntity ancestors command
126 # Retrieve all the ancestors (direct and indirect) of a MEntity.
130 # Include direct parents in the ancestors list
133 var parents
= true is optional
, writable
135 redef fun init_results
do
136 if results
!= null then return new CmdSuccess
139 if not res
isa CmdSuccess then return res
140 var mentity
= self.mentity
.as(not null)
142 var ancestors
= mentity
.collect_ancestors
(view
).to_a
148 var parents
= mentity
.collect_parents
(view
)
149 var mentities
= new HashSet[MEntity]
150 for ancestor
in ancestors
do
151 if not parents
.has
(ancestor
) then mentities
.add ancestor
153 results
= mentities
.to_a
158 # MEntity parents command
162 redef fun init_results
do
163 if results
!= null then return new CmdSuccess
166 if not res
isa CmdSuccess then return res
167 var mentity
= self.mentity
.as(not null)
169 results
= mentity
.collect_parents
(view
).to_a
174 # MEntity children command
178 redef fun init_results
do
179 if results
!= null then return new CmdSuccess
182 if not res
isa CmdSuccess then return res
183 var mentity
= self.mentity
.as(not null)
185 results
= mentity
.collect_children
(view
).to_a
190 # MEntity descendants command
194 # Include direct children in the descendants list
197 var children
= true is optional
, writable
199 redef fun init_results
do
200 if results
!= null then return new CmdSuccess
203 if not res
isa CmdSuccess then return res
204 var mentity
= self.mentity
.as(not null)
206 var descendants
= mentity
.collect_descendants
(view
).to_a
208 results
= descendants
212 var children
= mentity
.collect_children
(view
)
213 var mentities
= new HashSet[MEntity]
214 for descendant
in descendants
do
215 if not children
.has
(descendant
) then mentities
.add descendant
217 results
= mentities
.to_a
222 # Linearization command
224 # Collects and linearizes definitions about an MEntity.
225 class CmdLinearization
228 # Same states than `CmdEntity::init_mentity`
230 # Plus returns `WarningNoLinearization` if no linearization can be computed
232 redef fun init_results
do
233 if results
!= null then return new CmdSuccess
236 if not res
isa CmdSuccess then return res
237 var mentity
= self.mentity
.as(not null)
240 results
= mentity
.collect_linearization
(view
.mainmodule
)
241 if results
== null then return new WarningNoLinearization(mentity
)
246 # No linearization computed for `mentity`.
247 class WarningNoLinearization
253 redef fun to_s
do return "No linearization for `{mentity.full_name}`"
256 # A free text search command
260 # Free text command string
261 var query
: nullable String = null is optional
, writable
264 # * `CmdSuccess`: everything was ok;
265 # * `ErrorNoQuery`: no `query` provided.
266 redef fun init_results
do
267 if results
!= null then return new CmdSuccess
270 if not res
isa CmdSuccess then return res
272 var query
= self.query
273 if query
== null then return new ErrorNoQuery
275 results
= view
.find
(query
)
280 # No query string given
284 redef fun to_s
do return "Missing search string"
287 # MEntity feature list
289 # Mostly a list of mentities defined in `mentity`.
293 # Same as `CmdEntity::init_mentity`
295 # Plus `WarningNoFeatures` if no features are found for `mentity`.
296 redef fun init_results
do
297 if results
!= null then return new CmdSuccess
300 if not res
isa CmdSuccess then return res
301 var mentity
= self.mentity
.as(not null)
303 var mentities
= new Array[MEntity]
304 if mentity
isa MPackage then
305 mentities
.add_all mentity
.collect_mgroups
(view
)
306 mentities
.add_all mentity
.collect_mmodules
(view
)
307 else if mentity
isa MGroup then
308 mentities
.add_all mentity
.collect_mgroups
(view
)
309 mentities
.add_all mentity
.collect_mmodules
(view
)
310 else if mentity
isa MModule then
311 mentities
.add_all mentity
.collect_local_mclassdefs
(view
)
312 else if mentity
isa MClass then
313 mentities
.add_all mentity
.collect_intro_mproperties
(view
)
314 mentities
.add_all mentity
.collect_redef_mpropdefs
(view
)
315 else if mentity
isa MClassDef then
316 mentities
.add_all mentity
.collect_intro_mpropdefs
(view
)
317 mentities
.add_all mentity
.collect_redef_mpropdefs
(view
)
318 else if mentity
isa MProperty then
319 mentities
.add_all mentity
.collect_mpropdefs
(view
)
321 return new WarningNoFeatures(mentity
)
323 self.results
= mentities
328 # TODO remove once the filters/sorters are merged
332 redef fun init_results
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_intro_mclasses
(view
).to_a
341 self.results
= mentities
342 else if mentity
isa MClass then
343 var mentities
= mentity
.collect_intro_mproperties
(view
).to_a
344 self.results
= mentities
345 else if mentity
isa MClassDef then
346 var mentities
= mentity
.collect_intro_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_command
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 MModule then
368 var mentities
= mentity
.collect_redef_mclasses
(view
).to_a
369 self.results
= mentities
370 else if mentity
isa MClass then
371 var mentities
= mentity
.collect_redef_mproperties
(view
).to_a
372 self.results
= mentities
373 else if mentity
isa MClassDef then
374 var mentities
= mentity
.collect_redef_mpropdefs
(view
).to_a
375 view
.mainmodule
.linearize_mpropdefs
(mentities
)
376 self.results
= mentities
378 return new WarningNoFeatures(mentity
)
384 # TODO remove once the filters/sorters are merged
388 redef fun init_results
do
389 if results
!= null then return new CmdSuccess
392 if not res
isa CmdSuccess then return res
393 var mentity
= self.mentity
.as(not null)
395 if mentity
isa MClass then
396 results
= mentity
.collect_accessible_mproperties
(view
).to_a
398 return new WarningNoFeatures(mentity
)
404 # No feature list for `mentity`
405 class WarningNoFeatures
411 redef fun to_s
do return "No features for `{mentity.full_name}`"
414 # Abstract command that returns source-code pieces
415 abstract class CmdCode
418 autoinit
(view
, modelbuilder
, format
)
420 # ModelBuilder used to get AST nodes
421 var modelbuilder
: ModelBuilder
425 # Set the output format for this piece of code.
426 # Can be "raw", "html" or "ansi".
429 # This format can be different than the format used in the command response.
430 # For example you can choose to render code as HTML inside a JSON object response.
431 # Another example is to render raw format to put into a HTML code tag.
432 var format
= "raw" is optional
, writable
434 # Render `node` depending on the selected `format`
435 fun render_code
(node
: nullable ANode): nullable Writable do
436 if node
== null then return null
437 if format
== "html" then
438 var hl
= new HtmlightVisitor
439 hl
.highlight_node node
441 else if format
== "ansi" then
442 var hl
= new AnsiHighlightVisitor
443 hl
.highlight_node node
446 return node
.location
.text
450 # Cmd that finds the source code related to an `mentity`
455 autoinit
(view
, modelbuilder
, mentity
, mentity_name
, format
)
458 var node
: nullable ANode = null is optional
, writable
460 # Same as `CmdEntity::init_mentity`
462 # Plus `WarningNoCode` if no code/AST node is found for `mentity`.
463 redef fun init_command
do
464 if node
!= null then return new CmdSuccess
467 if not res
isa CmdSuccess then return res
468 var mentity
= self.mentity
.as(not null)
470 if mentity
isa MClass then mentity
= mentity
.intro
471 if mentity
isa MProperty then mentity
= mentity
.intro
472 node
= modelbuilder
.mentity2node
(mentity
)
473 if node
== null then return new WarningNoCode(mentity
)
478 # No code for `mentity`
485 redef fun to_s
do return "No code for `{mentity.full_name}`"
490 # A command that returns a list of all mentities in a model
491 class CmdModelEntities
494 # Kind of mentities to be returned.
496 # Value must be one of "packages", "groups", "modules", "classes", "classdefs",
497 # "properties", "propdefs" or "all".
500 var kind
= "all" is optional
, writable
502 # Default limit is `10`
505 redef fun init_results
do
506 if results
!= null then return new CmdSuccess
509 if not res
isa CmdSuccess then return res
511 var mentities
= new Array[MEntity]
512 if kind
== "packages" then
513 mentities
= view
.mpackages
.to_a
514 else if kind
== "groups" then
515 mentities
= view
.mgroups
.to_a
516 else if kind
== "modules" then
517 mentities
= view
.mmodules
.to_a
518 else if kind
== "classes" then
519 mentities
= view
.mclasses
.to_a
520 else if kind
== "classdefs" then
521 mentities
= view
.mclassdefs
.to_a
522 else if kind
== "properties" then
523 mentities
= view
.mproperties
.to_a
524 else if kind
== "propdefs" then
525 mentities
= view
.mpropdefs
.to_a
527 mentities
= view
.mentities
.to_a
534 # A command that returns a random list of mentities from a model
535 class CmdRandomEntities
536 super CmdModelEntities
538 # Always return `CmdSuccess`
539 redef fun init_results
do
540 if results
!= null then return new CmdSuccess
542 if not res
isa CmdSuccess then return res
547 # Randomize mentities order
549 var results
= self.results
550 if results
== null then return