Moved NitIndex redefintion from Debugger to Nitx
[nit.git] / src / nitx.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # nit index, is a command tool used to display documentation
16 module nitx
17
18 import model_utils
19 import modelize_property
20 import frontend
21
22 # Main class of the nit index tool
23 # NitIndex build the model using the toolcontext argument
24 # then wait for query on std in to display documentation
25 class NitIndex
26 private var toolcontext: ToolContext
27 private var model: Model
28 private var mbuilder: ModelBuilder
29 private var mainmodule: MModule
30 private var arguments: Array[String]
31 private var renderer: PagerMatchesRenderer
32
33 # New constructor to use the pre-calculated model when interpreting a module
34 init with_infos(mbuilder: ModelBuilder, mmodule: MModule) do
35
36 self.model = mbuilder.model
37 self.mbuilder = mbuilder
38
39 self.mainmodule = mmodule
40 self.toolcontext = mbuilder.toolcontext
41 self.arguments = toolcontext.option_context.rest
42
43 renderer = new PagerMatchesRenderer(self)
44 end
45
46 init(toolcontext: ToolContext) do
47 # We need a model to collect stufs
48 self.toolcontext = toolcontext
49 self.toolcontext.option_context.options.clear
50 self.arguments = toolcontext.option_context.rest
51
52 if arguments.is_empty or arguments.length > 2 then
53 print "usage: ni path/to/module.nit [expression]"
54 toolcontext.option_context.usage
55 exit(1)
56 end
57
58 model = new Model
59 mbuilder = new ModelBuilder(model, toolcontext)
60
61 # Here we load an process std modules
62 #var dir = "NIT_DIR".environ
63 #var mmodules = modelbuilder.parse_and_build(["{dir}/lib/standard/standard.nit"])
64 var mmodules = mbuilder.parse([arguments.first])
65 if mmodules.is_empty then return
66 mbuilder.run_phases
67 assert mmodules.length == 1
68 self.mainmodule = mmodules.first
69
70 renderer = new PagerMatchesRenderer(self)
71 end
72
73 fun start do
74 if arguments.length == 1 then
75 welcome
76 prompt
77 else
78 search(arguments[1])
79 end
80 end
81
82 fun welcome do
83 print "Welcome in the Nit Index."
84 print ""
85 print "Loaded modules:"
86 var mmodules = new Array[MModule]
87 mmodules.add_all(model.mmodules)
88 var sorter = new MModuleNameSorter
89 sorter.sort(mmodules)
90 for m in mmodules do
91 print "\t{m.name}"
92 end
93 print ""
94 help
95 end
96
97 fun help do
98 print "\nCommands:"
99 print "\tname\t\tlookup module, class and property with the corresponding 'name'"
100 print "\tparam: Type\tlookup methods using the corresponding 'Type' as parameter"
101 print "\treturn: Type\tlookup methods returning the corresponding 'Type'"
102 print "\tnew: Type\tlookup methods creating new instances of 'Type'"
103 print "\t:h\t\tdisplay this help message"
104 print "\t:q\t\texit"
105 print ""
106 end
107
108 fun prompt do
109 printn ">> "
110 search(stdin.read_line)
111 end
112
113 fun search(entry: String) do
114 if entry.is_empty then
115 prompt
116 return
117 end
118 if entry == ":h" then
119 help
120 prompt
121 return
122 end
123 if entry == ":q" then return
124
125 # Parse query string
126 var query = parse_query(entry)
127
128 # search in index
129 var matches = new HashSet[IndexMatch]
130 if query isa IndexQueryPair then
131 if query.category == "return" then
132 # seek return types
133 matches.add_all(search_returns(query))
134 else if query.category == "param" then
135 # seek param types
136 matches.add_all(search_params(query))
137 else if query.category == "new" then
138 # seek type inits
139 matches.add_all(search_inits(query))
140 end
141 else
142 matches.add_all(search_modules(query))
143 matches.add_all(search_classes(query))
144 matches.add_all(search_properties(query))
145 end
146 # no matches
147 if matches.is_empty then
148 print "Nothing known about '{query.string}', type ':h' for help"
149 else
150 renderer.render_matches(query, matches)
151 end
152 if arguments.length == 1 then prompt
153 end
154
155 private fun parse_query(str: String): IndexQuery do
156 var parts = str.split_with(":")
157 if parts.length == 1 then
158 return new IndexQuery(str, parts[0])
159 else
160 var category = parts[0]
161 var keyword = parts[1]
162 if keyword.first == ' ' then keyword = keyword.substring_from(1)
163 return new IndexQueryPair(str, keyword, category)
164 end
165 end
166
167 # search for modules
168 private fun search_modules(query: IndexQuery): Set[MModule] do
169 var matches = new HashSet[MModule]
170 for mmodule in model.mmodules do
171 if mmodule.name == query.keyword then matches.add(mmodule)
172 end
173 return matches
174 end
175
176 # search for classes
177 private fun search_classes(query: IndexQuery): Set[MClass] do
178 var matches = new HashSet[MClass]
179 for mclass in model.mclasses do
180 if mclass.name == query.keyword then matches.add(mclass)
181 end
182 return matches
183 end
184
185 # search for properties
186 private fun search_properties(query: IndexQuery): Set[MProperty] do
187 var matches = new HashSet[MProperty]
188 for mproperty in model.mproperties do
189 if mproperty.name == query.keyword then matches.add(mproperty)
190 end
191 return matches
192 end
193
194 # search for mpropdef returning keyword
195 private fun search_returns(query: IndexQuery): Set[MProperty] do
196 var matches = new HashSet[MProperty]
197 for mproperty in model.mproperties do
198 var intro = mproperty.intro
199 if intro isa MMethodDef then
200 if intro.msignature.return_mtype != null and intro.msignature.return_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
201 else if intro isa MAttributeDef then
202 if intro.static_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
203 end
204 end
205 return matches
206 end
207
208 # search for mpropdef taking keyword as parameter
209 private fun search_params(query: IndexQuery): Set[MProperty] do
210 var matches = new HashSet[MProperty]
211 for mproperty in model.mproperties do
212 var intro = mproperty.intro
213 if intro isa MMethodDef then
214 var mparameters = intro.msignature.mparameters
215 for mparameter in mparameters do
216 if mparameter.mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
217 end
218 else if intro isa MAttributeDef then
219 if intro.static_mtype.to_console.has_prefix(query.keyword) then matches.add(mproperty)
220 end
221 end
222 return matches
223 end
224
225 # search for mpropdef creating new instance of keyword
226 private fun search_inits(query: IndexQuery): Set[MPropDef] do
227 var mtype2mpropdefs = toolcontext.nitx_phase.mtype2mpropdefs
228 var matches = new HashSet[MPropDef]
229 for mtype in mtype2mpropdefs.keys do
230 if mtype.to_console.has_prefix(query.keyword) then
231 for mpropdef in mtype2mpropdefs[mtype] do
232 matches.add(mpropdef)
233 end
234 end
235 end
236 return matches
237 end
238 end
239
240 private class IndexQuery
241 var string: String
242 var keyword: String
243 init(string: String, keyword: String) do
244 self.string = string
245 self.keyword = keyword
246 end
247 end
248
249 private class IndexQueryPair
250 super IndexQuery
251 var category: String
252 init(string: String, keyword: String, category: String) do
253 super(string, keyword)
254 self.category = category
255 end
256 end
257
258 # A match to a query in the nit index
259 private interface IndexMatch
260 # Short preview of the result for result list display
261 fun preview(index: NitIndex, output: Pager) is abstract
262 fun content(index: NitIndex, output: Pager) is abstract
263 end
264
265 # Code Analysis
266
267 redef class ToolContext
268 private var nitx_phase: NitxPhase = new NitxPhase(self, [typing_phase])
269 end
270
271 # Compiler phase for nitx
272 private class NitxPhase
273 super Phase
274
275 var mtype2mpropdefs = new HashMap[MType, Set[MPropDef]]
276 redef fun process_npropdef(npropdef) do
277 var visitor = new TypeInitVisitor
278 visitor.enter_visit(npropdef)
279 for mtype in visitor.inits do
280 if not mtype2mpropdefs.has_key(mtype) then
281 mtype2mpropdefs[mtype] = new HashSet[MPropDef]
282 end
283 mtype2mpropdefs[mtype].add(npropdef.mpropdef.as(not null))
284 end
285 end
286 end
287
288 # Visitor looking for initialized mtype (new T)
289 private class TypeInitVisitor
290 super Visitor
291
292 var inits = new HashSet[MType]
293 redef fun visit(node)
294 do
295 node.visit_all(self)
296 # look for init
297 if not node isa ANewExpr then return
298 var mtype = node.n_type.mtype
299 if mtype != null then inits.add(mtype)
300 end
301 end
302
303 # Pager output for console
304
305 private class PagerMatchesRenderer
306 var index: NitIndex
307 init(index: NitIndex) do self.index = index
308
309 fun render_matches(query: IndexQuery, matches: Collection[IndexMatch]) do
310 var pager = new Pager
311 if matches.length == 1 then
312 pager.add("= result for '{query.string}'".bold)
313 pager.add("")
314 pager.indent = pager.indent + 1
315 matches.first.content(index, pager)
316 pager.indent = pager.indent - 1
317 else
318 pager.add("= multiple results for '{query.string}'".bold)
319 pager.indent = pager.indent + 1
320 for match in matches do
321 pager.add("")
322 match.preview(index, pager)
323 end
324 pager.indent = pager.indent - 1
325 end
326 pager.render
327 end
328
329 private fun props_fulldoc(pager: Pager, raw_mprops: List[MProperty]) do
330 # group by module
331 var cats = new HashMap[MModule, Array[MProperty]]
332 for mprop in raw_mprops do
333 if mprop isa MAttribute then continue
334 var key = mprop.intro.mclassdef.mmodule
335 if not cats.has_key(key) then cats[key] = new Array[MProperty]
336 cats[key].add(mprop)
337 end
338 #sort groups
339 var sorter = new MModuleNameSorter
340 var sorted = new Array[MModule]
341 sorted.add_all(cats.keys)
342 sorter.sort(sorted)
343 # display
344 for mmodule in sorted do
345 var mprops = cats[mmodule]
346 pager.add("# matches in module {mmodule.namespace.bold}")
347 var sorterp = new MPropertyNameSorter
348 sorterp.sort(mprops)
349 for mprop in mprops do
350
351 end
352 pager.add_rule
353 end
354 end
355 end
356
357 private class Pager
358 var content = new Buffer
359 var indent = 0
360 fun add(text: String) do
361 add_indent
362 addn("{text}\n")
363 end
364 fun add_indent do addn(" " * indent)
365 fun addn(text: String) do content.append(text.escape)
366 fun add_rule do add("\n---\n")
367 fun render do sys.system("echo \"{content}\" | pager -r")
368 end
369
370 redef class MModule
371 super IndexMatch
372 # prototype of the module
373 # module ownername::name
374 private fun prototype: String do return "module {name.bold}"
375
376 # namespace of the module
377 # ownername::name
378 private fun namespace: String do
379 if public_owner == null then
380 return self.name
381 else
382 return "{public_owner.namespace}::{self.name}"
383 end
384 end
385
386 redef fun preview(index, pager) do
387 if index.mbuilder.mmodule2nmodule.has_key(self) then
388 var node = index.mbuilder.mmodule2nmodule[self]
389 if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.short_comment.is_empty then
390 pager.add(node.n_moduledecl.n_doc.short_comment.green)
391 end
392 end
393 pager.add(prototype)
394 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
395 end
396
397 redef fun content(index, pager) do
398 if index.mbuilder.mmodule2nmodule.has_key(self) then
399 var node = index.mbuilder.mmodule2nmodule[self]
400 if node.n_moduledecl != null and not node.n_moduledecl.n_doc == null and not node.n_moduledecl.n_doc.comment.is_empty then
401 for comment in node.n_moduledecl.n_doc.comment do pager.add(comment.green)
402 end
403 end
404 pager.add(prototype)
405 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
406 pager.indent = pager.indent + 1
407 var sorter = new MModuleNameSorter
408 # imported modules
409 var imports = new Array[MModule]
410 for mmodule in in_importation.direct_greaters.to_a do
411 if not in_nesting.direct_greaters.has(mmodule) then imports.add(mmodule)
412 end
413 if not imports.is_empty then
414 sorter.sort(imports)
415 pager.add("")
416 pager.add("== imported modules".bold)
417 pager.indent = pager.indent + 1
418 for mmodule in imports do
419 pager.add("")
420 mmodule.preview(index, pager)
421 end
422 pager.indent = pager.indent - 1
423 end
424 # nested modules
425 var nested = in_nesting.direct_greaters.to_a
426 if not nested.is_empty then
427 sorter.sort(nested)
428 pager.add("")
429 pager.add("== nested modules".bold)
430 pager.indent = pager.indent + 1
431 for mmodule in nested do
432 pager.add("")
433 mmodule.preview(index, pager)
434 end
435 pager.indent = pager.indent - 1
436 end
437 # mclassdefs
438 var csorter = new MClassDefNameSorter
439 var intros = new Array[MClassDef]
440 var redefs = new Array[MClassDef]
441 for mclassdef in mclassdefs do
442 if mclassdef.is_intro then
443 intros.add(mclassdef)
444 else
445 redefs.add(mclassdef)
446 end
447 end
448 # introductions
449 if not intros.is_empty then
450 csorter.sort(intros)
451 pager.add("")
452 pager.add("== introduced classes".bold)
453 pager.indent = pager.indent + 1
454 for mclass in intros do
455 pager.add("")
456 mclass.preview(index, pager)
457 end
458 pager.indent = pager.indent - 1
459 end
460 # refinements
461 if not redefs.is_empty then
462 csorter.sort(redefs)
463 pager.add("")
464 pager.add("== refined classes".bold)
465 pager.indent = pager.indent + 1
466 for mclass in redefs do
467 pager.add("")
468 mclass.preview(index, pager)
469 end
470 pager.indent = pager.indent - 1
471 end
472 pager.indent = pager.indent - 1
473 end
474 end
475
476 redef class MClass
477 super IndexMatch
478 # return the generic signature of the class
479 # [E, F]
480 private fun signature: String do
481 var res = new Buffer
482 if arity > 0 then
483 res.append("[")
484 for i in [0..intro.parameter_names.length[ do
485 res.append(intro.parameter_names[i])
486 if i < intro.parameter_names.length - 1 then res.append(", ")
487 end
488 res.append("]")
489 end
490 return res.to_s
491 end
492
493 # return the prototype of the class
494 # class name is displayed with colors depending on visibility
495 # abstract interface Foo[E]
496 private fun prototype: String do
497 var res = new Buffer
498 res.append("{kind} ")
499 if visibility.to_s == "public" then res.append("{name}{signature}".bold.green)
500 if visibility.to_s == "private" then res.append("{name}{signature}".bold.red)
501 if visibility.to_s == "protected" then res.append("{name}{signature}".bold.yellow)
502 return res.to_s
503 end
504
505 private fun namespace: String do
506 return "{intro_mmodule.namespace}::{name}"
507 end
508
509 redef fun preview(index, pager) do
510 intro.preview(index, pager)
511 end
512
513 redef fun content(index, pager) do
514 # intro comment
515 if index.mbuilder.mclassdef2nclassdef.has_key(intro) then
516 var node = index.mbuilder.mclassdef2nclassdef[intro]
517 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
518 for comment in node.n_doc.comment do pager.add(comment.green)
519 end
520 end
521 pager.add(intro.to_console)
522 pager.add("{intro.namespace}".bold.gray + " (lines {intro.location.lines})".gray)
523 pager.indent = pager.indent + 1
524 # parents
525 var supers = self.in_hierarchy(index.mainmodule).direct_greaters.to_a
526 if not supers.is_empty then
527 var csorter = new MClassNameSorter
528 csorter.sort(supers)
529 pager.add("")
530 pager.add("== supers".bold)
531 pager.indent = pager.indent + 1
532 for mclass in supers do
533 pager.add("")
534 mclass.preview(index, pager)
535 end
536 pager.indent = pager.indent - 1
537 end
538 # formal types
539 if not self.parameter_types.is_empty then
540 pager.add("")
541 pager.add("== formal types".bold)
542 pager.indent = pager.indent + 1
543 for ft, bound in self.parameter_types do
544 pager.add("")
545 pager.add("{ft.to_s.bold.green}: {bound.to_console}")
546 end
547 pager.indent = pager.indent - 1
548 end
549 # intro mproperties
550 var psorter = new MPropDefNameSorter
551 var mpropdefs = intro.mpropdefs
552 index.mainmodule.linearize_mpropdefs(mpropdefs)
553 for cat in intro.cats2mpropdefs.keys do
554 var defs = intro.cats2mpropdefs[cat].to_a
555 if defs.is_empty then continue
556 psorter.sort(defs)
557 pager.add("")
558 pager.add("== {cat}".bold)
559 pager.indent = pager.indent + 1
560 for mpropdef in defs do
561 pager.add("")
562 mpropdef.preview(index, pager)
563 end
564 pager.indent = pager.indent - 1
565 end
566 # refinements
567 if not self.mclassdefs.is_empty then
568 pager.add("")
569 pager.add("== refinements".bold)
570 var mclassdefs = self.mclassdefs
571 index.mainmodule.linearize_mclassdefs(mclassdefs)
572 pager.indent = pager.indent + 1
573 for mclassdef in mclassdefs do
574 if not mclassdef.is_intro then
575 pager.add("")
576 mclassdef.content(index, pager)
577 end
578 end
579 pager.indent = pager.indent - 1
580 end
581 pager.indent = pager.indent - 1
582 end
583 end
584
585 redef class MClassDef
586 super IndexMatch
587
588 private fun namespace: String do
589 return "{mmodule.full_name}::{mclass.name}"
590 end
591
592 fun to_console: String do
593 var res = new Buffer
594 if not is_intro then res.append("redef ")
595 res.append(mclass.prototype)
596 return res.to_s
597 end
598
599 redef fun preview(index, pager) do
600 if index.mbuilder.mclassdef2nclassdef.has_key(self) then
601 var node = index.mbuilder.mclassdef2nclassdef[self]
602 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.short_comment.is_empty then
603 pager.add(node.n_doc.short_comment.green)
604 end
605 end
606 pager.add(to_console)
607 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
608 end
609
610 redef fun content(index, pager) do
611 if index.mbuilder.mclassdef2nclassdef.has_key(self) then
612 var node = index.mbuilder.mclassdef2nclassdef[self]
613 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
614 for comment in node.n_doc.comment do pager.add(comment.green)
615 end
616 end
617 pager.add(to_console)
618 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
619 pager.indent = pager.indent + 1
620 var mpropdefs = self.mpropdefs
621 var psorter = new MPropDefNameSorter
622 index.mainmodule.linearize_mpropdefs(mpropdefs)
623 for cat in cats2mpropdefs.keys do
624 var defs = cats2mpropdefs[cat].to_a
625 psorter.sort(defs)
626 if defs.is_empty then continue
627 pager.add("")
628 pager.add("== {cat}".bold)
629 pager.indent = pager.indent + 1
630 for mpropdef in defs do
631 pager.add("")
632 mpropdef.preview(index, pager)
633 end
634 pager.indent = pager.indent - 1
635 end
636 pager.indent = pager.indent - 1
637 end
638
639 # get mpropdefs grouped by categories (vt, init, methods)
640 fun cats2mpropdefs: Map[String, Set[MPropDef]] do
641 var cats = new ArrayMap[String, Set[MPropDef]]
642 cats["virtual types"] = new HashSet[MPropDef]
643 cats["constructors"] = new HashSet[MPropDef]
644 cats["methods"] = new HashSet[MPropDef]
645
646 for mpropdef in mpropdefs do
647 if mpropdef isa MAttributeDef then continue
648 if mpropdef isa MVirtualTypeDef then cats["virtual types"].add(mpropdef)
649 if mpropdef isa MMethodDef then
650 if mpropdef.mproperty.is_init then
651 cats["constructors"].add(mpropdef)
652 else
653 cats["methods"].add(mpropdef)
654 end
655 end
656 end
657 return cats
658 end
659 end
660
661 redef class MProperty
662 super IndexMatch
663
664 fun to_console: String do
665 if visibility.to_s == "public" then return name.green
666 if visibility.to_s == "private" then return name.red
667 if visibility.to_s == "protected" then return name.yellow
668 return name.bold
669 end
670
671 redef fun preview(index, pager) do
672 intro.preview(index, pager)
673 end
674
675 redef fun content(index, pager) do
676 intro.content(index, pager)
677 pager.indent = pager.indent + 1
678 var mpropdefs = self.mpropdefs
679 index.mainmodule.linearize_mpropdefs(mpropdefs)
680 for mpropdef in mpropdefs do
681 if mpropdef isa MAttributeDef then continue
682 if not mpropdef.is_intro then
683 pager.add("")
684 mpropdef.preview(index, pager)
685 end
686 end
687 pager.indent = pager.indent - 1
688 end
689 end
690
691 redef class MPropDef
692 super IndexMatch
693
694 fun to_console: String is abstract
695
696 private fun namespace: String do
697 return "{mclassdef.namespace}::{mproperty.name}"
698 end
699
700 redef fun preview(index, pager) do
701 if index.mbuilder.mpropdef2npropdef.has_key(self) then
702 var nprop = index.mbuilder.mpropdef2npropdef[self]
703 if not nprop.n_doc == null and not nprop.n_doc.short_comment.is_empty then
704 pager.add(nprop.n_doc.short_comment.green)
705 end
706 end
707 pager.add(to_console)
708 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
709 end
710
711 redef fun content(index, pager) do
712 if index.mbuilder.mpropdef2npropdef.has_key(self) then
713 var nprop = index.mbuilder.mpropdef2npropdef[self]
714 if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
715 for comment in nprop.n_doc.comment do pager.add(comment.green)
716 end
717 end
718 pager.add(to_console)
719 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
720 end
721 end
722
723 redef class MMethodDef
724 redef fun to_console do
725 var res = new Buffer
726 if not is_intro then res.append("redef ")
727 if not mproperty.is_init then res.append("fun ")
728 res.append(mproperty.to_console.bold)
729 if msignature != null then res.append(msignature.to_console)
730 # FIXME: modifiers should be accessible via the model
731 #if self isa ADeferredMethPropdef then ret = "{ret} is abstract"
732 #if self isa AInternMethPropdef then ret = "{ret} is intern"
733 #if self isa AExternMethPropdef then ret = "{ret} is extern"
734 return res.to_s
735 end
736 end
737
738 redef class MVirtualTypeDef
739 redef fun to_console do
740 var res = new Buffer
741 res.append("type ")
742 res.append(mproperty.to_console.bold)
743 res.append(": {bound.to_console}")
744 return res.to_s
745 end
746 end
747
748 redef class MAttributeDef
749 redef fun to_console do
750 var res = new Buffer
751 res.append("var ")
752 res.append(mproperty.to_console.bold)
753 res.append(": {static_mtype.to_console}")
754 return res.to_s
755 end
756 end
757
758 redef class MSignature
759 redef fun to_console do
760 var res = new Buffer
761 if not mparameters.is_empty then
762 res.append("(")
763 for i in [0..mparameters.length[ do
764 res.append(mparameters[i].to_console)
765 if i < mparameters.length - 1 then res.append(", ")
766 end
767 res.append(")")
768 end
769 if return_mtype != null then
770 res.append(": {return_mtype.to_console}")
771 end
772 return res.to_s
773 end
774 end
775
776 redef class MParameter
777 fun to_console: String do
778 var res = new Buffer
779 res.append("{name}: {mtype.to_console}")
780 if is_vararg then res.append("...")
781 return res.to_s
782 end
783 end
784
785 redef class MType
786 fun to_console: String do return self.to_s
787 end
788
789 redef class MNullableType
790 redef fun to_console do return "nullable {mtype.to_console}"
791 end
792
793 redef class MGenericType
794 redef fun to_console do
795 var res = new Buffer
796 res.append("{mclass.name}[")
797 for i in [0..arguments.length[ do
798 res.append(arguments[i].to_console)
799 if i < arguments.length - 1 then res.append(", ")
800 end
801 res.append("]")
802 return res.to_s
803 end
804 end
805
806 redef class MParameterType
807 redef fun to_console do return mclass.intro.parameter_names[rank]
808 end
809
810 redef class MVirtualType
811 redef fun to_console do return mproperty.name
812 end
813
814 redef class ADoc
815 private fun comment: List[String] do
816 var res = new List[String]
817 for t in n_comment do
818 res.add(t.text.replace("\n", ""))
819 end
820 return res
821 end
822
823 private fun short_comment: String do
824 return n_comment.first.text.replace("\n", "")
825 end
826 end
827
828 redef class AAttrPropdef
829 private fun read_accessor: String do
830 var ret = "fun "
831 #FIXME bug with standard::stream::FDStream::fd
832 var name = mreadpropdef.mproperty.name
833 if mpropdef.mproperty.visibility.to_s == "public" then ret = "{ret}{name.green}"
834 if mpropdef.mproperty.visibility.to_s == "private" then ret = "{ret}{name.red}"
835 if mpropdef.mproperty.visibility.to_s == "protected" then ret = "{ret}{name.yellow}"
836 ret = "{ret}: {n_type.to_s}"
837 if n_kwredef != null then ret = "redef {ret}"
838 return ret
839 end
840
841 private fun write_accessor: String do
842 var ret = "fun "
843 var name = "{mreadpropdef.mproperty.name}="
844 if n_readable != null and n_readable.n_visibility != null then
845 if n_readable.n_visibility isa APublicVisibility then ret = "{ret}{name.green}"
846 if n_readable.n_visibility isa APrivateVisibility then ret = "{ret}{name.red}"
847 if n_readable.n_visibility isa AProtectedVisibility then ret = "{ret}{name.yellow}"
848 else
849 ret = "{ret}{name.red}"
850 end
851 ret = "{ret}({mreadpropdef.mproperty.name}: {n_type.to_s})"
852 if n_kwredef != null then ret = "redef {ret}"
853 return ret
854 end
855 end
856
857 # Redef String class to add a function to color the string
858 redef class String
859
860 private fun add_escape_char(escapechar: String): String do
861 return "{escapechar}{self}\\033[0m"
862 end
863
864 private fun esc: Char do return 27.ascii
865 private fun gray: String do return add_escape_char("{esc}[30m")
866 private fun red: String do return add_escape_char("{esc}[31m")
867 private fun green: String do return add_escape_char("{esc}[32m")
868 private fun yellow: String do return add_escape_char("{esc}[33m")
869 private fun blue: String do return add_escape_char("{esc}[34m")
870 private fun purple: String do return add_escape_char("{esc}[35m")
871 private fun cyan: String do return add_escape_char("{esc}[36m")
872 private fun light_gray: String do return add_escape_char("{esc}[37m")
873 private fun bold: String do return add_escape_char("{esc}[1m")
874 private fun underline: String do return add_escape_char("{esc}[4m")
875
876 private fun escape: String
877 do
878 var b = new Buffer
879 for c in self do
880 if c == '\n' then
881 b.append("\\n")
882 else if c == '\0' then
883 b.append("\\0")
884 else if c == '"' then
885 b.append("\\\"")
886 else if c == '\\' then
887 b.append("\\\\")
888 else if c == '`' then
889 b.append("'")
890 else if c.ascii < 32 then
891 b.append("\\{c.ascii.to_base(8, false)}")
892 else
893 b.add(c)
894 end
895 end
896 return b.to_s
897 end
898 end
899
900 redef class Location
901 fun lines: String do
902 return "{line_start}-{line_end}"
903 end
904 end
905
906 # Create a tool context to handle options and paths
907 var toolcontext = new ToolContext
908 toolcontext.process_options
909
910 # Here we launch the nit index
911 var ni = new NitIndex(toolcontext)
912 ni.start
913
914 # TODO seek subclasses and super classes <.<class> >.<class>
915 # TODO seek subclasses and super types <:<type> >:<type>
916 # TODO seek with regexp
917 # TODO standardize namespaces with private option