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 # Documentation commands
17 # A DocCommand returns data about a model, an entity or a piece of documentation.
19 # Each command assumes a different goal like getting the comment of an entity,
20 # getting a list of packages, getting an UML class diagram etc.
22 # Commands are used by documentation tools to build up documentation ressources
23 # like Nitweb, Nitx, Nitdoc or documentation cards within READMEs.
26 import model
::model_index
29 # Documentation command
31 # An abstract command that works on a Model.
33 # Since they are used by a wide variety of clients, initialization of DocCommands
36 # First, you pass the data you already have to the command at init:
38 # var c1 = new CmdEntity(view, mentity_name = "Array")
39 # var c2 = new CmdEntity(view, mentity = my_entity)
42 # Then, you call `init_command` to initialize the missing field from the stub data:
44 # var r1 = c1.init_command
45 # assert c1.mentity != null
46 # assert r1 isa CmdSuccess
48 # var r2 = c2.init_command
49 # assert c2.mentity_name != null
50 # assert r2 isa CmdSuccess
53 # See `init_command` for more details about the returned statuses.
54 abstract class DocCommand
56 # Model to retrieve data for
59 # ModelFilter to apply if any
60 var filter
: nullable ModelFilter
62 # Initialize the command
64 # Returns a command message that gives the status of the command initialization.
66 # There is 3 categories of messages:
67 # * `CmdSuccess`: when the command that initialized correctly;
68 # * `CmdError`: when the command cannot be initialized;
69 # * `CmdWarning`: when something is wrong with the command but a result still can be produced.
71 # Warnings are generally used to distinguish empty list or mdoc from no data at all.
72 fun init_command
: CmdMessage do return new CmdSuccess
77 # A message returned by a command.
78 # Messages are used to inform the client of the command initialization status and results.
79 # Mostly, messages are used to check if a command is in an error state.
80 abstract class CmdMessage
85 # Returned when the command was performed without any error or warning.
92 # Command errors are returned when the command cannot provide results because
93 # of a problem on the user-end (i.e. Bad command name, MEntity not found etc.).
94 abstract class CmdError
100 # Command warnings are returned when the command cannot provide results because
101 # of a problem on the model-end (i.e. No documentation for a MEntity, no code etc.)
102 abstract class CmdWarning
108 # A command about a MEntity
112 # MEntity this command is about
114 # Alternatively you can provide a `mentity_name`.
115 var mentity
: nullable MEntity = null is optional
, writable
117 # Name of the mentity this command is about
119 # Alternatively you can directly provide the `mentity`.
120 var mentity_name
: nullable String = null is optional
, writable
122 # Initialize the command mentity.
124 # If not already set, tries to find the `mentity` from the `mentity_name`.
126 # This function try to match `mentity_name` both as a `full_name` and
130 # * `CmdSuccess`: everything was ok;
131 # * `ErrorMEntityNoName`: no `mentity` and no `mentity_name` provided;
132 # * `ErrorMEntityNotFound`: no mentity for `mentity_name`;
133 # * `ErrorMEntityConflict`: `mentity_name` was a non-qualified name that
134 # returns more than one MEntity.
135 fun init_mentity
: CmdMessage do
136 if mentity
!= null then
137 if mentity_name
== null then mentity_name
= mentity
.as(not null).full_name
138 return new CmdSuccess
141 var mentity_name
= self.mentity_name
142 if mentity_name
== null or mentity_name
.is_empty
then return new ErrorMEntityNoName
144 mentity
= model
.mentity_by_full_name
(mentity_name
)
145 if mentity
== null then
146 var mentities
= model
.mentities_by_name
(mentity_name
)
147 if mentities
.is_empty
then
148 var suggest
= model
.find
(mentity_name
, 3)
149 return new ErrorMEntityNotFound(mentity_name
, suggest
)
150 else if mentities
.length
> 1 then
151 return new ErrorMEntityConflict(mentity_name
, mentities
)
153 mentity
= mentities
.first
155 return new CmdSuccess
158 # See `init_mentity`.
159 redef fun init_command
do return init_mentity
162 # No MEntity name provided
163 class ErrorMEntityNoName
165 redef fun to_s
do return "No entity name provided"
168 # No MEntity matching `mentity_name`
169 class ErrorMEntityNotFound
172 # MEntity name provided
173 var mentity_name
: String
175 # Suggestions matching the `mentity_name`.
176 var suggestions
: Array[MEntity]
180 res
.append
"No entity for `{mentity_name}`.\n"
181 res
.append
"Did you mean: "
182 for mentity
in suggestions
do
183 res
.append
" `{mentity.full_name}`"
184 if mentity
!= suggestions
.last
then res
.append
","
186 return res
.write_to_string
190 # Multiple MEntities matching `mentity_name`
191 class ErrorMEntityConflict
194 # MEntity name provided
195 var mentity_name
: String
197 # Conflicts for `mentity_name`
198 var conflicts
: Array[MEntity]
202 res
.append
"Multiple entities for `{mentity_name}`:"
203 for mentity
in conflicts
do
204 res
.append
" `{mentity.full_name}`"
205 if mentity
!= conflicts
.last
then res
.append
","
207 return res
.write_to_string
211 # A command that returns a list of results
212 abstract class CmdList
218 # Limit the items in the list
219 var limit
: nullable Int = null is optional
, writable
222 var page
: nullable Int = null is optional
, writable
224 # Total number of ret
225 var count
: nullable Int = null is optional
, writable
227 # Total number of pages
228 var max
: nullable Int = null is optional
, writable
230 # Comparator used to sort the list
231 var sorter
: nullable Comparator = null is writable
234 var results
: nullable Array[ITEM] = null is writable
236 # `init_command` is used to factorize the sorting and pagination of results
238 # See `init_results` for the result list initialization.
239 redef fun init_command
do
241 if not res
isa CmdSuccess then return res
243 if not res
isa CmdSuccess then return res
249 # Initialize the `results` list
251 # This method must be redefined by CmdList subclasses.
252 fun init_results
: CmdMessage do return new CmdSuccess
254 # Sort `mentities` with `sorter`
256 var results
= self.results
257 if results
== null then return
258 var sorter
= self.sorter
259 if sorter
== null then return
263 # Paginate the results
265 # This methods keeps only a subset of `results` depending on the current `page` and the
266 # number of elements to return set by `limit`.
268 # The `count` can be specified when `results` does not contain all the results.
269 # For example when the results are already limited from a DB statement.
271 var results
= self.results
272 if results
== null then return
274 var limit
= self.limit
275 if limit
== null then return
278 if page
== null or page
<= 0 then page
= 1
280 var count
= self.count
281 if count
== null then count
= results
.length
283 var max
= count
/ limit
287 else if page
> max
then
291 var lstart
= (page
- 1) * limit
293 if lstart
+ lend
> count
then lend
= count
- lstart
294 self.results
= results
.subarray
(lstart
, lend
)
302 # A list of mentities
303 abstract class CmdEntities
306 redef type ITEM: MEntity
308 redef var sorter
= new MEntityNameSorter
311 # A command about a MEntity that returns a list of mentities
312 abstract class CmdEntityList
316 autoinit
(model
, filter
, mentity
, mentity_name
, limit
, page
, count
, max
)
318 redef fun init_command
do
319 var res
= init_mentity
320 if not res
isa CmdSuccess then return res
322 if not res
isa CmdSuccess then return res