# This file is part of NIT ( http://www.nitlanguage.org ). # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Doc commands about a Model or a MEntity # # This module defines several commands to retrieve data about a Model and MEntities. module commands_model import commands_base import model::model_collect import modelize import modelbuilder import highlight import doc_down # Retrieve the MDoc related to a MEntity class CmdComment super CmdEntity # Allow fallback # # If `true`, the command uses `mdoc_or_fallback`. # Default is `true`. var fallback = true is optional, writable # Retrieve the full documentation # # If `true`, retrieves the full documentation. # If `false`, retrieves only the synopsis. # Default is `true`. # # Since the rendering the final string (md, html...) depends on the kind of # client, the handling of this option is delegated to submodules. var full_doc = true is optional, writable # Format to render the comment # # Can be one of `raw` or `html`. # Default is `raw`. var format = "raw" is optional, writable # MDoc to return var mdoc: nullable MDoc = null is optional, writable # Same states than `CmdEntity::init_mentity` # # Plus returns `WarningNoMDoc` if no MDoc was found for the MEntity. redef fun init_command do var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) if mdoc == null then mdoc = if fallback then mentity.mdoc_or_fallback else mentity.mdoc end if mdoc == null then return new WarningNoMDoc(mentity) return res end # Render `mdoc` depending on `full_doc` and `format` fun render: nullable Writable do var mdoc = self.mdoc if mdoc == null then return null if format == "html" then if full_doc then return mdoc.html_documentation return mdoc.html_synopsis end if full_doc then return mdoc.documentation return mdoc.synopsis end end # No MDoc for `mentity` class WarningNoMDoc super CmdWarning # MEntity provided var mentity: MEntity redef fun to_s do return "No documentation for `{mentity.full_name}`." end # MEntity ancestors command # # Retrieve all the ancestors (direct and indirect) of a MEntity. class CmdAncestors super CmdEntityList # Include direct parents in the ancestors list # # Default is `true`. var parents = true is optional, writable redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) var ancestors = mentity.collect_ancestors(view).to_a if parents then results = ancestors return res end var parents = mentity.collect_parents(view) var mentities = new HashSet[MEntity] for ancestor in ancestors do if not parents.has(ancestor) then mentities.add ancestor end results = mentities.to_a return res end end # MEntity parents command class CmdParents super CmdEntityList redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) results = mentity.collect_parents(view).to_a return res end end # MEntity children command class CmdChildren super CmdEntityList redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) results = mentity.collect_children(view).to_a return res end end # MEntity descendants command class CmdDescendants super CmdEntityList # Include direct children in the descendants list # # Default is `true`. var children = true is optional, writable redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) var descendants = mentity.collect_descendants(view).to_a if children then results = descendants return res end var children = mentity.collect_children(view) var mentities = new HashSet[MEntity] for descendant in descendants do if not children.has(descendant) then mentities.add descendant end results = mentities.to_a return res end end # Linearization command # # Collects and linearizes definitions about an MEntity. class CmdLinearization super CmdEntityList # Same states than `CmdEntity::init_mentity` # # Plus returns `WarningNoLinearization` if no linearization can be computed # from the mentity. redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) sorter = null results = mentity.collect_linearization(view.mainmodule) if results == null then return new WarningNoLinearization(mentity) return res end end # No linearization computed for `mentity`. class WarningNoLinearization super CmdWarning # MEntity provided var mentity: MEntity redef fun to_s do return "No linearization for `{mentity.full_name}`" end # A free text search command class CmdSearch super CmdEntities # Free text command string var query: nullable String = null is optional, writable # Return states: # * `CmdSuccess`: everything was ok; # * `ErrorNoQuery`: no `query` provided. redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var query = self.query if query == null then return new ErrorNoQuery sorter = null results = view.find(query) return res end end # No query string given class ErrorNoQuery super CmdError redef fun to_s do return "Missing search string" end # MEntity feature list # # Mostly a list of mentities defined in `mentity`. class CmdFeatures super CmdEntityList # Same as `CmdEntity::init_mentity` # # Plus `WarningNoFeatures` if no features are found for `mentity`. redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) var mentities = new Array[MEntity] if mentity isa MPackage then mentities.add_all mentity.collect_mgroups(view) mentities.add_all mentity.collect_mmodules(view) else if mentity isa MGroup then mentities.add_all mentity.collect_mgroups(view) mentities.add_all mentity.collect_mmodules(view) else if mentity isa MModule then mentities.add_all mentity.collect_local_mclassdefs(view) else if mentity isa MClass then mentities.add_all mentity.collect_intro_mproperties(view) mentities.add_all mentity.collect_redef_mpropdefs(view) else if mentity isa MClassDef then mentities.add_all mentity.collect_intro_mpropdefs(view) mentities.add_all mentity.collect_redef_mpropdefs(view) else if mentity isa MProperty then mentities.add_all mentity.collect_mpropdefs(view) else return new WarningNoFeatures(mentity) end self.results = mentities return res end end # TODO remove once the filters/sorters are merged class CmdIntros super CmdEntityList redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) if mentity isa MModule then var mentities = mentity.collect_intro_mclasses(view).to_a self.results = mentities else if mentity isa MClass then var mentities = mentity.collect_intro_mproperties(view).to_a self.results = mentities else if mentity isa MClassDef then var mentities = mentity.collect_intro_mpropdefs(view).to_a view.mainmodule.linearize_mpropdefs(mentities) self.results = mentities else return new WarningNoFeatures(mentity) end return res end end # TODO remove once the filters/sorters are merged class CmdRedefs super CmdEntityList redef fun init_command do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) if mentity isa MModule then var mentities = mentity.collect_redef_mclasses(view).to_a self.results = mentities else if mentity isa MClass then var mentities = mentity.collect_redef_mproperties(view).to_a self.results = mentities else if mentity isa MClassDef then var mentities = mentity.collect_redef_mpropdefs(view).to_a view.mainmodule.linearize_mpropdefs(mentities) self.results = mentities else return new WarningNoFeatures(mentity) end return res end end # TODO remove once the filters/sorters are merged class CmdAllProps super CmdEntityList redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) if mentity isa MClass then results = mentity.collect_accessible_mproperties(view).to_a else return new WarningNoFeatures(mentity) end return res end end # No feature list for `mentity` class WarningNoFeatures super CmdWarning # MEntity provided var mentity: MEntity redef fun to_s do return "No features for `{mentity.full_name}`" end # Cmd that finds the source code related to an `mentity` class CmdCode super CmdEntity autoinit(view, modelbuilder, mentity, mentity_name, format) # ModelBuilder used to get AST nodes var modelbuilder: ModelBuilder # AST node to return var node: nullable ANode = null is optional, writable # Rendering format # # Set the output format for this piece of code. # Can be "raw" or "html". # Default is "raw". # # This format can be different than the format used in the command response. # For example you can choose to render code as HTML inside a JSON object response. # Another example is to render raw format to put into a HTML code tag. var format = "raw" is optional, writable # Same as `CmdEntity::init_mentity` # # Plus `WarningNoCode` if no code/AST node is found for `mentity`. redef fun init_command do if node != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentity = self.mentity.as(not null) if mentity isa MClass then mentity = mentity.intro if mentity isa MProperty then mentity = mentity.intro node = modelbuilder.mentity2node(mentity) if node == null then return new WarningNoCode(mentity) return res end # Render `node` depending on the selected `format` fun render: nullable Writable do var node = self.node if node == null then return null if format == "html" then var hl = new HighlightVisitor hl.enter_visit node return hl.html end # TODO make a raw visitor return node.to_s end end # No code for `mentity` class WarningNoCode super CmdWarning # MEntity provided var mentity: MEntity redef fun to_s do return "No code for `{mentity.full_name}`" end # Model commands # A command that returns a list of all mentities in a model class CmdModelEntities super CmdEntities # Kind of mentities to be returned. # # Value must be one of "packages", "groups", "modules", "classes", "classdefs", # "properties", "propdefs" or "all". # # Default is "all". var kind = "all" is optional, writable # Default limit is `10` redef var limit = 10 redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res var mentities = new Array[MEntity] if kind == "packages" then mentities = view.mpackages.to_a else if kind == "groups" then mentities = view.mgroups.to_a else if kind == "modules" then mentities = view.mmodules.to_a else if kind == "classes" then mentities = view.mclasses.to_a else if kind == "classdefs" then mentities = view.mclassdefs.to_a else if kind == "properties" then mentities = view.mproperties.to_a else if kind == "propdefs" then mentities = view.mpropdefs.to_a else mentities = view.mentities.to_a end results = mentities return res end end # A command that returns a random list of mentities from a model class CmdRandomEntities super CmdModelEntities # Always return `CmdSuccess` redef fun init_results do if results != null then return new CmdSuccess var res = super if not res isa CmdSuccess then return res randomize return res end # Randomize mentities order fun randomize do var results = self.results if results == null then return results.shuffle end end