| author | wenzelm | 
| Tue, 26 Jul 2022 19:06:03 +0200 | |
| changeset 75699 | 0a71b6c903e9 | 
| parent 75405 | b13ab7d11b90 | 
| child 75842 | a8c401312f9d | 
| permissions | -rw-r--r-- | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 1 | /* Title: Pure/System/options.scala | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 3 | |
| 51945 | 4 | System options with external string representation. | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 5 | */ | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 6 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 7 | package isabelle | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 8 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 9 | |
| 75393 | 10 | object Options {
 | 
| 48421 | 11 | type Spec = (String, Option[String]) | 
| 12 | ||
| 13 | val empty: Options = new Options() | |
| 14 | ||
| 15 | ||
| 16 | /* representation */ | |
| 17 | ||
| 75393 | 18 |   sealed abstract class Type {
 | 
| 56599 | 19 | def print: String = Word.lowercase(toString) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 20 | } | 
| 49246 | 21 | case object Bool extends Type | 
| 22 | case object Int extends Type | |
| 23 | case object Real extends Type | |
| 24 | case object String extends Type | |
| 25 | case object Unknown extends Type | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 26 | |
| 56465 | 27 | case class Opt( | 
| 28 | public: Boolean, | |
| 29 | pos: Position.T, | |
| 30 | name: String, | |
| 31 | typ: Type, | |
| 32 | value: String, | |
| 33 | default_value: String, | |
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 34 | standard_value: Option[String], | 
| 56465 | 35 | description: String, | 
| 75393 | 36 | section: String | 
| 37 |   ) {
 | |
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 38 | private def print_value(x: String): String = if (typ == Options.String) quote(x) else x | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 39 | private def print_standard: String = | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 40 |       standard_value match {
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 41 | case None => "" | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 42 | case Some(s) if s == default_value => " (standard)" | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 43 | case Some(s) => " (standard " + print_value(s) + ")" | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 44 | } | 
| 75393 | 45 |     private def print(default: Boolean): String = {
 | 
| 49289 | 46 | val x = if (default) default_value else value | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 47 | "option " + name + " : " + typ.print + " = " + print_value(x) + print_standard + | 
| 49289 | 48 | (if (description == "") "" else "\n -- " + quote(description)) | 
| 49 | } | |
| 50 | ||
| 51 | def print: String = print(false) | |
| 52 | def print_default: String = print(true) | |
| 49247 | 53 | |
| 75393 | 54 |     def title(strip: String = ""): String = {
 | 
| 56600 | 55 |       val words = Word.explode('_', name)
 | 
| 49270 | 56 | val words1 = | 
| 57 |         words match {
 | |
| 58 | case word :: rest if word == strip => rest | |
| 59 | case _ => words | |
| 60 | } | |
| 71601 | 61 | Word.implode(words1.map(Word.perhaps_capitalize)) | 
| 49270 | 62 | } | 
| 63 | ||
| 48860 | 64 | def unknown: Boolean = typ == Unknown | 
| 65 | } | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 66 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 67 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 68 | /* parsing */ | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 69 | |
| 49270 | 70 | private val SECTION = "section" | 
| 52065 
78f2475aa126
explicit notion of public options, which are shown in the editor options dialog;
 wenzelm parents: 
51945diff
changeset | 71 | private val PUBLIC = "public" | 
| 48795 
bece259ee055
clarified format of etc/options: only declarations, not re-definitions;
 wenzelm parents: 
48718diff
changeset | 72 | private val OPTION = "option" | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 73 | private val STANDARD = "standard" | 
| 48807 | 74 |   private val OPTIONS = Path.explode("etc/options")
 | 
| 67845 | 75 |   private val PREFS = Path.explode("$ISABELLE_HOME_USER/etc/preferences")
 | 
| 48713 
de26cf3191a3
more token markers, based on actual outer syntax;
 wenzelm parents: 
48693diff
changeset | 76 | |
| 71601 | 77 | val options_syntax: Outer_Syntax = | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 78 |     Outer_Syntax.empty + ":" + "=" + "--" + "(" + ")" +
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 79 | Symbol.comment + Symbol.comment_decoded + | 
| 63441 | 80 | (SECTION, Keyword.DOCUMENT_HEADING) + | 
| 81 | (PUBLIC, Keyword.BEFORE_COMMAND) + | |
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 82 | (OPTION, Keyword.THY_DECL) + | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 83 | STANDARD | 
| 49270 | 84 | |
| 71601 | 85 | val prefs_syntax: Outer_Syntax = Outer_Syntax.empty + "=" | 
| 48713 
de26cf3191a3
more token markers, based on actual outer syntax;
 wenzelm parents: 
48693diff
changeset | 86 | |
| 75405 | 87 |   trait Parsers extends Parse.Parsers {
 | 
| 71601 | 88 |     val option_name: Parser[String] = atom("option name", _.is_name)
 | 
| 89 |     val option_type: Parser[String] = atom("option type", _.is_name)
 | |
| 90 | val option_value: Parser[String] = | |
| 48807 | 91 |       opt(token("-", tok => tok.is_sym_ident && tok.content == "-")) ~ atom("nat", _.is_nat) ^^
 | 
| 92 |         { case s ~ n => if (s.isDefined) "-" + n else n } |
 | |
| 93 |       atom("option value", tok => tok.is_name || tok.is_float)
 | |
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 94 | val option_standard: Parser[Option[String]] = | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 95 |       $$$("(") ~! $$$(STANDARD) ~ opt(option_value) ~ $$$(")") ^^ { case _ ~ _ ~ a ~ _ => a }
 | 
| 62968 | 96 | } | 
| 48807 | 97 | |
| 75405 | 98 |   private object Parsers extends Parsers {
 | 
| 61579 | 99 | def comment_marker: Parser[String] = | 
| 100 |       $$$("--") | $$$(Symbol.comment) | $$$(Symbol.comment_decoded)
 | |
| 101 | ||
| 75393 | 102 |     val option_entry: Parser[Options => Options] = {
 | 
| 49270 | 103 | command(SECTION) ~! text ^^ | 
| 49295 | 104 |         { case _ ~ a => (options: Options) => options.set_section(a) } |
 | 
| 60133 
a90982bbe8b4
clarified keywords for quasi-command spans and Sidekick structure;
 wenzelm parents: 
59811diff
changeset | 105 |       opt($$$(PUBLIC)) ~ command(OPTION) ~! (position(option_name) ~ $$$(":") ~ option_type ~
 | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 106 |       $$$("=") ~ option_value ~ opt(option_standard) ~
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 107 |         (comment_marker ~! text ^^ { case _ ~ x => x } | success(""))) ^^
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 108 |         { case a ~ _ ~ ((b, pos) ~ _ ~ c ~ _ ~ d ~ e ~ f) =>
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 109 | (options: Options) => options.declare(a.isDefined, pos, b, c, d, e, f) } | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 110 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 111 | |
| 75393 | 112 |     val prefs_entry: Parser[Options => Options] = {
 | 
| 58908 | 113 |       option_name ~ ($$$("=") ~! option_value) ^^
 | 
| 48860 | 114 |       { case a ~ (_ ~ b) => (options: Options) => options.add_permissive(a, b) }
 | 
| 48807 | 115 | } | 
| 116 | ||
| 75393 | 117 | def parse_file( | 
| 118 | options: Options, | |
| 119 | file_name: String, | |
| 120 | content: String, | |
| 67845 | 121 | syntax: Outer_Syntax = options_syntax, | 
| 75393 | 122 | parser: Parser[Options => Options] = option_entry | 
| 123 |     ): Options = {
 | |
| 67845 | 124 | val toks = Token.explode(syntax.keywords, content) | 
| 48807 | 125 | val ops = | 
| 67845 | 126 |         parse_all(rep(parser), Token.reader(toks, Token.Pos.file(file_name))) match {
 | 
| 48807 | 127 | case Success(result, _) => result | 
| 128 | case bad => error(bad.toString) | |
| 129 | } | |
| 73359 | 130 |       try { ops.foldLeft(options.set_section("")) { case (opts, op) => op(opts) } }
 | 
| 73166 | 131 |       catch { case ERROR(msg) => error(msg + Position.here(Position.File(file_name))) }
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 132 | } | 
| 67845 | 133 | |
| 134 | def parse_prefs(options: Options, content: String): Options = | |
| 69366 | 135 | parse_file(options, PREFS.file_name, content, syntax = prefs_syntax, parser = prefs_entry) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 136 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 137 | |
| 67845 | 138 | def read_prefs(file: Path = PREFS): String = | 
| 139 | if (file.is_file) File.read(file) else "" | |
| 64186 
49816908ae42
support for separate sub-system options, independent of main Isabelle options;
 wenzelm parents: 
64151diff
changeset | 140 | |
| 75393 | 141 |   def init(prefs: String = read_prefs(PREFS), opts: List[String] = Nil): Options = {
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 142 | var options = empty | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 143 |     for {
 | 
| 73815 | 144 | dir <- Components.directories() | 
| 48548 | 145 | file = dir + OPTIONS if file.is_file | 
| 75405 | 146 |     } { options = Parsers.parse_file(options, file.implode, File.read(file)) }
 | 
| 147 | opts.foldLeft(Parsers.parse_prefs(options, prefs))(_ + _) | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 148 | } | 
| 48457 | 149 | |
| 150 | ||
| 62832 | 151 | /* Isabelle tool wrapper */ | 
| 48693 
ceeea46bdeba
"isabelle options" prints Isabelle system options;
 wenzelm parents: 
48605diff
changeset | 152 | |
| 72763 | 153 |   val isabelle_tool = Isabelle_Tool("options", "print Isabelle system options",
 | 
| 75394 | 154 | Scala_Project.here, | 
| 155 |     { args =>
 | |
| 156 | var build_options = false | |
| 157 | var get_option = "" | |
| 158 | var list_options = false | |
| 159 | var export_file = "" | |
| 62437 | 160 | |
| 75394 | 161 |       val getopts = Getopts("""
 | 
| 62437 | 162 | Usage: isabelle options [OPTIONS] [MORE_OPTIONS ...] | 
| 48693 
ceeea46bdeba
"isabelle options" prints Isabelle system options;
 wenzelm parents: 
48605diff
changeset | 163 | |
| 62437 | 164 | Options are: | 
| 165 | -b include $ISABELLE_BUILD_OPTIONS | |
| 166 | -g OPTION get value of OPTION | |
| 167 | -l list options | |
| 168 | -x FILE export options to FILE in YXML format | |
| 169 | ||
| 170 | Report Isabelle system options, augmented by MORE_OPTIONS given as | |
| 171 | arguments NAME=VAL or NAME. | |
| 172 | """, | |
| 75394 | 173 | "b" -> (_ => build_options = true), | 
| 174 | "g:" -> (arg => get_option = arg), | |
| 175 | "l" -> (_ => list_options = true), | |
| 176 | "x:" -> (arg => export_file = arg)) | |
| 52737 
7b396ef36af6
clarified meaning of options for "isabelle options";
 wenzelm parents: 
52735diff
changeset | 177 | |
| 75394 | 178 | val more_options = getopts(args) | 
| 179 | if (get_option == "" && !list_options && export_file == "") getopts.usage() | |
| 52737 
7b396ef36af6
clarified meaning of options for "isabelle options";
 wenzelm parents: 
52735diff
changeset | 180 | |
| 75394 | 181 |       val options = {
 | 
| 182 | val options0 = Options.init() | |
| 183 | val options1 = | |
| 184 | if (build_options) | |
| 185 |             Word.explode(Isabelle_System.getenv("ISABELLE_BUILD_OPTIONS")).foldLeft(options0)(_ + _)
 | |
| 186 | else options0 | |
| 187 | more_options.foldLeft(options1)(_ + _) | |
| 188 | } | |
| 48693 
ceeea46bdeba
"isabelle options" prints Isabelle system options;
 wenzelm parents: 
48605diff
changeset | 189 | |
| 75394 | 190 | if (get_option != "") | 
| 191 | Output.writeln(options.check_name(get_option).value, stdout = true) | |
| 62437 | 192 | |
| 75394 | 193 | if (export_file != "") | 
| 194 | File.write(Path.explode(export_file), YXML.string_of_body(options.encode)) | |
| 62437 | 195 | |
| 75394 | 196 | if (get_option == "" && export_file == "") | 
| 197 | Output.writeln(options.print, stdout = true) | |
| 198 | }) | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 199 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 200 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 201 | |
| 49270 | 202 | final class Options private( | 
| 49296 | 203 | val options: Map[String, Options.Opt] = Map.empty, | 
| 75393 | 204 | val section: String = "" | 
| 205 | ) {
 | |
| 64186 
49816908ae42
support for separate sub-system options, independent of main Isabelle options;
 wenzelm parents: 
64151diff
changeset | 206 |   override def toString: String = options.iterator.mkString("Options(", ",", ")")
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 207 | |
| 54347 | 208 | private def print_opt(opt: Options.Opt): String = | 
| 209 | if (opt.public) "public " + opt.print else opt.print | |
| 210 | ||
| 211 | def print: String = cat_lines(options.toList.sortBy(_._1).map(p => print_opt(p._2))) | |
| 48693 
ceeea46bdeba
"isabelle options" prints Isabelle system options;
 wenzelm parents: 
48605diff
changeset | 212 | |
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 213 | def description(name: String): String = check_name(name).description | 
| 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 214 | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 215 | |
| 48370 | 216 | /* check */ | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 217 | |
| 49246 | 218 | def check_name(name: String): Options.Opt = | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 219 |     options.get(name) match {
 | 
| 48860 | 220 | case Some(opt) if !opt.unknown => opt | 
| 221 |       case _ => error("Unknown option " + quote(name))
 | |
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 222 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 223 | |
| 75393 | 224 |   private def check_type(name: String, typ: Options.Type): Options.Opt = {
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 225 | val opt = check_name(name) | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 226 | if (opt.typ == typ) opt | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 227 |     else error("Ill-typed option " + quote(name) + " : " + opt.typ.print + " vs. " + typ.print)
 | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 228 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 229 | |
| 48370 | 230 | |
| 231 | /* basic operations */ | |
| 232 | ||
| 75393 | 233 |   private def put[A](name: String, typ: Options.Type, value: String): Options = {
 | 
| 48370 | 234 | val opt = check_type(name, typ) | 
| 49270 | 235 | new Options(options + (name -> opt.copy(value = value)), section) | 
| 48370 | 236 | } | 
| 237 | ||
| 75393 | 238 |   private def get[A](name: String, typ: Options.Type, parse: String => Option[A]): A = {
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 239 | val opt = check_type(name, typ) | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 240 |     parse(opt.value) match {
 | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 241 | case Some(x) => x | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 242 | case None => | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 243 |         error("Malformed value for option " + quote(name) +
 | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 244 | " : " + typ.print + " =\n" + quote(opt.value)) | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 245 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 246 | } | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 247 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 248 | |
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 249 | /* internal lookup and update */ | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 250 | |
| 75393 | 251 |   class Bool_Access {
 | 
| 63805 | 252 | def apply(name: String): Boolean = get(name, Options.Bool, Value.Boolean.unapply) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 253 | def update(name: String, x: Boolean): Options = | 
| 63805 | 254 | put(name, Options.Bool, Value.Boolean(x)) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 255 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 256 | val bool = new Bool_Access | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 257 | |
| 75393 | 258 |   class Int_Access {
 | 
| 63805 | 259 | def apply(name: String): Int = get(name, Options.Int, Value.Int.unapply) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 260 | def update(name: String, x: Int): Options = | 
| 63805 | 261 | put(name, Options.Int, Value.Int(x)) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 262 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 263 | val int = new Int_Access | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 264 | |
| 75393 | 265 |   class Real_Access {
 | 
| 63805 | 266 | def apply(name: String): Double = get(name, Options.Real, Value.Double.unapply) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 267 | def update(name: String, x: Double): Options = | 
| 63805 | 268 | put(name, Options.Real, Value.Double(x)) | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 269 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 270 | val real = new Real_Access | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 271 | |
| 75393 | 272 |   class String_Access {
 | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 273 | def apply(name: String): String = get(name, Options.String, s => Some(s)) | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 274 | def update(name: String, x: String): Options = put(name, Options.String, x) | 
| 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 275 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 276 | val string = new String_Access | 
| 48370 | 277 | |
| 69074 | 278 | def proper_string(name: String): Option[String] = | 
| 279 | Library.proper_string(string(name)) | |
| 280 | ||
| 69073 | 281 | def seconds(name: String): Time = Time.seconds(real(name)) | 
| 50207 | 282 | |
| 48370 | 283 | |
| 48807 | 284 | /* external updates */ | 
| 48370 | 285 | |
| 75393 | 286 |   private def check_value(name: String): Options = {
 | 
| 48370 | 287 | val opt = check_name(name) | 
| 288 |     opt.typ match {
 | |
| 289 | case Options.Bool => bool(name); this | |
| 290 | case Options.Int => int(name); this | |
| 291 | case Options.Real => real(name); this | |
| 292 | case Options.String => string(name); this | |
| 48860 | 293 | case Options.Unknown => this | 
| 48370 | 294 | } | 
| 295 | } | |
| 296 | ||
| 56465 | 297 | def declare( | 
| 298 | public: Boolean, | |
| 299 | pos: Position.T, | |
| 300 | name: String, | |
| 301 | typ_name: String, | |
| 302 | value: String, | |
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 303 | standard: Option[Option[String]], | 
| 75393 | 304 | description: String | 
| 305 |   ): Options = {
 | |
| 48370 | 306 |     options.get(name) match {
 | 
| 56465 | 307 | case Some(other) => | 
| 308 |         error("Duplicate declaration of option " + quote(name) + Position.here(pos) +
 | |
| 309 | Position.here(other.pos)) | |
| 48370 | 310 | case None => | 
| 311 | val typ = | |
| 312 |           typ_name match {
 | |
| 313 | case "bool" => Options.Bool | |
| 314 | case "int" => Options.Int | |
| 315 | case "real" => Options.Real | |
| 316 | case "string" => Options.String | |
| 56465 | 317 | case _ => | 
| 318 |               error("Unknown type for option " + quote(name) + " : " + quote(typ_name) +
 | |
| 319 | Position.here(pos)) | |
| 48370 | 320 | } | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 321 | val standard_value = | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 322 |           standard match {
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 323 | case None => None | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 324 | case Some(_) if typ == Options.Bool => | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 325 |               error("Illegal standard value for option " + quote(name) + " : " + typ_name +
 | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 326 | Position.here) | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 327 | case Some(s) => Some(s.getOrElse(value)) | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 328 | } | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 329 | val opt = | 
| 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 330 | Options.Opt(public, pos, name, typ, value, value, standard_value, description, section) | 
| 49270 | 331 | (new Options(options + (name -> opt), section)).check_value(name) | 
| 48370 | 332 | } | 
| 333 | } | |
| 334 | ||
| 75393 | 335 |   def add_permissive(name: String, value: String): Options = {
 | 
| 48860 | 336 | if (options.isDefinedAt(name)) this + (name, value) | 
| 56465 | 337 |     else {
 | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 338 | val opt = Options.Opt(false, Position.none, name, Options.Unknown, value, value, None, "", "") | 
| 56465 | 339 | new Options(options + (name -> opt), section) | 
| 340 | } | |
| 48860 | 341 | } | 
| 342 | ||
| 75393 | 343 |   def + (name: String, value: String): Options = {
 | 
| 48370 | 344 | val opt = check_name(name) | 
| 49270 | 345 | (new Options(options + (name -> opt.copy(value = value)), section)).check_value(name) | 
| 48370 | 346 | } | 
| 347 | ||
| 75393 | 348 |   def + (name: String, opt_value: Option[String]): Options = {
 | 
| 48370 | 349 | val opt = check_name(name) | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 350 |     opt_value orElse opt.standard_value match {
 | 
| 48807 | 351 | case Some(value) => this + (name, value) | 
| 74827 
c1b5d6e6ff74
clarified system option standard values: avoid oddities like "isabelle build -o document_output" producing directories named "true";
 wenzelm parents: 
74144diff
changeset | 352 | case None if opt.typ == Options.Bool => this + (name, "true") | 
| 48370 | 353 |       case None => error("Missing value for option " + quote(name) + " : " + opt.typ.print)
 | 
| 354 | } | |
| 355 | } | |
| 356 | ||
| 48807 | 357 | def + (str: String): Options = | 
| 73712 | 358 |     str match {
 | 
| 73715 
bf51c23f3f99
clarified signature -- avoid odd warning about scala/bug#6675;
 wenzelm parents: 
73712diff
changeset | 359 | case Properties.Eq(a, b) => this + (a, b) | 
| 73712 | 360 | case _ => this + (str, None) | 
| 48370 | 361 | } | 
| 48456 
d8ff14f44a40
added ML version of stand-alone options, with XML.encode/decode operations (unidirectional from Scala to ML);
 wenzelm parents: 
48421diff
changeset | 362 | |
| 48807 | 363 | def ++ (specs: List[Options.Spec]): Options = | 
| 73359 | 364 |     specs.foldLeft(this) { case (x, (y, z)) => x + (y, z) }
 | 
| 48807 | 365 | |
| 48456 
d8ff14f44a40
added ML version of stand-alone options, with XML.encode/decode operations (unidirectional from Scala to ML);
 wenzelm parents: 
48421diff
changeset | 366 | |
| 49270 | 367 | /* sections */ | 
| 368 | ||
| 369 | def set_section(new_section: String): Options = | |
| 370 | new Options(options, new_section) | |
| 371 | ||
| 372 | def sections: List[(String, List[Options.Opt])] = | |
| 373 |     options.groupBy(_._2.section).toList.map({ case (a, opts) => (a, opts.toList.map(_._2)) })
 | |
| 374 | ||
| 375 | ||
| 48456 
d8ff14f44a40
added ML version of stand-alone options, with XML.encode/decode operations (unidirectional from Scala to ML);
 wenzelm parents: 
48421diff
changeset | 376 | /* encode */ | 
| 
d8ff14f44a40
added ML version of stand-alone options, with XML.encode/decode operations (unidirectional from Scala to ML);
 wenzelm parents: 
48421diff
changeset | 377 | |
| 75393 | 378 |   def encode: XML.Body = {
 | 
| 48860 | 379 | val opts = | 
| 56465 | 380 | for ((_, opt) <- options.toList; if !opt.unknown) | 
| 381 | yield (opt.pos, (opt.name, (opt.typ.print, opt.value))) | |
| 48860 | 382 | |
| 56465 | 383 |     import XML.Encode.{string => string_, _}
 | 
| 384 | list(pair(properties, pair(string_, pair(string_, string_))))(opts) | |
| 48456 
d8ff14f44a40
added ML version of stand-alone options, with XML.encode/decode operations (unidirectional from Scala to ML);
 wenzelm parents: 
48421diff
changeset | 385 | } | 
| 48807 | 386 | |
| 387 | ||
| 67845 | 388 | /* save preferences */ | 
| 48807 | 389 | |
| 75393 | 390 |   def save_prefs(file: Path = Options.PREFS): Unit = {
 | 
| 67845 | 391 | val defaults: Options = Options.init(prefs = "") | 
| 48807 | 392 | val changed = | 
| 393 |       (for {
 | |
| 48860 | 394 | (name, opt2) <- options.iterator | 
| 395 | opt1 = defaults.options.get(name) | |
| 60215 | 396 | if opt1.isEmpty || opt1.get.value != opt2.value | 
| 48860 | 397 | } yield (name, opt2.value, if (opt1.isEmpty) " (* unknown *)" else "")).toList | 
| 398 | ||
| 48807 | 399 | val prefs = | 
| 400 | changed.sortBy(_._1) | |
| 48860 | 401 |         .map({ case (x, y, z) => x + " = " + Outer_Syntax.quote_string(y) + z + "\n" }).mkString
 | 
| 48807 | 402 | |
| 72375 | 403 | Isabelle_System.make_directory(file.dir) | 
| 67845 | 404 | File.write_backup(file, "(* generated by Isabelle " + Date.now() + " *)\n\n" + prefs) | 
| 48807 | 405 | } | 
| 48365 
d88aefda01c4
basic support for stand-alone options with external string representation;
 wenzelm parents: diff
changeset | 406 | } | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 407 | |
| 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 408 | |
| 75393 | 409 | class Options_Variable(init_options: Options) {
 | 
| 65236 
4fa82bbb394e
afford early initialization of JEdit_Options, but it may lead to messy exception trace for malformed etc/preferences (see also 6eeaaefcea56);
 wenzelm parents: 
64186diff
changeset | 410 | private var options = init_options | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 411 | |
| 65236 
4fa82bbb394e
afford early initialization of JEdit_Options, but it may lead to messy exception trace for malformed etc/preferences (see also 6eeaaefcea56);
 wenzelm parents: 
64186diff
changeset | 412 |   def value: Options = synchronized { options }
 | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 413 | |
| 65236 
4fa82bbb394e
afford early initialization of JEdit_Options, but it may lead to messy exception trace for malformed etc/preferences (see also 6eeaaefcea56);
 wenzelm parents: 
64186diff
changeset | 414 |   private def upd(f: Options => Options): Unit = synchronized { options = f(options) }
 | 
| 
4fa82bbb394e
afford early initialization of JEdit_Options, but it may lead to messy exception trace for malformed etc/preferences (see also 6eeaaefcea56);
 wenzelm parents: 
64186diff
changeset | 415 | def += (name: String, x: String): Unit = upd(opts => opts + (name, x)) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 416 | |
| 75393 | 417 |   class Bool_Access {
 | 
| 62227 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 418 | def apply(name: String): Boolean = value.bool(name) | 
| 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 419 | def update(name: String, x: Boolean): Unit = upd(opts => opts.bool.update(name, x)) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 420 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 421 | val bool = new Bool_Access | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 422 | |
| 75393 | 423 |   class Int_Access {
 | 
| 62227 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 424 | def apply(name: String): Int = value.int(name) | 
| 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 425 | def update(name: String, x: Int): Unit = upd(opts => opts.int.update(name, x)) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 426 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 427 | val int = new Int_Access | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 428 | |
| 75393 | 429 |   class Real_Access {
 | 
| 62227 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 430 | def apply(name: String): Double = value.real(name) | 
| 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 431 | def update(name: String, x: Double): Unit = upd(opts => opts.real.update(name, x)) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 432 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 433 | val real = new Real_Access | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 434 | |
| 75393 | 435 |   class String_Access {
 | 
| 62227 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 436 | def apply(name: String): String = value.string(name) | 
| 
6eeaaefcea56
clarified errors: more explicit treatment of uninitialized state;
 wenzelm parents: 
61579diff
changeset | 437 | def update(name: String, x: String): Unit = upd(opts => opts.string.update(name, x)) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 438 | } | 
| 49954 
44658062d822
more explicit auxiliary classes to avoid warning "reflective access of structural type member method" of scala-2.10.0-RC1;
 wenzelm parents: 
49296diff
changeset | 439 | val string = new String_Access | 
| 50207 | 440 | |
| 69074 | 441 | def proper_string(name: String): Option[String] = | 
| 442 | Library.proper_string(string(name)) | |
| 443 | ||
| 69073 | 444 | def seconds(name: String): Time = value.seconds(name) | 
| 49245 
cb70157293c0
manage Isabelle/jEdit options as Isabelle/Scala options (with persistent preferences);
 wenzelm parents: 
48992diff
changeset | 445 | } |