src/Tools/jEdit/src/isabelle_markup.scala
changeset 45669 06e259492f6b
parent 45668 0ea1c705eebb
parent 45667 546d78f0d81f
child 45670 b84170538043
child 45675 ac54a3abff81
child 45676 fa46fef06590
equal deleted inserted replaced
45668:0ea1c705eebb 45669:06e259492f6b
     1 /*  Title:      Tools/jEdit/src/isabelle_markup.scala
       
     2     Author:     Makarius
       
     3 
       
     4 Isabelle specific physical rendering and markup selection.
       
     5 */
       
     6 
       
     7 package isabelle.jedit
       
     8 
       
     9 
       
    10 import isabelle._
       
    11 
       
    12 import java.awt.Color
       
    13 
       
    14 import org.lobobrowser.util.gui.ColorFactory
       
    15 import org.gjt.sp.jedit.syntax.{Token => JEditToken}
       
    16 
       
    17 import scala.collection.immutable.SortedMap
       
    18 
       
    19 
       
    20 object Isabelle_Markup
       
    21 {
       
    22   /* physical rendering */
       
    23 
       
    24   // see http://www.w3schools.com/css/css_colornames.asp
       
    25 
       
    26   def get_color(s: String): Color = ColorFactory.getInstance.getColor(s)
       
    27 
       
    28   val outdated_color = new Color(238, 227, 227)
       
    29   val running_color = new Color(97, 0, 97)
       
    30   val running1_color = new Color(97, 0, 97, 100)
       
    31   val unprocessed_color = new Color(255, 160, 160)
       
    32   val unprocessed1_color = new Color(255, 160, 160, 50)
       
    33 
       
    34   val light_color = new Color(240, 240, 240)
       
    35   val regular_color = new Color(192, 192, 192)
       
    36   val warning_color = new Color(255, 140, 0)
       
    37   val error_color = new Color(178, 34, 34)
       
    38   val error1_color = new Color(178, 34, 34, 50)
       
    39   val bad_color = new Color(255, 106, 106, 100)
       
    40   val hilite_color = new Color(255, 204, 102, 100)
       
    41 
       
    42   val quoted_color = new Color(139, 139, 139, 25)
       
    43   val subexp_color = new Color(80, 80, 80, 50)
       
    44 
       
    45   val keyword1_color = get_color("#006699")
       
    46   val keyword2_color = get_color("#009966")
       
    47 
       
    48   class Icon(val priority: Int, val icon: javax.swing.Icon)
       
    49   {
       
    50     def >= (that: Icon): Boolean = this.priority >= that.priority
       
    51   }
       
    52   val warning_icon = new Icon(1, Isabelle.load_icon("16x16/status/dialog-information.png"))
       
    53   val legacy_icon = new Icon(2, Isabelle.load_icon("16x16/status/dialog-warning.png"))
       
    54   val error_icon = new Icon(3, Isabelle.load_icon("16x16/status/dialog-error.png"))
       
    55 
       
    56 
       
    57   /* command status */
       
    58 
       
    59   def status_color(snapshot: Document.Snapshot, command: Command): Option[Color] =
       
    60   {
       
    61     val state = snapshot.command_state(command)
       
    62     if (snapshot.is_outdated) Some(outdated_color)
       
    63     else
       
    64       Isar_Document.command_status(state.status) match {
       
    65         case Isar_Document.Forked(i) if i > 0 => Some(running1_color)
       
    66         case Isar_Document.Unprocessed => Some(unprocessed1_color)
       
    67         case _ => None
       
    68       }
       
    69   }
       
    70 
       
    71   def overview_color(snapshot: Document.Snapshot, command: Command): Option[Color] =
       
    72   {
       
    73     val state = snapshot.command_state(command)
       
    74     if (snapshot.is_outdated) None
       
    75     else
       
    76       Isar_Document.command_status(state.status) match {
       
    77         case Isar_Document.Forked(i) => if (i > 0) Some(running_color) else None
       
    78         case Isar_Document.Unprocessed => Some(unprocessed_color)
       
    79         case Isar_Document.Failed => Some(error_color)
       
    80         case Isar_Document.Finished =>
       
    81           if (state.results.exists(r => Isar_Document.is_error(r._2))) Some(error_color)
       
    82           else if (state.results.exists(r => Isar_Document.is_warning(r._2))) Some(warning_color)
       
    83           else None
       
    84       }
       
    85   }
       
    86 
       
    87 
       
    88   /* markup selectors */
       
    89 
       
    90   val message =
       
    91     Markup_Tree.Select[Color](
       
    92       {
       
    93         case Text.Info(_, XML.Elem(Markup(Markup.WRITELN, _), _)) => regular_color
       
    94         case Text.Info(_, XML.Elem(Markup(Markup.WARNING, _), _)) => warning_color
       
    95         case Text.Info(_, XML.Elem(Markup(Markup.ERROR, _), _)) => error_color
       
    96       },
       
    97       Some(Set(Markup.WRITELN, Markup.WARNING, Markup.ERROR)))
       
    98 
       
    99   val tooltip_message =
       
   100     Markup_Tree.Cumulate[SortedMap[Long, String]](SortedMap.empty,
       
   101       {
       
   102         case (msgs, Text.Info(_, msg @ XML.Elem(Markup(markup, Markup.Serial(serial)), _)))
       
   103         if markup == Markup.WRITELN || markup == Markup.WARNING || markup == Markup.ERROR =>
       
   104           msgs + (serial ->
       
   105             Pretty.string_of(List(msg), margin = Isabelle.Int_Property("tooltip-margin")))
       
   106       },
       
   107       Some(Set(Markup.WRITELN, Markup.WARNING, Markup.ERROR)))
       
   108 
       
   109   val gutter_message =
       
   110     Markup_Tree.Select[Icon](
       
   111       {
       
   112         case Text.Info(_, XML.Elem(Markup(Markup.WARNING, _), body)) =>
       
   113           body match {
       
   114             case List(XML.Elem(Markup(Markup.LEGACY, _), _)) => legacy_icon
       
   115             case _ => warning_icon
       
   116           }
       
   117         case Text.Info(_, XML.Elem(Markup(Markup.ERROR, _), _)) => error_icon
       
   118       },
       
   119       Some(Set(Markup.WARNING, Markup.ERROR)))
       
   120 
       
   121   val background1 =
       
   122     Markup_Tree.Select[Color](
       
   123       {
       
   124         case Text.Info(_, XML.Elem(Markup(Markup.BAD, _), _)) => bad_color
       
   125         case Text.Info(_, XML.Elem(Markup(Markup.HILITE, _), _)) => hilite_color
       
   126       },
       
   127       Some(Set(Markup.BAD, Markup.HILITE)))
       
   128 
       
   129   val background2 =
       
   130     Markup_Tree.Select[Color](
       
   131       {
       
   132         case Text.Info(_, XML.Elem(Markup(Markup.TOKEN_RANGE, _), _)) => light_color
       
   133       },
       
   134       Some(Set(Markup.TOKEN_RANGE)))
       
   135 
       
   136   val foreground =
       
   137     Markup_Tree.Select[Color](
       
   138       {
       
   139         case Text.Info(_, XML.Elem(Markup(Markup.STRING, _), _)) => quoted_color
       
   140         case Text.Info(_, XML.Elem(Markup(Markup.ALTSTRING, _), _)) => quoted_color
       
   141         case Text.Info(_, XML.Elem(Markup(Markup.VERBATIM, _), _)) => quoted_color
       
   142       },
       
   143       Some(Set(Markup.STRING, Markup.ALTSTRING, Markup.VERBATIM)))
       
   144 
       
   145   private val text_colors: Map[String, Color] =
       
   146     Map(
       
   147       Markup.STRING -> get_color("black"),
       
   148       Markup.ALTSTRING -> get_color("black"),
       
   149       Markup.VERBATIM -> get_color("black"),
       
   150       Markup.LITERAL -> keyword1_color,
       
   151       Markup.DELIMITER -> get_color("black"),
       
   152       Markup.TFREE -> get_color("#A020F0"),
       
   153       Markup.TVAR -> get_color("#A020F0"),
       
   154       Markup.FREE -> get_color("blue"),
       
   155       Markup.SKOLEM -> get_color("#D2691E"),
       
   156       Markup.BOUND -> get_color("green"),
       
   157       Markup.VAR -> get_color("#00009B"),
       
   158       Markup.INNER_STRING -> get_color("#D2691E"),
       
   159       Markup.INNER_COMMENT -> get_color("#8B0000"),
       
   160       Markup.DYNAMIC_FACT -> get_color("#7BA428"),
       
   161       Markup.ML_KEYWORD -> keyword1_color,
       
   162       Markup.ML_DELIMITER -> get_color("black"),
       
   163       Markup.ML_NUMERAL -> get_color("red"),
       
   164       Markup.ML_CHAR -> get_color("#D2691E"),
       
   165       Markup.ML_STRING -> get_color("#D2691E"),
       
   166       Markup.ML_COMMENT -> get_color("#8B0000"),
       
   167       Markup.ML_MALFORMED -> get_color("#FF6A6A"),
       
   168       Markup.ANTIQ -> get_color("blue"))
       
   169 
       
   170   val text_color =
       
   171     Markup_Tree.Select[Color](
       
   172       {
       
   173         case Text.Info(_, XML.Elem(Markup(m, _), _))
       
   174         if text_colors.isDefinedAt(m) => text_colors(m)
       
   175       },
       
   176       Some(Set() ++ text_colors.keys))
       
   177 
       
   178   private val tooltips: Map[String, String] =
       
   179     Map(
       
   180       Markup.SORT -> "sort",
       
   181       Markup.TYP -> "type",
       
   182       Markup.TERM -> "term",
       
   183       Markup.PROP -> "proposition",
       
   184       Markup.TOKEN_RANGE -> "inner syntax token",
       
   185       Markup.FREE -> "free variable",
       
   186       Markup.SKOLEM -> "skolem variable",
       
   187       Markup.BOUND -> "bound variable",
       
   188       Markup.VAR -> "schematic variable",
       
   189       Markup.TFREE -> "free type variable",
       
   190       Markup.TVAR -> "schematic type variable",
       
   191       Markup.ML_SOURCE -> "ML source",
       
   192       Markup.DOC_SOURCE -> "document source")
       
   193 
       
   194   private def string_of_typing(kind: String, body: XML.Body): String =
       
   195     Pretty.string_of(List(Pretty.block(XML.Text(kind) :: Pretty.Break(1) :: body)),
       
   196       margin = Isabelle.Int_Property("tooltip-margin"))
       
   197 
       
   198   val tooltip1 =
       
   199     Markup_Tree.Select[String](
       
   200       {
       
   201         case Text.Info(_, XML.Elem(Markup.Entity(kind, name), _)) => kind + " " + quote(name)
       
   202         case Text.Info(_, XML.Elem(Markup(Markup.ML_TYPING, _), body)) =>
       
   203           string_of_typing("ML:", body)
       
   204         case Text.Info(_, XML.Elem(Markup(name, _), _))
       
   205         if tooltips.isDefinedAt(name) => tooltips(name)
       
   206       },
       
   207       Some(Set(Markup.ENTITY, Markup.ML_TYPING) ++ tooltips.keys))
       
   208 
       
   209   val tooltip2 =
       
   210     Markup_Tree.Select[String](
       
   211       {
       
   212         case Text.Info(_, XML.Elem(Markup(Markup.TYPING, _), body)) => string_of_typing("::", body)
       
   213       },
       
   214       Some(Set(Markup.TYPING)))
       
   215 
       
   216   private val subexp_include =
       
   217     Set(Markup.SORT, Markup.TYP, Markup.TERM, Markup.PROP, Markup.ML_TYPING, Markup.TOKEN_RANGE,
       
   218       Markup.ENTITY, Markup.TYPING, Markup.FREE, Markup.SKOLEM, Markup.BOUND, Markup.VAR,
       
   219       Markup.TFREE, Markup.TVAR, Markup.ML_SOURCE, Markup.DOC_SOURCE)
       
   220 
       
   221   val subexp =
       
   222     Markup_Tree.Select[(Text.Range, Color)](
       
   223       {
       
   224         case Text.Info(range, XML.Elem(Markup(name, _), _)) if subexp_include(name) =>
       
   225           (range, subexp_color)
       
   226       },
       
   227       Some(subexp_include))
       
   228 
       
   229 
       
   230   /* token markup -- text styles */
       
   231 
       
   232   private val command_style: Map[String, Byte] =
       
   233   {
       
   234     import JEditToken._
       
   235     Map[String, Byte](
       
   236       Keyword.THY_END -> KEYWORD2,
       
   237       Keyword.THY_SCRIPT -> LABEL,
       
   238       Keyword.PRF_SCRIPT -> LABEL,
       
   239       Keyword.PRF_ASM -> KEYWORD3,
       
   240       Keyword.PRF_ASM_GOAL -> KEYWORD3
       
   241     ).withDefaultValue(KEYWORD1)
       
   242   }
       
   243 
       
   244   private val token_style: Map[Token.Kind.Value, Byte] =
       
   245   {
       
   246     import JEditToken._
       
   247     Map[Token.Kind.Value, Byte](
       
   248       Token.Kind.KEYWORD -> KEYWORD2,
       
   249       Token.Kind.IDENT -> NULL,
       
   250       Token.Kind.LONG_IDENT -> NULL,
       
   251       Token.Kind.SYM_IDENT -> NULL,
       
   252       Token.Kind.VAR -> NULL,
       
   253       Token.Kind.TYPE_IDENT -> NULL,
       
   254       Token.Kind.TYPE_VAR -> NULL,
       
   255       Token.Kind.NAT -> NULL,
       
   256       Token.Kind.FLOAT -> NULL,
       
   257       Token.Kind.STRING -> LITERAL1,
       
   258       Token.Kind.ALT_STRING -> LITERAL2,
       
   259       Token.Kind.VERBATIM -> COMMENT3,
       
   260       Token.Kind.SPACE -> NULL,
       
   261       Token.Kind.COMMENT -> COMMENT1,
       
   262       Token.Kind.UNPARSED -> INVALID
       
   263     ).withDefaultValue(NULL)
       
   264   }
       
   265 
       
   266   def token_markup(syntax: Outer_Syntax, token: Token): Byte =
       
   267     if (token.is_command) command_style(syntax.keyword_kind(token.content).getOrElse(""))
       
   268     else if (token.is_operator) JEditToken.OPERATOR
       
   269     else token_style(token.kind)
       
   270 }