isabelle-ml mode with separate token marker;
authorwenzelm
Sat, 15 Feb 2014 16:27:58 +0100
changeset 55500 cdbbaa3074a8
parent 55499 2581fbee5b95
child 55501 fdde1d62e1fb
isabelle-ml mode with separate token marker; clarified ML_Lex.gap_start: end-of-input counts as single newline;
src/Pure/ML/ml_lex.scala
src/Tools/jEdit/lib/Tools/jedit
src/Tools/jEdit/src/isabelle.scala
src/Tools/jEdit/src/modes/isabelle-ml.xml
src/Tools/jEdit/src/rendering.scala
src/Tools/jEdit/src/token_markup.scala
--- a/src/Pure/ML/ml_lex.scala	Sat Feb 15 14:52:51 2014 +0100
+++ b/src/Pure/ML/ml_lex.scala	Sat Feb 15 16:27:58 2014 +0100
@@ -32,6 +32,9 @@
   }
 
   sealed case class Token(val kind: Kind.Value, val source: String)
+  {
+    def is_operator: Boolean = kind == Kind.KEYWORD && !Symbol.is_ascii_identifier(source)
+  }
 
 
 
@@ -52,10 +55,11 @@
   {
     /* string material */
 
+    private val blanks = many(character(Symbol.is_ascii_blank))
     private val blanks1 = many1(character(Symbol.is_ascii_blank))
 
     private val gap = "\\" ~ blanks1 ~ "\\" ^^ { case x ~ y ~ z => x + y + z }
-    private val gap_start = "\\" ~ blanks1 ~ """\z""".r ^^ { case x ~ y ~ _ => x + y }
+    private val gap_start = "\\" ~ blanks ~ """\z""".r ^^ { case x ~ y ~ _ => x + y }
 
     private val escape =
       one(character("\"\\abtnvfr".contains(_))) |
@@ -96,7 +100,7 @@
           "\"" ~ ml_string_body ~ ("\"" | gap_start) ^^
             { case x ~ y ~ z => result(x + y + z, if (z == "\"") Scan.Finished else ML_String) }
         case ML_String =>
-          blanks1 ~ opt_term("\\" ~ ml_string_body ~ ("\"" | gap_start)) ^^
+          blanks ~ opt_term("\\" ~ ml_string_body ~ ("\"" | gap_start)) ^^
             { case x ~ Some(y ~ z ~ w) =>
                 result(x + y + z + w, if (w == "\"") Scan.Finished else ML_String)
               case x ~ None => result(x, ML_String) }
--- a/src/Tools/jEdit/lib/Tools/jedit	Sat Feb 15 14:52:51 2014 +0100
+++ b/src/Tools/jEdit/lib/Tools/jedit	Sat Feb 15 16:27:58 2014 +0100
@@ -55,6 +55,7 @@
   "src/Isabelle.props"
   "src/jEdit.props"
   "src/services.xml"
+  "src/modes/isabelle-ml.xml"
   "src/modes/isabelle-news.xml"
   "src/modes/isabelle-options.xml"
   "src/modes/isabelle-root.xml"
@@ -275,12 +276,19 @@
   cp -p -R -f src/modes/. dist/modes/.
 
   perl -i -e 'while (<>) {
-    if (m/NAME="javacc"/) {
+    if (m/FILE_NAME_GLOB="\*\.{sml,ml}"/) {
+      print qq,\t\t\t\tFILE_NAME_GLOB="*.sml" />\n,;
+    }
+    elsif (m/NAME="javacc"/) {
       print qq,<MODE NAME="isabelle" FILE="isabelle.xml" FILE_NAME_GLOB="*.thy"/>\n\n,;
+      print qq,<MODE NAME="isabelle-ml" FILE="isabelle-ml.xml" FILE_NAME_GLOB="*.ML"/>\n\n,;
       print qq,<MODE NAME="isabelle-news" FILE="isabelle-news.xml"/>\n\n,;
       print qq,<MODE NAME="isabelle-options" FILE="isabelle-options.xml"/>\n\n,;
-      print qq,<MODE NAME="isabelle-root" FILE="isabelle-root.xml" FILE_NAME_GLOB="ROOT"/>\n\n,; }
-    print; }' dist/modes/catalog
+      print qq,<MODE NAME="isabelle-root" FILE="isabelle-root.xml" FILE_NAME_GLOB="ROOT"/>\n\n,;
+      print;
+    }
+    else { print; }
+  }' dist/modes/catalog
 
   cd dist
   isabelle_jdk jar xf jedit.jar
--- a/src/Tools/jEdit/src/isabelle.scala	Sat Feb 15 14:52:51 2014 +0100
+++ b/src/Tools/jEdit/src/isabelle.scala	Sat Feb 15 16:27:58 2014 +0100
@@ -24,13 +24,14 @@
   val modes =
     List(
       "isabelle",         // theory source
+      "isabelle-ml",      // ML source
       "isabelle-markup",  // SideKick markup tree
       "isabelle-news",    // NEWS
       "isabelle-options", // etc/options
       "isabelle-output",  // pretty text area output
       "isabelle-root")    // session ROOT
 
