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