src/Pure/System/options.scala
changeset 49270 e5d162d15867
parent 49247 ffd9ad9dc35b
child 49289 60424f123621
--- a/src/Pure/System/options.scala	Tue Sep 11 11:53:34 2012 +0200
+++ b/src/Pure/System/options.scala	Tue Sep 11 15:47:42 2012 +0200
@@ -30,25 +30,40 @@
   case object String extends Type
   case object Unknown extends Type
 
-  case class Opt(name: String, typ: Type, value: String, description: String)
+  case class Opt(name: String, typ: Type, value: String, description: String, section: String)
   {
     def print: String =
       "option " + name + " : " + typ.print + " = " +
         (if (typ == Options.String) quote(value) else value) +
       (if (description == "") "" else "\n  -- " + quote(description))
 
+    def title(strip: String): String =
+    {
+      val words = space_explode('_', name)
+      val words1 =
+        words match {
+          case word :: rest if word == strip => rest
+          case _ => words
+        }
+      words1.map(Library.capitalize).mkString(" ")
+    }
+
     def unknown: Boolean = typ == Unknown
   }
 
 
   /* parsing */
 
+  private val SECTION = "section"
   private val OPTION = "option"
   private val OPTIONS = Path.explode("etc/options")
   private val PREFS = Path.explode("$ISABELLE_HOME_USER/etc/preferences")
   private val PREFS_BACKUP = Path.explode("$ISABELLE_HOME_USER/etc/preferences~")
 
-  lazy val options_syntax = Outer_Syntax.init() + ":" + "=" + "--" + (OPTION, Keyword.THY_DECL)
+  lazy val options_syntax =
+    Outer_Syntax.init() + ":" + "=" + "--" +
+      (SECTION, Keyword.THY_HEADING2) + (OPTION, Keyword.THY_DECL)
+
   lazy val prefs_syntax = Outer_Syntax.init() + "="
 
   object Parser extends Parse.Parser
@@ -62,6 +77,8 @@
 
     val option_entry: Parser[Options => Options] =
     {
+      command(SECTION) ~! text ^^
+        { case _ ~ a => (options: Options) => options.set_section(a.trim) } |
       command(OPTION) ~! (option_name ~ keyword(":") ~ option_type ~
       keyword("=") ~ option_value ~ (keyword("--") ~! text ^^ { case _ ~ x => x } | success(""))) ^^
         { case _ ~ (a ~ _ ~ b ~ _ ~ c ~ d) => (options: Options) => options.declare(a, b, c, d) }
@@ -82,7 +99,7 @@
           case Success(result, _) => result
           case bad => error(bad.toString)
         }
-      try { (options /: ops) { case (opts, op) => op(opts) } }
+      try { (options.set_section("") /: ops) { case (opts, op) => op(opts) } }
       catch { case ERROR(msg) => error(msg + Position.here(file.position)) }
     }
   }
@@ -125,24 +142,14 @@
 }
 
 
-final class Options private(protected val options: Map[String, Options.Opt] = Map.empty)
+final class Options private(
+  protected val options: Map[String, Options.Opt] = Map.empty,
+  val section: String = "")
 {
   override def toString: String = options.iterator.mkString("Options (", ",", ")")
 
   def print: String = cat_lines(options.toList.sortBy(_._1).map(p => p._2.print))
 
-  def title(strip: String, name: String): String =
-  {
-    check_name(name)
-    val words = space_explode('_', name)
-    val words1 =
-      words match {
-        case word :: rest if word == strip => rest
-        case _ => words
-      }
-    words1.map(Library.capitalize).mkString(" ")
-  }
-
   def description(name: String): String = check_name(name).description
 
 
@@ -167,7 +174,7 @@
   private def put[A](name: String, typ: Options.Type, value: String): Options =
   {
     val opt = check_type(name, typ)
-    new Options(options + (name -> opt.copy(value = value)))
+    new Options(options + (name -> opt.copy(value = value)), section)
   }
 
   private def get[A](name: String, typ: Options.Type, parse: String => Option[A]): A =
@@ -239,21 +246,21 @@
             case "string" => Options.String
             case _ => error("Unknown type for option " + quote(name) + " : " + quote(typ_name))
           }
-        val opt = Options.Opt(name, typ, value, description)
-        (new Options(options + (name -> opt))).check_value(name)
+        val opt = Options.Opt(name, typ, value, description, section)
+        (new Options(options + (name -> opt), section)).check_value(name)
     }
   }
 
   def add_permissive(name: String, value: String): Options =
   {
     if (options.isDefinedAt(name)) this + (name, value)
-    else new Options(options + (name -> Options.Opt(name, Options.Unknown, value, "")))
+    else new Options(options + (name -> Options.Opt(name, Options.Unknown, value, "", "")), section)
   }
 
   def + (name: String, value: String): Options =
   {
     val opt = check_name(name)
-    (new Options(options + (name -> opt.copy(value = value)))).check_value(name)
+    (new Options(options + (name -> opt.copy(value = value)), section)).check_value(name)
   }
 
   def + (name: String, opt_value: Option[String]): Options =
@@ -278,6 +285,15 @@
     (this /: specs)({ case (x, (y, z)) => x + (y, z) })
 
 
+  /* sections */
+
+  def set_section(new_section: String): Options =
+    new Options(options, new_section)
+
+  def sections: List[(String, List[Options.Opt])] =
+    options.groupBy(_._2.section).toList.map({ case (a, opts) => (a, opts.toList.map(_._2)) })
+
+
   /* encode */
 
   def encode: XML.Body =