-  private lazy val news_syntax = Outer_Syntax.init().no_tokens
+  private lazy val symbols_syntax = Outer_Syntax.init().no_tokens
 
   def mode_syntax(name: String): Option[Outer_Syntax] =
     name match {
@@ -39,7 +40,7 @@
         if (syntax == Outer_Syntax.empty) None else Some(syntax)
       case "isabelle-options" => Some(Options.options_syntax)
       case "isabelle-root" => Some(Build.root_syntax)
-      case "isabelle-news" => Some(news_syntax)
+      case "isabelle-ml" | "isabelle-news" => Some(symbols_syntax)
       case "isabelle-output" => None
       case _ => None
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/modes/isabelle-ml.xml	Sat Feb 15 16:27:58 2014 +0100
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MODE SYSTEM "xmode.dtd">
+
+<!-- Isabelle/ML mode -->
+<MODE>
+  <PROPS>
+    <PROPERTY NAME="commentStart" VALUE="(*"/>
+    <PROPERTY NAME="commentEnd" VALUE="*)"/>
+    <PROPERTY NAME="noWordSep" VALUE="_'.?"/>
+    <PROPERTY NAME="unalignedOpenBrackets" VALUE="{[(«‹⟨⌈⌊⦇⟦⦃" />
+    <PROPERTY NAME="unalignedCloseBrackets" VALUE="⦄⟧⦈⌋⌉⟩›»)]}" />
+    <PROPERTY NAME="tabSize" VALUE="2" />
+    <PROPERTY NAME="indentSize" VALUE="2" />
+  </PROPS>
+</MODE>
--- a/src/Tools/jEdit/src/rendering.scala	Sat Feb 15 14:52:51 2014 +0100
+++ b/src/Tools/jEdit/src/rendering.scala	Sat Feb 15 16:27:58 2014 +0100
@@ -110,6 +110,29 @@
     if (token.is_command) command_style(syntax.keyword_kind(token.content).getOrElse(""))
     else if (token.is_operator) JEditToken.OPERATOR
     else token_style(token.kind)
+
+  private val ml_token_style: Map[ML_Lex.Kind.Value, Byte] =
+  {
+    import JEditToken._
+    Map[ML_Lex.Kind.Value, Byte](
+      ML_Lex.Kind.KEYWORD -> KEYWORD1,
+      ML_Lex.Kind.IDENT -> NULL,
+      ML_Lex.Kind.LONG_IDENT -> NULL,
+      ML_Lex.Kind.TYPE_VAR -> NULL,
+      ML_Lex.Kind.WORD -> NULL,
+      ML_Lex.Kind.INT -> NULL,
+      ML_Lex.Kind.REAL -> NULL,
+      ML_Lex.Kind.CHAR -> LITERAL2,
+      ML_Lex.Kind.STRING -> LITERAL1,
+      ML_Lex.Kind.SPACE -> NULL,
+      ML_Lex.Kind.COMMENT -> COMMENT1,
+      ML_Lex.Kind.ERROR -> INVALID
+    ).withDefaultValue(NULL)
+  }
+
+  def ml_token_markup(token: ML_Lex.Token): Byte =
+    if (token.is_operator) JEditToken.OPERATOR
+    else ml_token_style(token.kind)
 }
 
 
--- a/src/Tools/jEdit/src/token_markup.scala	Sat Feb 15 14:52:51 2014 +0100
+++ b/src/Tools/jEdit/src/token_markup.scala	Sat Feb 15 16:27:58 2014 +0100
@@ -203,21 +203,29 @@
       val context1 =
       {
         val (styled_tokens, context1) =
-          Isabelle.mode_syntax(mode) match {
-            case Some(syntax) if syntax.has_tokens && line_ctxt.isDefined =>
-              val (tokens, ctxt1) = syntax.scan_context(line, line_ctxt.get)
-              val styled_tokens = tokens.map(tok => (Rendering.token_markup(syntax, tok), tok))
-              (styled_tokens, new Line_Context(Some(ctxt1)))
-            case _ =>
-              val token = Token(Token.Kind.UNPARSED, line.subSequence(0, line.count).toString)
-              (List((JEditToken.NULL, token)), new Line_Context(None))
+          if (mode == "isabelle-ml") {
+            val (tokens, ctxt1) = ML_Lex.tokenize_context(line, line_ctxt.get)
+            val styled_tokens = tokens.map(tok => (Rendering.ml_token_markup(tok), tok.source))
+            (styled_tokens, new Line_Context(Some(ctxt1)))
+          }
+          else {
+            Isabelle.mode_syntax(mode) match {
+              case Some(syntax) if syntax.has_tokens && line_ctxt.isDefined =>
+                val (tokens, ctxt1) = syntax.scan_context(line, line_ctxt.get)
+                val styled_tokens =
+                  tokens.map(tok => (Rendering.token_markup(syntax, tok), tok.source))
+                (styled_tokens, new Line_Context(Some(ctxt1)))
+              case _ =>
+                val styled_token = (JEditToken.NULL, line.subSequence(0, line.count).toString)
+                (List(styled_token), new Line_Context(None))
+            }
           }
 
         val extended = extended_styles(line)
 
         var offset = 0
         for ((style, token) <- styled_tokens) {
-          val length = token.source.length
+          val length = token.length
           val end_offset = offset + length
           if ((offset until end_offset) exists
               (i => extended.isDefinedAt(i) || line.charAt(i) == '\t')) {