more formal class Markup_Tree.Elements;
authorwenzelm
Sat, 15 Dec 2012 16:59:33 +0100
changeset 5156667d934cdc9b9
parent 51565 8c3c7f158861
child 51567 2b7fd8c9c4ac
more formal class Markup_Tree.Elements;
src/Pure/PIDE/markup_tree.scala
     1.1 --- a/src/Pure/PIDE/markup_tree.scala	Sat Dec 15 14:45:08 2012 +0100
     1.2 +++ b/src/Pure/PIDE/markup_tree.scala	Sat Dec 15 16:59:33 2012 +0100
     1.3 @@ -18,6 +18,8 @@
     1.4  
     1.5  object Markup_Tree
     1.6  {
     1.7 +  /* construct trees */
     1.8 +
     1.9    val empty: Markup_Tree = new Markup_Tree(Branches.empty)
    1.10  
    1.11    def merge_disjoint(trees: List[Markup_Tree]): Markup_Tree =
    1.12 @@ -35,24 +37,49 @@
    1.13            })
    1.14      }
    1.15  
    1.16 +
    1.17 +  /* tree building blocks */
    1.18 +
    1.19 +  object Elements
    1.20 +  {
    1.21 +    val empty = new Elements(Set.empty)
    1.22 +    def merge(es: Iterable[Elements]): Elements = (empty /: es.iterator)(_ ++ _)
    1.23 +  }
    1.24 +
    1.25 +  final class Elements private(private val rep: Set[String])
    1.26 +  {
    1.27 +    def contains(name: String): Boolean = rep.contains(name)
    1.28 +
    1.29 +    def + (name: String): Elements =
    1.30 +      if (contains(name)) this
    1.31 +      else new Elements(rep + name)
    1.32 +
    1.33 +    def + (elem: XML.Elem): Elements = this + elem.markup.name
    1.34 +    def ++ (elems: Iterable[XML.Elem]): Elements = (this /: elems.iterator)(_ + _)
    1.35 +
    1.36 +    def ++ (other: Elements): Elements =
    1.37 +      if (this eq other) this
    1.38 +      else if (rep.isEmpty) other
    1.39 +      else (this /: other.rep)(_ + _)
    1.40 +  }
    1.41 +
    1.42    object Entry
    1.43    {
    1.44      def apply(markup: Text.Markup, subtree: Markup_Tree): Entry =
    1.45 -      Entry(markup.range, List(markup.info), Set(markup.info.markup.name), subtree)
    1.46 +      Entry(markup.range, List(markup.info), Elements.empty + markup.info, subtree)
    1.47  
    1.48      def apply(range: Text.Range, rev_markups: List[XML.Elem], subtree: Markup_Tree): Entry =
    1.49 -      Entry(range, rev_markups, Set.empty ++ rev_markups.iterator.map(_.markup.name), subtree)
    1.50 +      Entry(range, rev_markups, Elements.empty ++ rev_markups, subtree)
    1.51    }
    1.52  
    1.53    sealed case class Entry(
    1.54      range: Text.Range,
    1.55      rev_markup: List[XML.Elem],
    1.56 -    elements: Set[String],
    1.57 +    elements: Elements,
    1.58      subtree: Markup_Tree)
    1.59    {
    1.60      def + (info: XML.Elem): Entry =
    1.61 -      if (elements(info.markup.name)) copy(rev_markup = info :: rev_markup)
    1.62 -      else copy(rev_markup = info :: rev_markup, elements = elements + info.markup.name)
    1.63 +      copy(rev_markup = info :: rev_markup, elements = elements + info)
    1.64  
    1.65      def markup: List[XML.Elem] = rev_markup.reverse
    1.66    }
    1.67 @@ -184,10 +211,17 @@
    1.68    def cumulate[A](root_range: Text.Range, root_info: A, result_elements: Option[Set[String]],
    1.69      result: PartialFunction[(A, Text.Markup), A]): Stream[Text.Info[A]] =
    1.70    {
    1.71 +    val notable: Elements => Boolean =
    1.72 +      result_elements match {
    1.73 +        case Some(res) => (elements: Elements) => res.exists(elements.contains)
    1.74 +        case None => (elements: Elements) => true
    1.75 +      }
    1.76 +
    1.77      def results(x: A, entry: Entry): Option[A] =
    1.78 -      if (result_elements match { case Some(es) => es.exists(entry.elements) case None => true }) {
    1.79 +      if (notable(entry.elements)) {
    1.80          val (y, changed) =
    1.81 -          ((x, false) /: entry.rev_markup)((res, info) =>  // FIXME proper order!?
    1.82 +          // FIXME proper cumulation order (including status markup) (!?)
    1.83 +          ((x, false) /: entry.rev_markup)((res, info) =>
    1.84              {
    1.85                val (y, changed) = res
    1.86                val arg = (y, Text.Info(entry.range, info))