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
28 # Documentation command
30 # An abstract command that works on a Model.
32 # Since they are used by a wide variety of clients, initialization of DocCommands
35 # First, you pass the data you already have to the command at init:
37 # var c1 = new CmdEntity(view, mentity_name = "Array")
38 # var c2 = new CmdEntity(view, mentity = my_entity)
41 # Then, you call `init_command` to initialize the missing field from the stub data:
43 # var r1 = c1.init_command
44 # assert c1.mentity != null
45 # assert r1 isa CmdSuccess
47 # var r2 = c2.init_command
48 # assert c2.mentity_name != null
49 # assert r2 isa CmdSuccess
52 # See `init_command` for more details about the returned statuses.
53 abstract class DocCommand
55 # Model to retrieve data for
58 # ModelFilter to apply if any
59 var filter
: nullable ModelFilter
61 # Initialize the command
63 # Returns a command message that gives the status of the command initialization.
65 # There is 3 categories of messages:
66 # * `CmdSuccess`: when the command that initialized correctly;
67 # * `CmdError`: when the command cannot be initialized;
68 # * `CmdWarning`: when something is wrong with the command but a result still can be produced.
70 # Warnings are generally used to distinguish empty list or mdoc from no data at all.
71 fun init_command
: CmdMessage do return new CmdSuccess
76 # A message returned by a command.
77 # Messages are used to inform the client of the command initialization status and results.
78 # Mostly, messages are used to check if a command is in an error state.
79 abstract class CmdMessage
84 # Returned when the command was performed without any error or warning.
91 # Command errors are returned when the command cannot provide results because
92 # of a problem on the user-end (i.e. Bad command name, MEntity not found etc.).
93 abstract class CmdError
99 # Command warnings are returned when the command cannot provide results because
100 # of a problem on the model-end (i.e. No documentation for a MEntity, no code etc.)
101 abstract class CmdWarning
107 # A command about a MEntity
111 # MEntity this command is about
113 # Alternatively you can provide a `mentity_name`.
114 var mentity
: nullable MEntity = null is optional
, writable
116 # Name of the mentity this command is about
118 # Alternatively you can directly provide the `mentity`.
119 var mentity_name
: nullable String = null is optional
, writable
121 # Initialize the command mentity.
123 # If not already set, tries to find the `mentity` from the `mentity_name`.
125 # This function try to match `mentity_name` both as a `full_name` and
129 # * `CmdSuccess`: everything was ok;
130 # * `ErrorMEntityNoName`: no `mentity` and no `mentity_name` provided;
131 # * `ErrorMEntityNotFound`: no mentity for `mentity_name`;
132 # * `ErrorMEntityConflict`: `mentity_name` was a non-qualified name that
133 # returns more than one MEntity.
134 fun init_mentity
: CmdMessage do
135 if mentity
!= null then
136 if mentity_name
== null then mentity_name
= mentity
.as(not null).full_name
137 return new CmdSuccess
140 var mentity_name
= self.mentity_name
141 if mentity_name
== null or mentity_name
.is_empty
then return new ErrorMEntityNoName
143 mentity
= model
.mentity_by_full_name
(mentity_name
)
144 if mentity
== null then
145 var mentities
= model
.mentities_by_name
(mentity_name
)
146 if mentities
.is_empty
then
147 var suggest
= model
.find
(mentity_name
, 3)
148 return new ErrorMEntityNotFound(mentity_name
, suggest
)
149 else if mentities
.length
> 1 then
150 return new ErrorMEntityConflict(mentity_name
, mentities
)
152 mentity
= mentities
.first
154 return new CmdSuccess
157 # See `init_mentity`.
158 redef fun init_command
do return init_mentity
161 # No MEntity name provided
162 class ErrorMEntityNoName
164 redef fun to_s
do return "No entity name provided"
167 # No MEntity matching `mentity_name`
168 class ErrorMEntityNotFound
171 # MEntity name provided
172 var mentity_name
: String
174 # Suggestions matching the `mentity_name`.
175 var suggestions
: Array[MEntity]
179 res
.append
"No entity for `{mentity_name}`.\n"
180 res
.append
"Did you mean: "
181 for mentity
in suggestions
do
182 res
.append
" `{mentity.full_name}`"
183 if mentity
!= suggestions
.last
then res
.append
","
185 return res
.write_to_string
189 # Multiple MEntities matching `mentity_name`
190 class ErrorMEntityConflict
193 # MEntity name provided
194 var mentity_name
: String
196 # Conflicts for `mentity_name`
197 var conflicts
: Array[MEntity]
201 res
.append
"Multiple entities for `{mentity_name}`:"
202 for mentity
in conflicts
do
203 res
.append
" `{mentity.full_name}`"
204 if mentity
!= conflicts
.last
then res
.append
","
206 return res
.write_to_string
210 # A command that returns a list of results
211 abstract class CmdList
217 # Limit the items in the list
218 var limit
: nullable Int = null is optional
, writable
221 var page
: nullable Int = null is optional
, writable
223 # Total number of ret
224 var count
: nullable Int = null is optional
, writable
226 # Total number of pages
227 var max
: nullable Int = null is optional
, writable
229 # Comparator used to sort the list
230 var sorter
: nullable Comparator = null is writable
233 var results
: nullable Array[ITEM] = null is writable
235 # `init_command` is used to factorize the sorting and pagination of results
237 # See `init_results` for the result list initialization.
238 redef fun init_command
do
240 if not res
isa CmdSuccess then return res
242 if not res
isa CmdSuccess then return res
248 # Initialize the `results` list
250 # This method must be redefined by CmdList subclasses.
251 fun init_results
: CmdMessage do return new CmdSuccess
253 # Sort `mentities` with `sorter`
255 var results
= self.results
256 if results
== null then return
257 var sorter
= self.sorter
258 if sorter
== null then return
262 # Paginate the results
264 # This methods keeps only a subset of `results` depending on the current `page` and the
265 # number of elements to return set by `limit`.
267 # The `count` can be specified when `results` does not contain all the results.
268 # For example when the results are already limited from a DB statement.
270 var results
= self.results
271 if results
== null then return
273 var limit
= self.limit
274 if limit
== null then return
277 if page
== null or page
<= 0 then page
= 1
279 var count
= self.count
280 if count
== null then count
= results
.length
282 var max
= count
/ limit
286 else if page
> max
then
290 var lstart
= (page
- 1) * limit
292 if lstart
+ lend
> count
then lend
= count
- lstart
293 self.results
= results
.subarray
(lstart
, lend
)
301 # A list of mentities
302 abstract class CmdEntities
305 redef type ITEM: MEntity
307 redef var sorter
= new MEntityNameSorter
310 # A command about a MEntity that returns a list of mentities
311 abstract class CmdEntityList
315 autoinit
(model
, filter
, mentity
, mentity_name
, limit
, page
, count
, max
)
317 redef fun init_command
do
318 var res
= init_mentity
319 if not res
isa CmdSuccess then return res
321 if not res
isa CmdSuccess then return res