28 case object Int extends Type |
28 case object Int extends Type |
29 case object Real extends Type |
29 case object Real extends Type |
30 case object String extends Type |
30 case object String extends Type |
31 case object Unknown extends Type |
31 case object Unknown extends Type |
32 |
32 |
33 case class Opt(name: String, typ: Type, value: String, description: String) |
33 case class Opt(name: String, typ: Type, value: String, description: String, section: String) |
34 { |
34 { |
35 def print: String = |
35 def print: String = |
36 "option " + name + " : " + typ.print + " = " + |
36 "option " + name + " : " + typ.print + " = " + |
37 (if (typ == Options.String) quote(value) else value) + |
37 (if (typ == Options.String) quote(value) else value) + |
38 (if (description == "") "" else "\n -- " + quote(description)) |
38 (if (description == "") "" else "\n -- " + quote(description)) |
39 |
39 |
|
40 def title(strip: String): String = |
|
41 { |
|
42 val words = space_explode('_', name) |
|
43 val words1 = |
|
44 words match { |
|
45 case word :: rest if word == strip => rest |
|
46 case _ => words |
|
47 } |
|
48 words1.map(Library.capitalize).mkString(" ") |
|
49 } |
|
50 |
40 def unknown: Boolean = typ == Unknown |
51 def unknown: Boolean = typ == Unknown |
41 } |
52 } |
42 |
53 |
43 |
54 |
44 /* parsing */ |
55 /* parsing */ |
45 |
56 |
|
57 private val SECTION = "section" |
46 private val OPTION = "option" |
58 private val OPTION = "option" |
47 private val OPTIONS = Path.explode("etc/options") |
59 private val OPTIONS = Path.explode("etc/options") |
48 private val PREFS = Path.explode("$ISABELLE_HOME_USER/etc/preferences") |
60 private val PREFS = Path.explode("$ISABELLE_HOME_USER/etc/preferences") |
49 private val PREFS_BACKUP = Path.explode("$ISABELLE_HOME_USER/etc/preferences~") |
61 private val PREFS_BACKUP = Path.explode("$ISABELLE_HOME_USER/etc/preferences~") |
50 |
62 |
51 lazy val options_syntax = Outer_Syntax.init() + ":" + "=" + "--" + (OPTION, Keyword.THY_DECL) |
63 lazy val options_syntax = |
|
64 Outer_Syntax.init() + ":" + "=" + "--" + |
|
65 (SECTION, Keyword.THY_HEADING2) + (OPTION, Keyword.THY_DECL) |
|
66 |
52 lazy val prefs_syntax = Outer_Syntax.init() + "=" |
67 lazy val prefs_syntax = Outer_Syntax.init() + "=" |
53 |
68 |
54 object Parser extends Parse.Parser |
69 object Parser extends Parse.Parser |
55 { |
70 { |
56 val option_name = atom("option name", _.is_xname) |
71 val option_name = atom("option name", _.is_xname) |
60 { case s ~ n => if (s.isDefined) "-" + n else n } | |
75 { case s ~ n => if (s.isDefined) "-" + n else n } | |
61 atom("option value", tok => tok.is_name || tok.is_float) |
76 atom("option value", tok => tok.is_name || tok.is_float) |
62 |
77 |
63 val option_entry: Parser[Options => Options] = |
78 val option_entry: Parser[Options => Options] = |
64 { |
79 { |
|
80 command(SECTION) ~! text ^^ |
|
81 { case _ ~ a => (options: Options) => options.set_section(a.trim) } | |
65 command(OPTION) ~! (option_name ~ keyword(":") ~ option_type ~ |
82 command(OPTION) ~! (option_name ~ keyword(":") ~ option_type ~ |
66 keyword("=") ~ option_value ~ (keyword("--") ~! text ^^ { case _ ~ x => x } | success(""))) ^^ |
83 keyword("=") ~ option_value ~ (keyword("--") ~! text ^^ { case _ ~ x => x } | success(""))) ^^ |
67 { case _ ~ (a ~ _ ~ b ~ _ ~ c ~ d) => (options: Options) => options.declare(a, b, c, d) } |
84 { case _ ~ (a ~ _ ~ b ~ _ ~ c ~ d) => (options: Options) => options.declare(a, b, c, d) } |
68 } |
85 } |
69 |
86 |
80 val ops = |
97 val ops = |
81 parse_all(rep(parser), Token.reader(toks, file.implode)) match { |
98 parse_all(rep(parser), Token.reader(toks, file.implode)) match { |
82 case Success(result, _) => result |
99 case Success(result, _) => result |
83 case bad => error(bad.toString) |
100 case bad => error(bad.toString) |
84 } |
101 } |
85 try { (options /: ops) { case (opts, op) => op(opts) } } |
102 try { (options.set_section("") /: ops) { case (opts, op) => op(opts) } } |
86 catch { case ERROR(msg) => error(msg + Position.here(file.position)) } |
103 catch { case ERROR(msg) => error(msg + Position.here(file.position)) } |
87 } |
104 } |
88 } |
105 } |
89 |
106 |
90 def init_defaults(): Options = |
107 def init_defaults(): Options = |
123 } |
140 } |
124 } |
141 } |
125 } |
142 } |
126 |
143 |
127 |
144 |
128 final class Options private(protected val options: Map[String, Options.Opt] = Map.empty) |
145 final class Options private( |
|
146 protected val options: Map[String, Options.Opt] = Map.empty, |
|
147 val section: String = "") |
129 { |
148 { |
130 override def toString: String = options.iterator.mkString("Options (", ",", ")") |
149 override def toString: String = options.iterator.mkString("Options (", ",", ")") |
131 |
150 |
132 def print: String = cat_lines(options.toList.sortBy(_._1).map(p => p._2.print)) |
151 def print: String = cat_lines(options.toList.sortBy(_._1).map(p => p._2.print)) |
133 |
|
134 def title(strip: String, name: String): String = |
|
135 { |
|
136 check_name(name) |
|
137 val words = space_explode('_', name) |
|
138 val words1 = |
|
139 words match { |
|
140 case word :: rest if word == strip => rest |
|
141 case _ => words |
|
142 } |
|
143 words1.map(Library.capitalize).mkString(" ") |
|
144 } |
|
145 |
152 |
146 def description(name: String): String = check_name(name).description |
153 def description(name: String): String = check_name(name).description |
147 |
154 |
148 |
155 |
149 /* check */ |
156 /* check */ |
165 /* basic operations */ |
172 /* basic operations */ |
166 |
173 |
167 private def put[A](name: String, typ: Options.Type, value: String): Options = |
174 private def put[A](name: String, typ: Options.Type, value: String): Options = |
168 { |
175 { |
169 val opt = check_type(name, typ) |
176 val opt = check_type(name, typ) |
170 new Options(options + (name -> opt.copy(value = value))) |
177 new Options(options + (name -> opt.copy(value = value)), section) |
171 } |
178 } |
172 |
179 |
173 private def get[A](name: String, typ: Options.Type, parse: String => Option[A]): A = |
180 private def get[A](name: String, typ: Options.Type, parse: String => Option[A]): A = |
174 { |
181 { |
175 val opt = check_type(name, typ) |
182 val opt = check_type(name, typ) |
237 case "int" => Options.Int |
244 case "int" => Options.Int |
238 case "real" => Options.Real |
245 case "real" => Options.Real |
239 case "string" => Options.String |
246 case "string" => Options.String |
240 case _ => error("Unknown type for option " + quote(name) + " : " + quote(typ_name)) |
247 case _ => error("Unknown type for option " + quote(name) + " : " + quote(typ_name)) |
241 } |
248 } |
242 val opt = Options.Opt(name, typ, value, description) |
249 val opt = Options.Opt(name, typ, value, description, section) |
243 (new Options(options + (name -> opt))).check_value(name) |
250 (new Options(options + (name -> opt), section)).check_value(name) |
244 } |
251 } |
245 } |
252 } |
246 |
253 |
247 def add_permissive(name: String, value: String): Options = |
254 def add_permissive(name: String, value: String): Options = |
248 { |
255 { |
249 if (options.isDefinedAt(name)) this + (name, value) |
256 if (options.isDefinedAt(name)) this + (name, value) |
250 else new Options(options + (name -> Options.Opt(name, Options.Unknown, value, ""))) |
257 else new Options(options + (name -> Options.Opt(name, Options.Unknown, value, "", "")), section) |
251 } |
258 } |
252 |
259 |
253 def + (name: String, value: String): Options = |
260 def + (name: String, value: String): Options = |
254 { |
261 { |
255 val opt = check_name(name) |
262 val opt = check_name(name) |
256 (new Options(options + (name -> opt.copy(value = value)))).check_value(name) |
263 (new Options(options + (name -> opt.copy(value = value)), section)).check_value(name) |
257 } |
264 } |
258 |
265 |
259 def + (name: String, opt_value: Option[String]): Options = |
266 def + (name: String, opt_value: Option[String]): Options = |
260 { |
267 { |
261 val opt = check_name(name) |
268 val opt = check_name(name) |
274 } |
281 } |
275 } |
282 } |
276 |
283 |
277 def ++ (specs: List[Options.Spec]): Options = |
284 def ++ (specs: List[Options.Spec]): Options = |
278 (this /: specs)({ case (x, (y, z)) => x + (y, z) }) |
285 (this /: specs)({ case (x, (y, z)) => x + (y, z) }) |
|
286 |
|
287 |
|
288 /* sections */ |
|
289 |
|
290 def set_section(new_section: String): Options = |
|
291 new Options(options, new_section) |
|
292 |
|
293 def sections: List[(String, List[Options.Opt])] = |
|
294 options.groupBy(_._2.section).toList.map({ case (a, opts) => (a, opts.toList.map(_._2)) }) |
279 |
295 |
280 |
296 |
281 /* encode */ |
297 /* encode */ |
282 |
298 |
283 def encode: XML.Body = |
299 def encode: XML.Body = |