src/Pure/System/options.scala
changeset 49270 e5d162d15867
parent 49247 ffd9ad9dc35b
child 49289 60424f123621
equal deleted inserted replaced
49269:7157af98ca55 49270:e5d162d15867
    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 =