1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
23 var content
: String = ""
24 fun add
(text
: String) do addn
("{text}\n")
25 fun addn
(text
: String) do content
+= text
.escape
26 fun add_rule
do add
("\n---\n")
27 fun render
do sys
.system
("echo \"{content}\
" | pager -r")
31 private var toolcontext
: ToolContext
32 private var model
: Model
33 private var mbuilder
: ModelBuilder
34 private var mainmodule
: MModule
35 private var arguments
: Array[String]
37 init(toolcontext
: ToolContext) do
38 # We need a model to collect stufs
39 self.toolcontext
= toolcontext
40 self.arguments
= toolcontext
.option_context
.rest
42 if arguments
.length
> 2 then
43 print
"usage: ni path/to/module.nit [expression]"
44 toolcontext
.option_context
.usage
49 mbuilder
= new ModelBuilder(model
, toolcontext
)
51 # Here we load an process std modules
52 #var dir = "NIT_DIR".environ
53 #var mmodules = modelbuilder.parse_and_build(["{dir}/lib/standard/standard.nit"])
54 var mmodules
= mbuilder
.parse_and_build
([arguments
.first
])
55 if mmodules
.is_empty
then return
56 mbuilder
.full_propdef_semantic_analysis
57 assert mmodules
.length
== 1
58 self.mainmodule
= mmodules
.first
62 if arguments
.length
== 1 then
71 print
"Welcome in Nit Index.\n"
72 print
"Loaded modules"
73 for m
in mbuilder
.nmodules
do
74 print
" - {m.mmodule.name}"
76 print
"\nEnter the module, class or property name you want to look up."
77 print
"Enter a blank line to exit.\n"
85 fun seek
(entry
: String) do
87 if entry
.is_empty
then exit
(0)
90 for n
in mbuilder
.nmodules
do
92 if m
.name
== entry
then
97 for c
in model
.mclasses
do
98 if c
.name
== entry
then
99 if not mbuilder
.mclassdef2nclassdef
[c
.intro
] isa AStdClassdef then continue
104 var matches
= new List[MProperty]
105 for p
in model
.mproperties
do
106 if p
.name
== entry
then
111 #if not matches.is_empty then doc_properties
113 if not flag
then print
"Nothing known about '{entry}'"
114 if arguments
.length
== 1 then prompt
117 private fun module_fulldoc
(nmodule
: AModule) do
118 var mmodule
= nmodule
.mmodule
119 var pager
= new Pager
120 pager
.add
("# module {mmodule.name}\n".bold
)
121 pager
.add
("import {mmodule.in_importation.direct_greaters.join(", ")}")
123 pager
.addn
(nmodule
.comment
.green
)
126 var cats
= new HashMap[String, Collection[MClass]]
127 cats
["introduced classes"] = mmodule
.intro_mclasses
128 cats
["refined classes"] = mmodule
.redef_mclasses
129 cats
["inherited classes"] = mmodule
.inherited_mclasses
131 for cat
, list
in cats
do
132 if not list
.is_empty
then
133 pager
.add
("# {cat}\n".bold
)
134 for mclass
in list
do
135 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
].as(AStdClassdef)
136 if not nclass
.short_comment
.is_empty
then
137 pager
.add
("\t# {nclass.short_comment}")
139 if cat
== "refined classes" then
140 pager
.add
("\tredef {mclass.short_doc}")
142 pager
.add
("\t{mclass.short_doc}")
144 if not mclass
.intro_mmodule
== mmodule
then
145 pager
.add
("\t\tintroduced in {mmodule.full_name}::{mclass}".gray
)
155 fun doc_class
(mclass
: MClass) do
156 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
].as(AStdClassdef)
157 var pager
= new Pager
158 pager
.add
("# {mclass.intro_mmodule.public_owner.name}::{mclass.name}\n".bold
)
159 pager
.add
("{mclass.short_doc} ")
161 pager
.addn
(nclass
.comment
.green
)
166 var cats
= new HashMap[String, Collection[MMethod]]
167 cats
["constructors"] = mclass
.constructors
168 cats
["introduced methods"] = mclass
.intro_methods
169 cats
["refined methods"] = mclass
.redef_methods
170 cats
["inherited methods"] = mclass
.inherited_methods
172 for cat
, list
in cats
do
173 if not list
.is_empty
then
174 pager
.add
("# {cat}\n".bold
)
175 for mmethod
in list
do
177 var nmethod
= mbuilder
.mpropdef2npropdef
[mmethod
.intro
].as(AMethPropdef)
178 if not nmethod
.short_comment
.is_empty
then
179 pager
.add
("\t# {nmethod.short_comment}")
181 if cat
== "refined methods" then
182 pager
.add
("\tredef {nmethod}")
184 pager
.add
("\t{nmethod}")
186 if not mmethod
.intro_mclassdef
== mclass
.intro
then
187 pager
.add
("\t\tintroduced in {mmethod.intro_mclassdef.namespace}::{mmethod}".gray
)
200 # Get the list of mclasses refined in self
201 private fun redef_mclasses
: Set[MClass] do
202 var mclasses
= new HashSet[MClass]
203 for c
in mclassdefs
do
204 if not c
.is_intro
then mclasses
.add
(c
.mclass
)
209 private fun inherited_mclasses
: Set[MClass] do
210 var mclasses
= new HashSet[MClass]
211 for m
in in_importation
.greaters
do
212 for c
in m
.mclassdefs
do mclasses
.add
(c
.mclass
)
220 redef fun to_s
: String do
222 return "{name}[{intro.parameter_names.join(", ")}]"
228 private fun short_doc
: String do
230 if is_interface
then ret
= "interface {ret}"
231 if is_enum
then ret
= "enum {ret}"
232 if is_class
then ret
= "class {ret}"
233 if is_abstract
then ret
= "abstract {ret}"
234 if visibility
.to_s
== "public" then ret
= "{ret}{to_s.green}"
235 if visibility
.to_s
== "private" then ret
= "{ret}{to_s.red}"
236 if visibility
.to_s
== "protected" then ret
= "{ret}{to_s.yellow}"
237 ret
= "{ret} super {supers.join(", ")}"
241 private fun supers
: Set[MClass] do
242 var ret
= new HashSet[MClass]
243 for mclassdef
in mclassdefs
do
244 for mclasstype
in mclassdef
.supertypes
do
245 ret
.add
(mclasstype
.mclass
)
251 # Get ancestors of the class (all super classes)
252 fun ancestors
: Set[MClass] do
253 var lst
= new HashSet[MClass]
254 for mclassdef
in self.mclassdefs
do
255 for super_mclassdef
in mclassdef
.in_hierarchy
.greaters
do
256 if super_mclassdef
== mclassdef
then continue # skip self
257 lst
.add
(super_mclassdef
.mclass
)
263 # Get the list of class constructors
264 private fun constructors
: Set[MMethod] do
265 var res
= new HashSet[MMethod]
266 for mclassdef
in mclassdefs
do
267 for mpropdef
in mclassdef
.mpropdefs
do
268 if mpropdef
isa MMethodDef then
269 if mpropdef
.mproperty
.is_init
then res
.add
(mpropdef
.mproperty
)
276 # Get the list of intro methods
277 private fun intro_methods
: Set[MMethod] do
278 var res
= new HashSet[MMethod]
279 for mclassdef
in mclassdefs
do
280 for mpropdef
in mclassdef
.mpropdefs
do
281 if mpropdef
isa MMethodDef then
282 if mpropdef
.is_intro
and not mpropdef
.mproperty
.is_init
then res
.add
(mpropdef
.mproperty
)
289 # Get the list of locally refined methods
290 private fun redef_methods
: Set[MMethod] do
291 var res
= new HashSet[MMethod]
292 for mclassdef
in mclassdefs
do
293 for mpropdef
in mclassdef
.mpropdefs
do
294 if mpropdef
isa MMethodDef then
295 if not mpropdef
.is_intro
and not mpropdef
.mproperty
.is_init
then res
.add
(mpropdef
.mproperty
)
302 # Get the list of locally refined methods
303 private fun inherited_methods
: Set[MMethod] do
304 var res
= new HashSet[MMethod]
305 for s
in ancestors
do
306 for m
in s
.intro_methods
do
307 if not self.intro_methods
.has
(m
) and not self.redef_methods
.has
(m
) then res
.add
(m
)
313 private fun is_class
: Bool do
314 return self.kind
== concrete_kind
or self.kind
== abstract_kind
317 private fun is_interface
: Bool do
318 return self.kind
== interface_kind
321 private fun is_enum
: Bool do
322 return self.kind
== enum_kind
325 private fun is_abstract
: Bool do
326 return self.kind
== abstract_kind
330 redef class MClassDef
331 private fun namespace
: String do
332 return "{mmodule.full_name}::{mclass.name}"
339 private fun comment
: String do
341 for t
in n_moduledecl
.n_doc
.n_comment
do
342 ret
+= "{t.text.replace("# ", "")}"
348 redef class AStdClassdef
349 private fun comment
: String do
351 if n_doc
!= null then
352 for t
in n_doc
.n_comment
do
353 var txt
= t
.text
.replace
("# ", "")
354 txt
= txt
.replace
("#", "")
361 private fun short_comment
: String do
363 if n_doc
!= null then
364 var txt
= n_doc
.n_comment
.first
.text
365 txt
= txt
.replace
("# ", "")
366 txt
= txt
.replace
("\n", "")
373 redef class AMethPropdef
374 private fun short_comment
: String do
376 if n_doc
!= null then
377 var txt
= n_doc
.n_comment
.first
.text
378 txt
= txt
.replace
("# ", "")
379 txt
= txt
.replace
("\n", "")
387 if not mpropdef
.mproperty
.is_init
then
390 if mpropdef
.mproperty
.visibility
.to_s
== "public" then ret
= "{ret}{mpropdef.mproperty.name.green}"
391 if mpropdef
.mproperty
.visibility
.to_s
== "private" then ret
= "{ret}{mpropdef.mproperty.name.red}"
392 if mpropdef
.mproperty
.visibility
.to_s
== "protected" then ret
= "{ret}{mpropdef.mproperty.name.yellow}"
393 if n_signature
!= null then ret
= "{ret}{n_signature.to_s}"
394 if n_kwredef
!= null then ret
= "redef {ret}"
395 if self isa ADeferredMethPropdef then ret
= "{ret} is abstract"
396 if self isa AInternMethPropdef then ret
= "{ret} is intern"
397 if self isa AExternMethPropdef then ret
= "{ret} is extern"
402 redef class ASignature
406 if not n_params
.is_empty
then
407 ret
= "{ret}({n_params.join(", ")})"
409 if n_type
!= null then ret
+= ": {n_type.to_s}"
416 var ret
= "{n_id.text}"
417 if n_type
!= null then
418 ret
= "{ret}: {n_type.to_s}"
419 if n_dotdotdot
!= null then ret
= "{ret}..."
428 if n_kwnullable
!= null then ret
= "nullable {ret}"
429 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
434 # Redef String class to add a function to color the string
437 private fun add_escape_char
(escapechar
: String): String do
438 return "{escapechar}{self}\\033[0m"
441 private fun esc
: Char do return 27.ascii
442 private fun red
: String do return add_escape_char
("{esc}[1;31m")
443 private fun yellow
: String do return add_escape_char
("{esc}[1;33m")
444 private fun green
: String do return add_escape_char
("{esc}[1;32m")
445 private fun blue
: String do return add_escape_char
("{esc}[1;34m")
446 private fun cyan
: String do return add_escape_char
("{esc}[1;36m")
447 private fun gray
: String do return add_escape_char
("{esc}[30;1m")
448 private fun bold
: String do return add_escape_char
("{esc}[1m")
449 private fun underline
: String do return add_escape_char
("{esc}[4m")
451 private fun escape
: String
457 else if c
== '\0' then
459 else if c
== '"' then
461 else if c == '\\' then
463 else if c == '`' then
465 else if c.ascii < 32 then
466 b.append("\\{c.ascii.to_base(8, false)}")
475 # Create a tool context to handle options and paths
476 var toolcontext = new ToolContext
477 toolcontext.process_options
479 # Here we launch the nit index
480 var ni = new NitIndex(toolcontext)
484 # TODO lister les methods qui retournent un certain type
485 # TODO lister les methods qui utilisent un certain type
486 # TODO lister les sous-types connus d'une
type
487 # TODO sorter par ordre alphabétique