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.
22 var content
: String = ""
23 fun add
(text
: String) do addn
("{text}\n")
24 fun addn
(text
: String) do content
+= text
.escape
25 fun add_rule
do add
("\n---\n")
26 fun render
do sys
.system
("echo \"{content}\
" | pager -r")
30 private var toolcontext
: ToolContext
31 private var model
: Model
32 private var mbuilder
: ModelBuilder
33 private var mainmodule
: MModule
34 private var arguments
: Array[String]
36 init(toolcontext
: ToolContext) do
37 # We need a model to collect stufs
38 self.toolcontext
= toolcontext
39 self.arguments
= toolcontext
.option_context
.rest
41 if arguments
.length
> 2 then
42 print
"usage: ni path/to/module.nit [expression]"
43 toolcontext
.option_context
.usage
48 mbuilder
= new ModelBuilder(model
, toolcontext
)
50 # Here we load an process std modules
51 #var dir = "NIT_DIR".environ
52 #var mmodules = modelbuilder.parse_and_build(["{dir}/lib/standard/standard.nit"])
53 var mmodules
= mbuilder
.parse_and_build
([arguments
.first
])
54 if mmodules
.is_empty
then return
55 mbuilder
.full_propdef_semantic_analysis
56 assert mmodules
.length
== 1
57 self.mainmodule
= mmodules
.first
61 if arguments
.length
== 1 then
70 print
"Welcome in Nit Index.\n"
71 print
"Loaded modules"
72 for m
in mbuilder
.nmodules
do
73 print
" - {m.mmodule.name}"
75 print
"\nEnter the module, class or property name you want to look up."
76 print
"Enter a blank line to exit.\n"
84 fun seek
(entry
: String) do
85 if entry
.is_empty
then exit
(0)
88 var mmatches
= new List[MModule]
89 for m
in model
.mmodules
do
90 if m
.name
== entry
then
95 if not mmatches
.is_empty
then modules_fulldoc
(mmatches
)
97 var cmatches
= new List[MClass]
98 for c
in model
.mclasses
do
99 if c
.name
== entry
then
104 if not cmatches
.is_empty
then classes_fulldoc
(cmatches
)
105 # seek for properties
106 var matches
= new List[MProperty]
107 for p
in model
.mproperties
do
108 if p
.name
== entry
then
113 if not matches
.is_empty
then props_fulldoc
(matches
)
115 if not flag
then print
"Nothing known about '{entry}'"
116 if arguments
.length
== 1 then prompt
119 private fun modules_fulldoc
(mmodules
: List[MModule]) do
120 var pager
= new Pager
121 for mmodule
in mmodules
do
122 var nmodule
= mbuilder
.mmodule2nmodule
[mmodule
]
123 pager
.add
("# module {mmodule.namespace}\n".bold
)
124 if not mmodule
.in_importation
.direct_greaters
.is_empty
then
125 pager
.add
("import ".bold
+ "{mmodule.in_importation.direct_greaters.join(", ")}\n")
127 if not mmodule
.in_importation
.direct_smallers
.is_empty
then
128 pager
.add
("known clients: ".bold
+ "{mmodule.in_importation.direct_smallers.join(", ")}\n")
131 pager
.addn
(nmodule
.comment
.green
)
134 var cats
= new HashMap[String, Collection[MClass]]
135 cats
["introduced classes"] = mmodule
.intro_mclasses
136 cats
["refined classes"] = mmodule
.redef_mclasses
137 cats
["imported classes"] = mmodule
.imported_mclasses
139 for cat
, list
in cats
do
140 if not list
.is_empty
then
141 pager
.add
("\n# {cat}".bold
)
142 for mclass
in list
do
143 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
].as(AStdClassdef)
145 if not nclass
.short_comment
.is_empty
then
146 pager
.add
("\t# {nclass.short_comment}")
148 if cat
== "refined classes" then
149 pager
.add
("\tredef {mclass.short_doc}")
151 pager
.add
("\t{mclass.short_doc}")
153 if cat
!= "introduced classes" then
154 pager
.add
("\t\t" + "introduced in {mmodule.full_name}::{mclass}".gray
)
156 for mclassdef
in mclass
.mclassdefs
do
157 if mclassdef
!= mclass
.intro
then
158 pager
.add
("\t\t" + "refined in {mclassdef.namespace}".gray
)
169 private fun classes_fulldoc
(mclasses
: List[MClass]) do
170 var pager
= new Pager
171 for mclass
in mclasses
do
172 var nclass
= mbuilder
.mclassdef2nclassdef
[mclass
.intro
].as(AStdClassdef)
174 pager
.add
("# {mclass.namespace}\n".bold
)
175 pager
.add
("{mclass.short_doc}")
177 pager
.addn
(nclass
.comment
.green
)
179 if not mclass
.parameter_types
.is_empty
then
180 pager
.add
("# formal types".bold
)
181 for ft
, bound
in mclass
.parameter_types
do
183 pager
.add
("\t{ft.to_s.green}: {bound}")
186 if not mclass
.virtual_types
.is_empty
then
187 pager
.add
("# virtual types".bold
)
188 for vt
in mclass
.virtual_types
do
190 vt_fulldoc
(pager
, vt
)
195 var cats
= new HashMap[String, Collection[MMethod]]
196 cats
["constructors"] = mclass
.constructors
197 cats
["introduced methods"] = mclass
.intro_methods
198 cats
["refined methods"] = mclass
.redef_methods
199 cats
["inherited methods"] = mclass
.inherited_methods
201 for cat
, list
in cats
do
202 if not list
.is_empty
then
203 pager
.add
("\n# {cat}".bold
)
206 method_fulldoc
(pager
, mprop
)
215 private fun props_fulldoc
(raw_mprops
: List[MProperty]) do
216 var pager
= new Pager
218 var cats
= new HashMap[MModule, List[MProperty]]
219 for mprop
in raw_mprops
do
220 var mmodule
= mprop
.intro_mclassdef
.mmodule
221 if not cats
.has_key
(mmodule
) then cats
[mmodule
] = new List[MProperty]
222 cats
[mmodule
].add
(mprop
)
225 for mmodule
, mprops
in cats
do
226 pager
.add
("# {mmodule.namespace}".bold
)
227 for mprop
in mprops
do
228 if mprop
isa MMethod and mbuilder
.mpropdef2npropdef
.has_key
(mprop
.intro
) then
230 method_fulldoc
(pager
, mprop
)
231 else if mprop
isa MVirtualTypeProp then
233 vt_fulldoc
(pager
, mprop
)
241 private fun method_fulldoc
(pager
: Pager, mprop
: MMethod) do
242 if mbuilder
.mpropdef2npropdef
.has_key
(mprop
.intro
) then
243 var nprop
= mbuilder
.mpropdef2npropdef
[mprop
.intro
]
244 if not nprop
.short_comment
.is_empty
then
245 pager
.add
("\t# {nprop.short_comment}")
247 if nprop
isa AAttrPropdef then
248 pager
.add
("\t{nprop.read_accessor}")
249 pager
.add
("\t{nprop.write_accessor}")
250 else if nprop
isa AMethPropdef then
251 pager
.add
("\t{nprop}")
253 pager
.add
("\t\t" + "introduced in {mprop.intro_mclassdef.namespace}".gray
)
254 for mpropdef
in mprop
.mpropdefs
do
255 if mpropdef
!= mprop
.intro
then
256 pager
.add
("\t\t" + "refined in {mpropdef.mclassdef.namespace}".gray
)
262 private fun vt_fulldoc
(pager
: Pager, vt
: MVirtualTypeProp) do
263 pager
.add
("\t{vt.short_doc}")
264 pager
.add
("\t\t" + "introduced in {vt.intro_mclassdef.namespace}::{vt}".gray
)
265 for mpropdef
in vt
.mpropdefs
do
266 if mpropdef
!= vt
.intro
then
267 pager
.add
("\t\t" + "refined in {mpropdef.mclassdef.namespace}".gray
)
273 # Printing facilities
276 private fun namespace
: String do
283 redef fun to_s
: String do
285 return "{name}[{intro.parameter_names.join(", ")}]"
291 private fun short_doc
: String do
293 if is_interface
then ret
= "interface {ret}"
294 if is_enum
then ret
= "enum {ret}"
295 if is_class
then ret
= "class {ret}"
296 if is_abstract
then ret
= "abstract {ret}"
297 if visibility
.to_s
== "public" then ret
= "{ret}{to_s.green}"
298 if visibility
.to_s
== "private" then ret
= "{ret}{to_s.red}"
299 if visibility
.to_s
== "protected" then ret
= "{ret}{to_s.yellow}"
300 if not parents
.is_empty
then
301 ret
= "{ret} super {parents.join(", ")}"
306 private fun namespace
: String do
307 return "{intro_mmodule.public_owner.name}::{name}"
311 redef class MClassDef
312 private fun namespace
: String do
313 return "{mmodule.full_name}::{mclass.name}"
317 redef class MVirtualTypeProp
318 private fun short_doc
: String do
320 if visibility
.to_s
== "public" then ret
= "{to_s.green}: {intro.bound.to_s}"
321 if visibility
.to_s
== "private" then ret
= "\t{to_s.red}: {intro.bound.to_s}"
322 if visibility
.to_s
== "protected" then ret
= "\t{to_s.yellow}: {intro.bound.to_s}"
328 private fun comment
: String do
330 for t
in n_moduledecl
.n_doc
.n_comment
do
331 ret
+= "{t.text.replace("# ", "")}"
337 redef class AStdClassdef
338 private fun comment
: String do
340 if n_doc
!= null then
341 for t
in n_doc
.n_comment
do
342 var txt
= t
.text
.replace
("# ", "")
343 txt
= txt
.replace
("#", "")
350 private fun short_comment
: String do
352 if n_doc
!= null then
353 var txt
= n_doc
.n_comment
.first
.text
354 txt
= txt
.replace
("# ", "")
355 txt
= txt
.replace
("\n", "")
363 private fun short_comment
: String is abstract
366 redef class AAttrPropdef
367 redef fun short_comment
do
369 if n_doc
!= null then
370 var txt
= n_doc
.n_comment
.first
.text
371 txt
= txt
.replace
("# ", "")
372 txt
= txt
.replace
("\n", "")
378 private fun read_accessor
: String do
380 var name
= mreadpropdef
.mproperty
.name
381 if mpropdef
.mproperty
.visibility
.to_s
== "public" then ret
= "{ret}{name.green}"
382 if mpropdef
.mproperty
.visibility
.to_s
== "private" then ret
= "{ret}{name.red}"
383 if mpropdef
.mproperty
.visibility
.to_s
== "protected" then ret
= "{ret}{name.yellow}"
384 ret
= "{ret}: {n_type.to_s}"
385 if n_kwredef
!= null then ret
= "redef {ret}"
389 private fun write_accessor
: String do
391 var name
= "{mreadpropdef.mproperty.name}="
392 if n_readable
!= null and n_readable
.n_visibility
!= null then
393 if n_readable
.n_visibility
isa APublicVisibility then ret
= "{ret}{name.green}"
394 if n_readable
.n_visibility
isa APrivateVisibility then ret
= "{ret}{name.red}"
395 if n_readable
.n_visibility
isa AProtectedVisibility then ret
= "{ret}{name.yellow}"
397 ret
= "{ret}{name.red}"
399 ret
= "{ret}({mreadpropdef.mproperty.name}: {n_type.to_s})"
400 if n_kwredef
!= null then ret
= "redef {ret}"
405 redef class AMethPropdef
406 redef fun short_comment
do
408 if n_doc
!= null then
409 var txt
= n_doc
.n_comment
.first
.text
410 txt
= txt
.replace
("# ", "")
411 txt
= txt
.replace
("\n", "")
419 if not mpropdef
.mproperty
.is_init
then
422 if mpropdef
.mproperty
.visibility
.to_s
== "public" then ret
= "{ret}{mpropdef.mproperty.name.green}"
423 if mpropdef
.mproperty
.visibility
.to_s
== "private" then ret
= "{ret}{mpropdef.mproperty.name.red}"
424 if mpropdef
.mproperty
.visibility
.to_s
== "protected" then ret
= "{ret}{mpropdef.mproperty.name.yellow}"
425 if n_signature
!= null then ret
= "{ret}{n_signature.to_s}"
426 if n_kwredef
!= null then ret
= "redef {ret}"
427 if self isa ADeferredMethPropdef then ret
= "{ret} is abstract"
428 if self isa AInternMethPropdef then ret
= "{ret} is intern"
429 if self isa AExternMethPropdef then ret
= "{ret} is extern"
434 redef class ASignature
438 if not n_params
.is_empty
then
439 ret
= "{ret}({n_params.join(", ")})"
441 if n_type
!= null then ret
+= ": {n_type.to_s}"
448 var ret
= "{n_id.text}"
449 if n_type
!= null then
450 ret
= "{ret}: {n_type.to_s}"
451 if n_dotdotdot
!= null then ret
= "{ret}..."
460 if n_kwnullable
!= null then ret
= "nullable {ret}"
461 if not n_types
.is_empty
then ret
= "{ret}[{n_types.join(", ")}]"
466 # Redef String class to add a function to color the string
469 private fun add_escape_char
(escapechar
: String): String do
470 return "{escapechar}{self}\\033[0m"
473 private fun esc
: Char do return 27.ascii
474 private fun red
: String do return add_escape_char
("{esc}[1;31m")
475 private fun yellow
: String do return add_escape_char
("{esc}[1;33m")
476 private fun green
: String do return add_escape_char
("{esc}[1;32m")
477 private fun blue
: String do return add_escape_char
("{esc}[1;34m")
478 private fun cyan
: String do return add_escape_char
("{esc}[1;36m")
479 private fun gray
: String do return add_escape_char
("{esc}[30;1m")
480 private fun bold
: String do return add_escape_char
("{esc}[1m")
481 private fun underline
: String do return add_escape_char
("{esc}[4m")
483 private fun escape
: String
489 else if c
== '\0' then
491 else if c
== '"' then
493 else if c == '\\' then
495 else if c == '`' then
497 else if c.ascii < 32 then
498 b.append("\\{c.ascii.to_base(8, false)}")
507 # Create a tool context to handle options and paths
508 var toolcontext = new ToolContext
509 toolcontext.process_options
511 # Here we launch the nit index
512 var ni = new NitIndex(toolcontext)
515 # TODO seek methods by return type :<type>
516 # TODO seek methods by param type: (<type>)
517 # TODO seek subclasses and super classes <.<class> >.<class>
518 # TODO seek subclasses and super types <:<type> >:<type>
519 # TODO sort by alphabetic order
520 # TODO seek with regexp
521 # TODO standardize namespaces with private option