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
73 # Return a new filter for that command execution.
74 fun cmd_filter
: ModelFilter do
75 var filter
= self.filter
76 if filter
== null then return new ModelFilter
77 return new ModelFilter.from
(filter
)
83 # A message returned by a command.
84 # Messages are used to inform the client of the command initialization status and results.
85 # Mostly, messages are used to check if a command is in an error state.
86 abstract class CmdMessage
91 # Returned when the command was performed without any error or warning.
98 # Command errors are returned when the command cannot provide results because
99 # of a problem on the user-end (i.e. Bad command name, MEntity not found etc.).
100 abstract class CmdError
106 # Command warnings are returned when the command cannot provide results because
107 # of a problem on the model-end (i.e. No documentation for a MEntity, no code etc.)
108 abstract class CmdWarning
114 # A command about a MEntity
118 # MEntity this command is about
120 # Alternatively you can provide a `mentity_name`.
121 var mentity
: nullable MEntity = null is optional
, writable
123 # Name of the mentity this command is about
125 # Alternatively you can directly provide the `mentity`.
126 var mentity_name
: nullable String = null is optional
, writable
128 # Initialize the command mentity.
130 # If not already set, tries to find the `mentity` from the `mentity_name`.
132 # This function try to match `mentity_name` both as a `full_name` and
136 # * `CmdSuccess`: everything was ok;
137 # * `ErrorMEntityNoName`: no `mentity` and no `mentity_name` provided;
138 # * `ErrorMEntityNotFound`: no mentity for `mentity_name`;
139 # * `ErrorMEntityConflict`: `mentity_name` was a non-qualified name that
140 # returns more than one MEntity.
141 fun init_mentity
: CmdMessage do
142 if mentity
!= null then
143 if mentity_name
== null then mentity_name
= mentity
.as(not null).full_name
144 return new CmdSuccess
147 var mentity_name
= self.mentity_name
148 if mentity_name
== null or mentity_name
.is_empty
then return new ErrorMEntityNoName
150 mentity
= model
.mentity_by_full_name
(mentity_name
)
151 if mentity
== null then
152 var mentities
= model
.mentities_by_name
(mentity_name
)
153 if mentities
.is_empty
then
154 var suggest
= model
.find
(mentity_name
, 3)
155 return new ErrorMEntityNotFound(mentity_name
, suggest
)
156 else if mentities
.length
> 1 then
157 return new ErrorMEntityConflict(mentity_name
, mentities
)
159 mentity
= mentities
.first
161 return new CmdSuccess
164 # See `init_mentity`.
165 redef fun init_command
do return init_mentity
168 # No MEntity name provided
169 class ErrorMEntityNoName
171 redef fun to_s
do return "No entity name provided"
174 # No MEntity matching `mentity_name`
175 class ErrorMEntityNotFound
178 # MEntity name provided
179 var mentity_name
: String
181 # Suggestions matching the `mentity_name`.
182 var suggestions
: Array[MEntity]
186 res
.append
"No entity for `{mentity_name}`.\n"
187 res
.append
"Did you mean: "
188 for mentity
in suggestions
do
189 res
.append
" `{mentity.full_name}`"
190 if mentity
!= suggestions
.last
then res
.append
","
192 return res
.write_to_string
196 # Multiple MEntities matching `mentity_name`
197 class ErrorMEntityConflict
200 # MEntity name provided
201 var mentity_name
: String
203 # Conflicts for `mentity_name`
204 var conflicts
: Array[MEntity]
208 res
.append
"Multiple entities for `{mentity_name}`:"
209 for mentity
in conflicts
do
210 res
.append
" `{mentity.full_name}`"
211 if mentity
!= conflicts
.last
then res
.append
","
213 return res
.write_to_string
217 # A command that returns a list of results
218 abstract class CmdList
224 # Limit the items in the list
225 var limit
: nullable Int = null is optional
, writable
228 var page
: nullable Int = null is optional
, writable
230 # Total number of ret
231 var count
: nullable Int = null is optional
, writable
233 # Total number of pages
234 var max
: nullable Int = null is optional
, writable
236 # Comparator used to sort the list
237 var sorter
: nullable Comparator = null is writable
240 var results
: nullable Array[ITEM] = null is writable
242 # `init_command` is used to factorize the sorting and pagination of results
244 # See `init_results` for the result list initialization.
245 redef fun init_command
do
247 if not res
isa CmdSuccess then return res
249 if not res
isa CmdSuccess then return res
255 # Initialize the `results` list
257 # This method must be redefined by CmdList subclasses.
258 fun init_results
: CmdMessage do return new CmdSuccess
260 # Sort `mentities` with `sorter`
262 var results
= self.results
263 if results
== null then return
264 var sorter
= self.sorter
265 if sorter
== null then return
269 # Paginate the results
271 # This methods keeps only a subset of `results` depending on the current `page` and the
272 # number of elements to return set by `limit`.
274 # The `count` can be specified when `results` does not contain all the results.
275 # For example when the results are already limited from a DB statement.
277 var results
= self.results
278 if results
== null then return
280 var limit
= self.limit
281 if limit
== null then return
284 if page
== null or page
<= 0 then page
= 1
286 var count
= self.count
287 if count
== null then count
= results
.length
289 var max
= count
/ limit
293 else if page
> max
then
297 var lstart
= (page
- 1) * limit
299 if lstart
+ lend
> count
then lend
= count
- lstart
300 self.results
= results
.subarray
(lstart
, lend
)
308 # A list of mentities
309 abstract class CmdEntities
312 redef type ITEM: MEntity
314 redef var sorter
= new MEntityNameSorter
317 # A command about a MEntity that returns a list of mentities
318 abstract class CmdEntityList
322 autoinit
(model
, filter
, mentity
, mentity_name
, limit
, page
, count
, max
)
324 redef fun init_command
do
325 var res
= init_mentity
326 if not res
isa CmdSuccess then return res
328 if not res
isa CmdSuccess then return res