Fix opts: forgot to assign the default value.
[nit.git] / lib / opts.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
4 # Copyright 2008 Jean Privat <jean@pryen.org>
5 #
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
12 # another product.
13
14 # Super class of all option's class
15 class Option
16 # Names for the option (including long and short ones)
17 readable attr _names: Array[String]
18
19 # Type of the value of the option
20 type VALUE: Object
21
22 # Human readable description of the option
23 readable attr _helptext: String
24
25 # Is this option mandatory?
26 readable writable attr _mandatory: Bool
27
28 # context where the option is located
29 readable writable attr _context: OptionContext
30
31 # Current value of this option
32 readable writable attr _value: VALUE
33
34 # Default value of this option
35 readable writable attr _default_value: VALUE
36
37 # Create a new option
38 init init_opt(help: String, default: VALUE, names: Array[String])
39 do
40 if names == null then
41 _names = new Array[String]
42 else
43 _names = names.to_a
44 end
45 _helptext = help
46 _mandatory = false
47 _default_value = default
48 _value = default
49 end
50
51 # Add new aliases for this option
52 meth add_aliases(names: String...) do _names.add_all(names)
53
54 # An help text for this option with default settings
55 redef meth to_s do return pretty(2)
56
57 # A pretty print for this help
58 meth pretty(off: Int): String
59 do
60 var text = " "
61 text.append(_names.join(", "))
62 text.append(" ")
63 var rest = off - text.length
64 if rest > 0 then text.append(" " * rest)
65 text.append(helptext)
66 #text.append(pretty_default)
67 return text
68 end
69
70 meth pretty_default: String
71 do
72 if default_value != null then
73 return " ({default_value})"
74 end
75 return ""
76 end
77
78 # Consume parameters for this option
79 protected meth read_param(it: Iterator[String]) is abstract
80 end
81
82 class OptionText
83 special Option
84 init(text: String) do init_opt(text, null, null)
85
86 redef meth pretty(off) do return to_s
87
88 redef meth to_s do return helptext
89 end
90
91 class OptionBool
92 special Option
93 redef type VALUE: Bool
94
95 init(help: String, names: String...) do init_opt(help, false, names)
96
97 redef meth read_param(it) do value = true
98 end
99
100 # Option with one mandatory parameter
101 class OptionParameter
102 special Option
103 protected meth convert(str: String): VALUE is abstract
104
105 redef meth read_param(it)
106 do
107 assert context != null
108 if it.is_ok then
109 value = convert(it.item)
110 it.next
111 else
112 # TODO: What to do?
113 end
114 end
115
116 init init_opt(h, d, n) do super
117 end
118
119 class OptionString
120 special OptionParameter
121 redef type VALUE: String
122
123 init(help: String, names: String...) do init_opt(help, null, names)
124
125 redef meth convert(str) do return str
126 end
127
128 class OptionEnum
129 special OptionParameter
130 redef type VALUE: Int
131 attr _enum: Array[String]
132
133 init(enum: Array[String], help: String, default: Int, names: String...)
134 do
135 assert enum != null and enum.length > 0
136 _enum = enum.to_a
137 init_opt("{help} <{enum.join(", ")}>", default, names)
138 end
139
140 redef meth convert(str)
141 do
142 var id = _enum.index_of(str)
143 return id
144 end
145
146 redef meth pretty_default
147 do
148 if default_value != null then
149 return " ({_enum[default_value]})"
150 else
151 return ""
152 end
153 end
154 end
155
156 class OptionInt
157 special OptionParameter
158 redef type VALUE: Int
159
160 init(help: String, default: Int, names: String...) do init_opt(help, default, names)
161
162 redef meth convert(str) do return str.to_i
163 end
164
165 class OptionArray
166 special OptionParameter
167 redef type VALUE: Array[String]
168
169 init(help: String, names: String...)
170 do
171 _values = new Array[String]
172 init_opt(help, _values, names)
173 end
174
175 attr _values: Array[String]
176 redef meth convert(str)
177 do
178 _values.add(str)
179 return _values
180 end
181 end
182
183 class OptionContext
184 readable attr _options: Array[Option]
185 readable attr _rest: Array[String]
186
187 attr _optmap: Map[String, Option]
188
189 meth usage
190 do
191 var lmax = 1
192 for i in _options do
193 var l = 3
194 for n in i.names do
195 l += n.length + 2
196 end
197 if lmax < l then lmax = l
198 end
199
200 for i in _options do
201 print(i.pretty(lmax))
202 end
203 end
204
205 # Parse ans assign options everywhere is the argument list
206 meth parse(argv: Collection[String])
207 do
208 var it = argv.iterator
209 parse_intern(it)
210 end
211
212 protected meth parse_intern(it: Iterator[String])
213 do
214 var parseargs = true
215 build
216 var rest = _rest
217
218 while parseargs and it.is_ok do
219 var str = it.item
220 if str == "--" then
221 it.next
222 rest.add_all(it.to_a)
223 parseargs = false
224 else
225 if _optmap.has_key(str) then
226 var opt = _optmap[str]
227 it.next
228 opt.read_param(it)
229 else
230 rest.add(it.item)
231 it.next
232 end
233 end
234 end
235 end
236
237 meth add_option(opts: Option...)
238 do
239 for opt in opts do
240 opt.context = self
241 _options.add(opt)
242 end
243 end
244
245 init
246 do
247 _options = new Array[Option]
248 _optmap = new HashMap[String, Option]
249 _rest = new Array[String]
250 end
251
252 private meth build
253 do
254 for o in _options do
255 for n in o.names do
256 _optmap[n] = o
257 end
258 end
259 end
260 end