stdlib/strings: Removed usage of Strings as SequenceRead by using chars.
[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.chars.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 name
374 private fun prototype: String do return "module {name.bold}"
375
376 # namespace of the module
377 # project::name
378 private fun namespace: String do
379 if mgroup == null or mgroup.mproject.name == self.name then
380 return self.name
381 else
382 return "{mgroup.mproject}::{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 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 # mclassdefs
425 var csorter = new MClassDefNameSorter
426 var intros = new Array[MClassDef]
427 var redefs = new Array[MClassDef]
428 for mclassdef in mclassdefs do
429 if mclassdef.is_intro then
430 intros.add(mclassdef)
431 else
432 redefs.add(mclassdef)
433 end
434 end
435 # introductions
436 if not intros.is_empty then
437 csorter.sort(intros)
438 pager.add("")
439 pager.add("== introduced classes".bold)
440 pager.indent = pager.indent + 1
441 for mclass in intros do
442 pager.add("")
443 mclass.preview(index, pager)
444 end
445 pager.indent = pager.indent - 1
446 end
447 # refinements
448 if not redefs.is_empty then
449 csorter.sort(redefs)
450 pager.add("")
451 pager.add("== refined classes".bold)
452 pager.indent = pager.indent + 1
453 for mclass in redefs do
454 pager.add("")
455 mclass.preview(index, pager)
456 end
457 pager.indent = pager.indent - 1
458 end
459 pager.indent = pager.indent - 1
460 end
461 end
462
463 redef class MClass
464 super IndexMatch
465 # return the generic signature of the class
466 # [E, F]
467 private fun signature: String do
468 var res = new Buffer
469 if arity > 0 then
470 res.append("[")
471 for i in [0..intro.parameter_names.length[ do
472 res.append(intro.parameter_names[i])
473 if i < intro.parameter_names.length - 1 then res.append(", ")
474 end
475 res.append("]")
476 end
477 return res.to_s
478 end
479
480 # return the prototype of the class
481 # class name is displayed with colors depending on visibility
482 # abstract interface Foo[E]
483 private fun prototype: String do
484 var res = new Buffer
485 res.append("{kind} ")
486 if visibility.to_s == "public" then res.append("{name}{signature}".bold.green)
487 if visibility.to_s == "private" then res.append("{name}{signature}".bold.red)
488 if visibility.to_s == "protected" then res.append("{name}{signature}".bold.yellow)
489 return res.to_s
490 end
491
492 private fun namespace: String do
493 return "{intro_mmodule.namespace}::{name}"
494 end
495
496 redef fun preview(index, pager) do
497 intro.preview(index, pager)
498 end
499
500 redef fun content(index, pager) do
501 # intro comment
502 if index.mbuilder.mclassdef2nclassdef.has_key(intro) then
503 var node = index.mbuilder.mclassdef2nclassdef[intro]
504 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
505 for comment in node.n_doc.comment do pager.add(comment.green)
506 end
507 end
508 pager.add(intro.to_console)
509 pager.add("{intro.namespace}".bold.gray + " (lines {intro.location.lines})".gray)
510 pager.indent = pager.indent + 1
511 # parents
512 var supers = self.in_hierarchy(index.mainmodule).direct_greaters.to_a
513 if not supers.is_empty then
514 var csorter = new MClassNameSorter
515 csorter.sort(supers)
516 pager.add("")
517 pager.add("== supers".bold)
518 pager.indent = pager.indent + 1
519 for mclass in supers do
520 pager.add("")
521 mclass.preview(index, pager)
522 end
523 pager.indent = pager.indent - 1
524 end
525 # formal types
526 if not self.parameter_types.is_empty then
527 pager.add("")
528 pager.add("== formal types".bold)
529 pager.indent = pager.indent + 1
530 for ft, bound in self.parameter_types do
531 pager.add("")
532 pager.add("{ft.to_s.bold.green}: {bound.to_console}")
533 end
534 pager.indent = pager.indent - 1
535 end
536 # intro mproperties
537 var psorter = new MPropDefNameSorter
538 var mpropdefs = intro.mpropdefs
539 index.mainmodule.linearize_mpropdefs(mpropdefs)
540 for cat in intro.cats2mpropdefs.keys do
541 var defs = intro.cats2mpropdefs[cat].to_a
542 if defs.is_empty then continue
543 psorter.sort(defs)
544 pager.add("")
545 pager.add("== {cat}".bold)
546 pager.indent = pager.indent + 1
547 for mpropdef in defs do
548 pager.add("")
549 mpropdef.preview(index, pager)
550 end
551 pager.indent = pager.indent - 1
552 end
553 # refinements
554 if not self.mclassdefs.is_empty then
555 pager.add("")
556 pager.add("== refinements".bold)
557 var mclassdefs = self.mclassdefs
558 index.mainmodule.linearize_mclassdefs(mclassdefs)
559 pager.indent = pager.indent + 1
560 for mclassdef in mclassdefs do
561 if not mclassdef.is_intro then
562 pager.add("")
563 mclassdef.content(index, pager)
564 end
565 end
566 pager.indent = pager.indent - 1
567 end
568 pager.indent = pager.indent - 1
569 end
570 end
571
572 redef class MClassDef
573 super IndexMatch
574
575 private fun namespace: String do
576 return "{mmodule.full_name}::{mclass.name}"
577 end
578
579 fun to_console: String do
580 var res = new Buffer
581 if not is_intro then res.append("redef ")
582 res.append(mclass.prototype)
583 return res.to_s
584 end
585
586 redef fun preview(index, pager) do
587 if index.mbuilder.mclassdef2nclassdef.has_key(self) then
588 var node = index.mbuilder.mclassdef2nclassdef[self]
589 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.short_comment.is_empty then
590 pager.add(node.n_doc.short_comment.green)
591 end
592 end
593 pager.add(to_console)
594 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
595 end
596
597 redef fun content(index, pager) do
598 if index.mbuilder.mclassdef2nclassdef.has_key(self) then
599 var node = index.mbuilder.mclassdef2nclassdef[self]
600 if node isa AStdClassdef and not node.n_doc == null and not node.n_doc.comment.is_empty then
601 for comment in node.n_doc.comment do pager.add(comment.green)
602 end
603 end
604 pager.add(to_console)
605 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
606 pager.indent = pager.indent + 1
607 var mpropdefs = self.mpropdefs
608 var psorter = new MPropDefNameSorter
609 index.mainmodule.linearize_mpropdefs(mpropdefs)
610 for cat in cats2mpropdefs.keys do
611 var defs = cats2mpropdefs[cat].to_a
612 psorter.sort(defs)
613 if defs.is_empty then continue
614 pager.add("")
615 pager.add("== {cat}".bold)
616 pager.indent = pager.indent + 1
617 for mpropdef in defs do
618 pager.add("")
619 mpropdef.preview(index, pager)
620 end
621 pager.indent = pager.indent - 1
622 end
623 pager.indent = pager.indent - 1
624 end
625
626 # get mpropdefs grouped by categories (vt, init, methods)
627 fun cats2mpropdefs: Map[String, Set[MPropDef]] do
628 var cats = new ArrayMap[String, Set[MPropDef]]
629 cats["virtual types"] = new HashSet[MPropDef]
630 cats["constructors"] = new HashSet[MPropDef]
631 cats["methods"] = new HashSet[MPropDef]
632
633 for mpropdef in mpropdefs do
634 if mpropdef isa MAttributeDef then continue
635 if mpropdef isa MVirtualTypeDef then cats["virtual types"].add(mpropdef)
636 if mpropdef isa MMethodDef then
637 if mpropdef.mproperty.is_init then
638 cats["constructors"].add(mpropdef)
639 else
640 cats["methods"].add(mpropdef)
641 end
642 end
643 end
644 return cats
645 end
646 end
647
648 redef class MProperty
649 super IndexMatch
650
651 fun to_console: String do
652 if visibility.to_s == "public" then return name.green
653 if visibility.to_s == "private" then return name.red
654 if visibility.to_s == "protected" then return name.yellow
655 return name.bold
656 end
657
658 redef fun preview(index, pager) do
659 intro.preview(index, pager)
660 end
661
662 redef fun content(index, pager) do
663 intro.content(index, pager)
664 pager.indent = pager.indent + 1
665 var mpropdefs = self.mpropdefs
666 index.mainmodule.linearize_mpropdefs(mpropdefs)
667 for mpropdef in mpropdefs do
668 if mpropdef isa MAttributeDef then continue
669 if not mpropdef.is_intro then
670 pager.add("")
671 mpropdef.preview(index, pager)
672 end
673 end
674 pager.indent = pager.indent - 1
675 end
676 end
677
678 redef class MPropDef
679 super IndexMatch
680
681 fun to_console: String is abstract
682
683 private fun namespace: String do
684 return "{mclassdef.namespace}::{mproperty.name}"
685 end
686
687 redef fun preview(index, pager) do
688 if index.mbuilder.mpropdef2npropdef.has_key(self) then
689 var nprop = index.mbuilder.mpropdef2npropdef[self]
690 if not nprop.n_doc == null and not nprop.n_doc.short_comment.is_empty then
691 pager.add(nprop.n_doc.short_comment.green)
692 end
693 end
694 pager.add(to_console)
695 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
696 end
697
698 redef fun content(index, pager) do
699 if index.mbuilder.mpropdef2npropdef.has_key(self) then
700 var nprop = index.mbuilder.mpropdef2npropdef[self]
701 if not nprop.n_doc == null and not nprop.n_doc.comment.is_empty then
702 for comment in nprop.n_doc.comment do pager.add(comment.green)
703 end
704 end
705 pager.add(to_console)
706 pager.add("{namespace}".bold.gray + " (lines {location.lines})".gray)
707 end
708 end
709
710 redef class MMethodDef
711 redef fun to_console do
712 var res = new Buffer
713 if not is_intro then res.append("redef ")
714 if not mproperty.is_init then res.append("fun ")
715 res.append(mproperty.to_console.bold)
716 if msignature != null then res.append(msignature.to_console)
717 # FIXME: modifiers should be accessible via the model
718 #if self isa ADeferredMethPropdef then ret = "{ret} is abstract"
719 #if self isa AInternMethPropdef then ret = "{ret} is intern"
720 #if self isa AExternMethPropdef then ret = "{ret} is extern"
721 return res.to_s
722 end
723 end
724
725 redef class MVirtualTypeDef
726 redef fun to_console do
727 var res = new Buffer
728 res.append("type ")
729 res.append(mproperty.to_console.bold)
730 res.append(": {bound.to_console}")
731 return res.to_s
732 end
733 end
734
735 redef class MAttributeDef
736 redef fun to_console do
737 var res = new Buffer
738 res.append("var ")
739 res.append(mproperty.to_console.bold)
740 res.append(": {static_mtype.to_console}")
741 return res.to_s
742 end
743 end
744
745 redef class MSignature
746 redef fun to_console do
747 var res = new Buffer
748 if not mparameters.is_empty then
749 res.append("(")
750 for i in [0..mparameters.length[ do
751 res.append(mparameters[i].to_console)
752 if i < mparameters.length - 1 then res.append(", ")
753 end
754 res.append(")")
755 end
756 if return_mtype != null then
757 res.append(": {return_mtype.to_console}")
758 end
759 return res.to_s
760 end
761 end
762
763 redef class MParameter
764 fun to_console: String do
765 var res = new Buffer
766 res.append("{name}: {mtype.to_console}")
767 if is_vararg then res.append("...")
768 return res.to_s
769 end
770 end
771
772 redef class MType
773 fun to_console: String do return self.to_s
774 end
775
776 redef class MNullableType
777 redef fun to_console do return "nullable {mtype.to_console}"
778 end
779
780 redef class MGenericType
781 redef fun to_console do
782 var res = new Buffer
783 res.append("{mclass.name}[")
784 for i in [0..arguments.length[ do
785 res.append(arguments[i].to_console)
786 if i < arguments.length - 1 then res.append(", ")
787 end
788 res.append("]")
789 return res.to_s
790 end
791 end
792
793 redef class MParameterType
794 redef fun to_console do return mclass.intro.parameter_names[rank]
795 end
796
797 redef class MVirtualType
798 redef fun to_console do return mproperty.name
799 end
800
801 redef class ADoc
802 private fun comment: List[String] do
803 var res = new List[String]
804 for t in n_comment do
805 res.add(t.text.replace("\n", ""))
806 end
807 return res
808 end
809
810 private fun short_comment: String do
811 return n_comment.first.text.replace("\n", "")
812 end
813 end
814
815 redef class AAttrPropdef
816 private fun read_accessor: String do
817 var ret = "fun "
818 #FIXME bug with standard::stream::FDStream::fd
819 var name = mreadpropdef.mproperty.name
820 if mpropdef.mproperty.visibility.to_s == "public" then ret = "{ret}{name.green}"
821 if mpropdef.mproperty.visibility.to_s == "private" then ret = "{ret}{name.red}"
822 if mpropdef.mproperty.visibility.to_s == "protected" then ret = "{ret}{name.yellow}"
823 ret = "{ret}: {n_type.to_s}"
824 if n_kwredef != null then ret = "redef {ret}"
825 return ret
826 end
827
828 private fun write_accessor: String do
829 var ret = "fun "
830 var name = "{mreadpropdef.mproperty.name}="
831 if n_readable != null and n_readable.n_visibility != null then
832 if n_readable.n_visibility isa APublicVisibility then ret = "{ret}{name.green}"
833 if n_readable.n_visibility isa APrivateVisibility then ret = "{ret}{name.red}"
834 if n_readable.n_visibility isa AProtectedVisibility then ret = "{ret}{name.yellow}"
835 else
836 ret = "{ret}{name.red}"
837 end
838 ret = "{ret}({mreadpropdef.mproperty.name}: {n_type.to_s})"
839 if n_kwredef != null then ret = "redef {ret}"
840 return ret
841 end
842 end
843
844 # Redef String class to add a function to color the string
845 redef class String
846
847 private fun add_escape_char(escapechar: String): String do
848 return "{escapechar}{self}\\033[0m"
849 end
850
851 private fun esc: Char do return 27.ascii
852 private fun gray: String do return add_escape_char("{esc}[30m")
853 private fun red: String do return add_escape_char("{esc}[31m")
854 private fun green: String do return add_escape_char("{esc}[32m")
855 private fun yellow: String do return add_escape_char("{esc}[33m")
856 private fun blue: String do return add_escape_char("{esc}[34m")
857 private fun purple: String do return add_escape_char("{esc}[35m")
858 private fun cyan: String do return add_escape_char("{esc}[36m")
859 private fun light_gray: String do return add_escape_char("{esc}[37m")
860 private fun bold: String do return add_escape_char("{esc}[1m")
861 private fun underline: String do return add_escape_char("{esc}[4m")
862
863 private fun escape: String
864 do
865 var b = new Buffer
866 for c in self.chars do
867 if c == '\n' then
868 b.append("\\n")
869 else if c == '\0' then
870 b.append("\\0")
871 else if c == '"' then
872 b.append("\\\"")
873 else if c == '\\' then
874 b.append("\\\\")
875 else if c == '`' then
876 b.append("'")
877 else if c.ascii < 32 then
878 b.append("\\{c.ascii.to_base(8, false)}")
879 else
880 b.add(c)
881 end
882 end
883 return b.to_s
884 end
885 end
886
887 redef class Location
888 fun lines: String do
889 return "{line_start}-{line_end}"
890 end
891 end
892
893 # Create a tool context to handle options and paths
894 var toolcontext = new ToolContext
895 toolcontext.process_options
896
897 # Here we launch the nit index
898 var ni = new NitIndex(toolcontext)
899 ni.start
900
901 # TODO seek subclasses and super classes <.<class> >.<class>
902 # TODO seek subclasses and super types <:<type> >:<type>
903 # TODO seek with regexp
904 # TODO standardize namespaces with private option