src/Pure/PIDE/rendering.scala
changeset 81395 d9f791f75b8b
parent 81304 228f4b9d1d67
child 81396 c3046c9b5fe9
equal deleted inserted replaced
81394:95b53559af80 81395:d9f791f75b8b
   602   def timing_threshold: Double = 0.0
   602   def timing_threshold: Double = 0.0
   603 
   603 
   604   private sealed case class Tooltip_Info(
   604   private sealed case class Tooltip_Info(
   605     range: Text.Range,
   605     range: Text.Range,
   606     timing: Timing = Timing.zero,
   606     timing: Timing = Timing.zero,
   607     messages: List[(Long, XML.Tree)] = Nil,
   607     messages: List[(Long, XML.Elem)] = Nil,
   608     rev_infos: List[(Boolean, Int, XML.Tree)] = Nil
   608     rev_infos: List[(Boolean, Int, XML.Elem)] = Nil
   609   ) {
   609   ) {
   610     def add_timing(t: Timing): Tooltip_Info = copy(timing = timing + t)
   610     def add_timing(t: Timing): Tooltip_Info = copy(timing = timing + t)
   611     def add_message(r0: Text.Range, serial: Long, tree: XML.Tree): Tooltip_Info = {
   611     def add_message(r0: Text.Range, serial: Long, msg: XML.Elem): Tooltip_Info = {
   612       val r = snapshot.convert(r0)
   612       val r = snapshot.convert(r0)
   613       if (range == r) copy(messages = (serial -> tree) :: messages)
   613       if (range == r) copy(messages = (serial -> msg) :: messages)
   614       else copy(range = r, messages = List(serial -> tree))
   614       else copy(range = r, messages = List(serial -> msg))
   615     }
   615     }
   616     def add_info(r0: Text.Range, tree: XML.Tree, important: Boolean = true, ord: Int = 0): Tooltip_Info = {
   616     def add_info(r0: Text.Range, info: XML.Elem,
       
   617       important: Boolean = true,
       
   618       ord: Int = 0
       
   619     ): Tooltip_Info = {
   617       val r = snapshot.convert(r0)
   620       val r = snapshot.convert(r0)
   618       val entry = (important, ord, tree)
   621       val entry = (important, ord, info)
   619       if (range == r) copy(rev_infos = entry :: rev_infos)
   622       if (range == r) copy(rev_infos = entry :: rev_infos)
   620       else copy (range = r, rev_infos = List(entry))
   623       else copy (range = r, rev_infos = List(entry))
   621     }
   624     }
   622 
   625     def add_info_text(r0: Text.Range, text: String, ord: Int = 0): Tooltip_Info =
   623     def timing_info(tree: XML.Tree): Option[XML.Tree] =
   626       add_info(r0, Pretty.string(text), ord = ord)
   624       tree match {
   627 
   625         case XML.Elem(Markup(Markup.TIMING, _), _) =>
   628     def timing_info(elem: XML.Elem): Option[XML.Elem] =
   626           if (timing.elapsed.seconds >= timing_threshold) Some(XML.Text(timing.message)) else None
   629       if (elem.markup.name == Markup.TIMING) {
   627         case _ => Some(tree)
   630         if (timing.elapsed.seconds >= timing_threshold) {
       
   631           Some(Pretty.string(timing.message))
       
   632         }
       
   633         else None
   628       }
   634       }
   629     def infos(important: Boolean = true): List[XML.Tree] =
   635       else Some(elem)
       
   636     def infos(important: Boolean = true): List[XML.Elem] =
   630       for {
   637       for {
   631         (is_important, _, tree) <- rev_infos.reverse.sortBy(_._2) if is_important == important
   638         (is_important, _, elem) <- rev_infos.reverse.sortBy(_._2) if is_important == important
   632         tree1 <- timing_info(tree)
   639         elem1 <- timing_info(elem)
   633       } yield tree1
   640       } yield elem1
   634   }
   641   }
   635 
   642 
   636   def perhaps_append_file(node_name: Document.Node.Name, name: String): String =
   643   def perhaps_append_file(node_name: Document.Node.Name, name: String): String =
   637     if (Path.is_valid(name)) session.resources.append_path(node_name.master_dir, Path.explode(name))
   644     if (Path.is_valid(name)) session.resources.append_path(node_name.master_dir, Path.explode(name))
   638     else name
   645     else name
   639 
   646 
   640   def tooltips(elements: Markup.Elements, range: Text.Range): Option[Text.Info[List[XML.Tree]]] = {
   647   def tooltips(elements: Markup.Elements, range: Text.Range): Option[Text.Info[List[XML.Elem]]] = {
   641     val results =
   648     val results =
   642       snapshot.cumulate[Tooltip_Info](range, Tooltip_Info(range), elements, command_states =>
   649       snapshot.cumulate[Tooltip_Info](range, Tooltip_Info(range), elements, command_states =>
   643         {
   650         {
   644           case (info, Text.Info(_, XML.Elem(Markup.Timing(t), _))) => Some(info.add_timing(t))
   651           case (info, Text.Info(_, XML.Elem(Markup.Timing(t), _))) => Some(info.add_timing(t))
   645 
   652 
   646           case (info, Text.Info(r0, msg @ XML.Elem(Markup(Markup.BAD, Markup.Serial(i)), body)))
   653           case (info, Text.Info(r0, msg @ XML.Elem(Markup(Markup.BAD, Markup.Serial(i)), body)))
   647           if body.nonEmpty => Some(info.add_message(r0, i, msg))
   654           if body.nonEmpty => Some(info.add_message(r0, i, msg))
   648 
   655 
   649           case (info, Text.Info(r0, XML.Elem(Markup(name, props), _)))
   656           case (info, Text.Info(r0, XML.Elem(Markup(name, props), _)))
   650           if Rendering.tooltip_message_elements(name) =>
   657           if Rendering.tooltip_message_elements(name) =>
   651             for ((i, tree) <- Command.State.get_result_proper(command_states, props))
   658             for ((i, msg) <- Command.State.get_result_proper(command_states, props))
   652             yield info.add_message(r0, i, tree)
   659             yield info.add_message(r0, i, msg)
   653 
   660 
   654           case (info, Text.Info(r0, XML.Elem(Markup.Entity(kind, name), _)))
   661           case (info, Text.Info(r0, XML.Elem(Markup.Entity(kind, name), _)))
   655           if kind != "" && kind != Markup.ML_DEF =>
   662           if kind != "" && kind != Markup.ML_DEF =>
   656             val kind1 = Word.implode(Word.explode('_', kind))
   663             val kind1 = Word.implode(Word.explode('_', kind))
   657             val txt1 =
   664             val txt1 =
   658               if (name == "") kind1
   665               if (name == "") kind1
   659               else if (kind1 == "") quote(name)
   666               else if (kind1 == "") quote(name)
   660               else kind1 + " " + quote(name)
   667               else kind1 + " " + quote(name)
   661             val info1 = info.add_info(r0, XML.Text(txt1), ord = 2)
   668             val info1 = info.add_info_text(r0, txt1, ord = 2)
   662             Some(if (kind == Markup.COMMAND) info1.add_info(r0, XML.elem(Markup.TIMING)) else info1)
   669             Some(if (kind == Markup.COMMAND) info1.add_info(r0, XML.elem(Markup.TIMING)) else info1)
   663 
   670 
   664           case (info, Text.Info(r0, XML.Elem(Markup.Path(name), _))) =>
   671           case (info, Text.Info(r0, XML.Elem(Markup.Path(name), _))) =>
   665             val file = perhaps_append_file(snapshot.node_name, name)
   672             val file = perhaps_append_file(snapshot.node_name, name)
   666             val text =
   673             val text =
   667               if (name == file) "file " + quote(file)
   674               if (name == file) "file " + quote(file)
   668               else "path " + quote(name) + "\nfile " + quote(file)
   675               else "path " + quote(name) + "\nfile " + quote(file)
   669             Some(info.add_info(r0, XML.Text(text)))
   676             Some(info.add_info_text(r0, text))
   670 
   677 
   671           case (info, Text.Info(r0, XML.Elem(Markup.Doc(name), _))) =>
   678           case (info, Text.Info(r0, XML.Elem(Markup.Doc(name), _))) =>
   672             val text = "doc " + quote(name)
   679             val text = "doc " + quote(name)
   673             Some(info.add_info(r0, XML.Text(text)))
   680             Some(info.add_info_text(r0, text))
   674 
   681 
   675           case (info, Text.Info(r0, XML.Elem(Markup.Url(name), _))) =>
   682           case (info, Text.Info(r0, XML.Elem(Markup.Url(name), _))) =>
   676             Some(info.add_info(r0, XML.Text("URL " + quote(name))))
   683             Some(info.add_info_text(r0, "URL " + quote(name)))
   677 
   684 
   678           case (info, Text.Info(r0, XML.Elem(Markup.Command_Span(span), _))) =>
   685           case (info, Text.Info(r0, XML.Elem(Markup.Command_Span(span), _))) =>
   679             Some(info.add_info(r0, XML.Text("command span " + quote(span.name))))
   686             Some(info.add_info_text(r0, "command span " + quote(span.name)))
   680 
   687 
   681           case (info, Text.Info(r0, XML.Elem(Markup(name, _), body)))
   688           case (info, Text.Info(r0, XML.Elem(Markup(name, _), body)))
   682           if name == Markup.SORTING || name == Markup.TYPING =>
   689           if name == Markup.SORTING || name == Markup.TYPING =>
   683             Some(info.add_info(r0, Pretty.block(XML.Text("::") :: Pretty.brk(1) :: body), ord = 3))
   690             Some(info.add_info(r0, Pretty.block(XML.Text("::") :: Pretty.brk(1) :: body), ord = 3))
   684 
   691 
   691 
   698 
   692           case (info, Text.Info(r0, Protocol.ML_Breakpoint(breakpoint))) =>
   699           case (info, Text.Info(r0, Protocol.ML_Breakpoint(breakpoint))) =>
   693               val text =
   700               val text =
   694                 if (session.debugger.breakpoint_state(breakpoint)) "breakpoint (enabled)"
   701                 if (session.debugger.breakpoint_state(breakpoint)) "breakpoint (enabled)"
   695                 else "breakpoint (disabled)"
   702                 else "breakpoint (disabled)"
   696               Some(info.add_info(r0, XML.Text(text)))
   703               Some(info.add_info_text(r0, text))
   697 
   704 
   698           case (info, Text.Info(r0, XML.Elem(Markup.Language(lang), _))) =>
   705           case (info, Text.Info(r0, XML.Elem(Markup.Language(lang), _))) =>
   699             Some(info.add_info(r0, XML.Text("language: " + lang.description)))
   706             Some(info.add_info_text(r0, "language: " + lang.description))
   700 
   707 
   701           case (info, Text.Info(r0, XML.Elem(Markup.Notation(kind, name), _))) =>
   708           case (info, Text.Info(r0, XML.Elem(Markup.Notation(kind, name), _))) =>
   702             val a = kind.nonEmpty
   709             val a = kind.nonEmpty
   703             val b = name.nonEmpty
   710             val b = name.nonEmpty
   704             val k = Word.implode(Word.explode('_', kind))
   711             val k = Word.implode(Word.explode('_', kind))
   705             val description =
   712             val description =
   706               if (!a && !b) "notation"
   713               if (!a && !b) "notation"
   707               else "notation: " + k + if_proper(a && b, " ") + if_proper(b, quote(name))
   714               else "notation: " + k + if_proper(a && b, " ") + if_proper(b, quote(name))
   708             Some(info.add_info(r0, XML.Text(description), ord = 1))
   715             Some(info.add_info_text(r0, description, ord = 1))
   709 
   716 
   710           case (info, Text.Info(r0, XML.Elem(Markup.Expression(kind), _))) =>
   717           case (info, Text.Info(r0, XML.Elem(Markup.Expression(kind), _))) =>
   711             val description =
   718             val description =
   712               if (kind.isEmpty) "expression"
   719               if (kind.isEmpty) "expression"
   713               else "expression: " + Word.implode(Word.explode('_', kind))
   720               else "expression: " + Word.implode(Word.explode('_', kind))
   714             Some(info.add_info(r0, XML.Text(description), ord = 1))
   721             Some(info.add_info_text(r0, description, ord = 1))
   715 
   722 
   716           case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) =>
   723           case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) =>
   717             Some(info.add_info(r0, XML.Text("Markdown: paragraph")))
   724             Some(info.add_info_text(r0, "Markdown: paragraph"))
   718           case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_ITEM, _), _))) =>
   725           case (info, Text.Info(r0, XML.Elem(Markup(Markup.MARKDOWN_ITEM, _), _))) =>
   719             Some(info.add_info(r0, XML.Text("Markdown: item")))
   726             Some(info.add_info_text(r0, "Markdown: item"))
   720           case (info, Text.Info(r0, XML.Elem(Markup.Markdown_List(kind), _))) =>
   727           case (info, Text.Info(r0, XML.Elem(Markup.Markdown_List(kind), _))) =>
   721             Some(info.add_info(r0, XML.Text("Markdown: " + kind)))
   728             Some(info.add_info_text(r0, "Markdown: " + kind))
   722 
   729 
   723           case (info, Text.Info(r0, XML.Elem(Markup(name, _), _))) =>
   730           case (info, Text.Info(r0, XML.Elem(Markup(name, _), _))) =>
   724             Rendering.tooltip_descriptions.get(name).map(desc => info.add_info(r0, XML.Text(desc)))
   731             Rendering.tooltip_descriptions.get(name).map(desc => info.add_info_text(r0, desc))
   725         }).map(_.info)
   732         }).map(_.info)
   726 
   733 
   727     if (results.isEmpty) None
   734     if (results.isEmpty) None
   728     else {
   735     else {
   729       val r = Text.Range(results.head.range.start, results.last.range.stop)
   736       val r = Text.Range(results.head.range.start, results.last.range.stop)
   730       val all_tips =
   737       val all_tips =
   731         results.flatMap(_.messages).foldLeft(SortedMap.empty[Long, XML.Tree])(_ + _)
   738         results.flatMap(_.messages).foldLeft(SortedMap.empty[Long, XML.Elem])(_ + _)
   732           .iterator.map(_._2).toList :::
   739           .iterator.map(_._2).toList :::
   733         results.flatMap(res => res.infos()) :::
   740         results.flatMap(res => res.infos()) :::
   734         results.flatMap(res => res.infos(important = false)).lastOption.toList
   741         results.flatMap(res => res.infos(important = false)).lastOption.toList
   735       if (all_tips.isEmpty) None else Some(Text.Info(r, all_tips))
   742       if (all_tips.isEmpty) None else Some(Text.Info(r, all_tips))
   736     }
   743     }