src/Pure/PIDE/markup_tree.scala
changeset 75393 87ebf5a50283
parent 73361 ef8c9b3d5355
child 75659 9bd92ac9328f
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
    11 import scala.collection.immutable.SortedMap
    11 import scala.collection.immutable.SortedMap
    12 import scala.collection.mutable
    12 import scala.collection.mutable
    13 import scala.annotation.tailrec
    13 import scala.annotation.tailrec
    14 
    14 
    15 
    15 
    16 object Markup_Tree
    16 object Markup_Tree {
    17 {
       
    18   /* construct trees */
    17   /* construct trees */
    19 
    18 
    20   val empty: Markup_Tree = new Markup_Tree(Branches.empty)
    19   val empty: Markup_Tree = new Markup_Tree(Branches.empty)
    21 
    20 
    22   def merge(trees: List[Markup_Tree], range: Text.Range, elements: Markup.Elements): Markup_Tree =
    21   def merge(trees: List[Markup_Tree], range: Text.Range, elements: Markup.Elements): Markup_Tree =
    38     }
    37     }
    39 
    38 
    40 
    39 
    41   /* tree building blocks */
    40   /* tree building blocks */
    42 
    41 
    43   object Entry
    42   object Entry {
    44   {
       
    45     def apply(markup: Text.Markup, subtree: Markup_Tree): Entry =
    43     def apply(markup: Text.Markup, subtree: Markup_Tree): Entry =
    46       Entry(markup.range, List(markup.info), subtree)
    44       Entry(markup.range, List(markup.info), subtree)
    47   }
    45   }
    48 
    46 
    49   sealed case class Entry(
    47   sealed case class Entry(
    50     range: Text.Range,
    48     range: Text.Range,
    51     rev_markup: List[XML.Elem],
    49     rev_markup: List[XML.Elem],
    52     subtree: Markup_Tree)
    50     subtree: Markup_Tree
    53   {
    51   ) {
    54     def markup: List[XML.Elem] = rev_markup.reverse
    52     def markup: List[XML.Elem] = rev_markup.reverse
    55 
    53 
    56     def filter_markup(elements: Markup.Elements): List[XML.Elem] =
    54     def filter_markup(elements: Markup.Elements): List[XML.Elem] = {
    57     {
       
    58       var result: List[XML.Elem] = Nil
    55       var result: List[XML.Elem] = Nil
    59       for (elem <- rev_markup if elements(elem.name))
    56       for (elem <- rev_markup if elements(elem.name))
    60         result ::= elem
    57         result ::= elem
    61       result
    58       result
    62     }
    59     }
    63 
    60 
    64     def + (markup: Text.Markup): Entry = copy(rev_markup = markup.info :: rev_markup)
    61     def + (markup: Text.Markup): Entry = copy(rev_markup = markup.info :: rev_markup)
    65     def \ (markup: Text.Markup): Entry = copy(subtree = subtree + markup)
    62     def \ (markup: Text.Markup): Entry = copy(subtree = subtree + markup)
    66   }
    63   }
    67 
    64 
    68   object Branches
    65   object Branches {
    69   {
       
    70     type T = SortedMap[Text.Range, Entry]
    66     type T = SortedMap[Text.Range, Entry]
    71     val empty: T = SortedMap.empty(Text.Range.Ordering)
    67     val empty: T = SortedMap.empty(Text.Range.Ordering)
    72   }
    68   }
    73 
    69 
    74 
    70 
    82       case List(XML.Elem(markup1, body1)) =>
    78       case List(XML.Elem(markup1, body1)) =>
    83         strip_elems(XML.Elem(markup1, Nil) :: elems, body1)
    79         strip_elems(XML.Elem(markup1, Nil) :: elems, body1)
    84       case _ => (elems, body)
    80       case _ => (elems, body)
    85     }
    81     }
    86 
    82 
    87   private def make_trees(acc: (Int, List[Markup_Tree]), tree: XML.Tree): (Int, List[Markup_Tree]) =
    83   private def make_trees(
    88     {
    84     acc: (Int, List[Markup_Tree]),
    89       val (offset, markup_trees) = acc
    85     tree: XML.Tree
    90 
    86   ): (Int, List[Markup_Tree]) = {
    91       strip_elems(Nil, List(tree)) match {
    87     val (offset, markup_trees) = acc
    92         case (Nil, body) =>
    88 
    93           (offset + XML.text_length(body), markup_trees)
    89     strip_elems(Nil, List(tree)) match {
    94 
    90       case (Nil, body) =>
    95         case (elems, body) =>
    91         (offset + XML.text_length(body), markup_trees)
    96           val (end_offset, subtrees) =
    92 
    97              body.foldLeft((offset, List.empty[Markup_Tree]))(make_trees)
    93       case (elems, body) =>
    98           if (offset == end_offset) acc
    94         val (end_offset, subtrees) =
    99           else {
    95            body.foldLeft((offset, List.empty[Markup_Tree]))(make_trees)
   100             val range = Text.Range(offset, end_offset)
    96         if (offset == end_offset) acc
   101             val entry = Entry(range, elems, merge_disjoint(subtrees))
    97         else {
   102             (end_offset, new Markup_Tree(Branches.empty, entry) :: markup_trees)
    98           val range = Text.Range(offset, end_offset)
   103           }
    99           val entry = Entry(range, elems, merge_disjoint(subtrees))
   104       }
   100           (end_offset, new Markup_Tree(Branches.empty, entry) :: markup_trees)
   105     }
   101         }
       
   102     }
       
   103   }
   106 
   104 
   107   def from_XML(body: XML.Body): Markup_Tree =
   105   def from_XML(body: XML.Body): Markup_Tree =
   108     merge_disjoint(body.foldLeft((0, List.empty[Markup_Tree]))(make_trees)._2)
   106     merge_disjoint(body.foldLeft((0, List.empty[Markup_Tree]))(make_trees)._2)
   109 }
   107 }
   110 
   108 
   111 
   109 
   112 final class Markup_Tree private(val branches: Markup_Tree.Branches.T)
   110 final class Markup_Tree private(val branches: Markup_Tree.Branches.T) {
   113 {
       
   114   import Markup_Tree._
   111   import Markup_Tree._
   115 
   112 
   116   private def this(branches: Markup_Tree.Branches.T, entry: Markup_Tree.Entry) =
   113   private def this(branches: Markup_Tree.Branches.T, entry: Markup_Tree.Entry) =
   117     this(branches + (entry.range -> entry))
   114     this(branches + (entry.range -> entry))
   118 
   115 
   133   def restrict(range: Text.Range): Markup_Tree =
   130   def restrict(range: Text.Range): Markup_Tree =
   134     new Markup_Tree(overlapping(range))
   131     new Markup_Tree(overlapping(range))
   135 
   132 
   136   def is_empty: Boolean = branches.isEmpty
   133   def is_empty: Boolean = branches.isEmpty
   137 
   134 
   138   def + (new_markup: Text.Markup): Markup_Tree =
   135   def + (new_markup: Text.Markup): Markup_Tree = {
   139   {
       
   140     val new_range = new_markup.range
   136     val new_range = new_markup.range
   141 
   137 
   142     branches.get(new_range) match {
   138     branches.get(new_range) match {
   143       case None => new Markup_Tree(branches, Entry(new_markup, empty))
   139       case None => new Markup_Tree(branches, Entry(new_markup, empty))
   144       case Some(entry) =>
   140       case Some(entry) =>
   159           }
   155           }
   160         }
   156         }
   161     }
   157     }
   162   }
   158   }
   163 
   159 
   164   def merge(other: Markup_Tree, root_range: Text.Range, elements: Markup.Elements): Markup_Tree =
   160   def merge(other: Markup_Tree, root_range: Text.Range, elements: Markup.Elements): Markup_Tree = {
   165   {
       
   166     def merge_trees(tree1: Markup_Tree, tree2: Markup_Tree): Markup_Tree =
   161     def merge_trees(tree1: Markup_Tree, tree2: Markup_Tree): Markup_Tree =
   167       tree2.branches.foldLeft(tree1) {
   162       tree2.branches.foldLeft(tree1) {
   168         case (tree, (range, entry)) =>
   163         case (tree, (range, entry)) =>
   169           if (!range.overlaps(root_range)) tree
   164           if (!range.overlaps(root_range)) tree
   170           else {
   165           else {
   181       if (tree1.is_empty) tree2
   176       if (tree1.is_empty) tree2
   182       else merge_trees(tree1, tree2)
   177       else merge_trees(tree1, tree2)
   183     }
   178     }
   184   }
   179   }
   185 
   180 
   186   def cumulate[A](root_range: Text.Range, root_info: A, elements: Markup.Elements,
   181   def cumulate[A](
   187     result: (A, Text.Markup) => Option[A]): List[Text.Info[A]] =
   182     root_range: Text.Range,
   188   {
   183     root_info: A,
   189     def results(x: A, entry: Entry): Option[A] =
   184     elements: Markup.Elements,
   190     {
   185     result: (A, Text.Markup) => Option[A]
       
   186   ): List[Text.Info[A]] = {
       
   187     def results(x: A, entry: Entry): Option[A] = {
   191       var y = x
   188       var y = x
   192       var changed = false
   189       var changed = false
   193       for {
   190       for {
   194         elem <- entry.filter_markup(elements)
   191         elem <- entry.filter_markup(elements)
   195         y1 <- result(y, Text.Info(entry.range, elem))
   192         y1 <- result(y, Text.Info(entry.range, elem))
   197       if (changed) Some(y) else None
   194       if (changed) Some(y) else None
   198     }
   195     }
   199 
   196 
   200     def traverse(
   197     def traverse(
   201       last: Text.Offset,
   198       last: Text.Offset,
   202       stack: List[(Text.Info[A], List[(Text.Range, Entry)])]): List[Text.Info[A]] =
   199       stack: List[(Text.Info[A], List[(Text.Range, Entry)])]
   203     {
   200     ): List[Text.Info[A]] = {
   204       stack match {
   201       stack match {
   205         case (parent, (range, entry) :: more) :: rest =>
   202         case (parent, (range, entry) :: more) :: rest =>
   206           val subrange = range.restrict(root_range)
   203           val subrange = range.restrict(root_range)
   207           val subtree = entry.subtree.overlapping(subrange).toList
   204           val subtree = entry.subtree.overlapping(subrange).toList
   208           val start = subrange.start
   205           val start = subrange.start
   230     }
   227     }
   231     traverse(root_range.start,
   228     traverse(root_range.start,
   232       List((Text.Info(root_range, root_info), overlapping(root_range).toList)))
   229       List((Text.Info(root_range, root_info), overlapping(root_range).toList)))
   233   }
   230   }
   234 
   231 
   235   def to_XML(root_range: Text.Range, text: CharSequence, elements: Markup.Elements): XML.Body =
   232   def to_XML(root_range: Text.Range, text: CharSequence, elements: Markup.Elements): XML.Body = {
   236   {
       
   237     def make_text(start: Text.Offset, stop: Text.Offset): XML.Body =
   233     def make_text(start: Text.Offset, stop: Text.Offset): XML.Body =
   238       if (start == stop) Nil
   234       if (start == stop) Nil
   239       else List(XML.Text(text.subSequence(start, stop).toString))
   235       else List(XML.Text(text.subSequence(start, stop).toString))
   240 
   236 
   241     def make_elems(rev_markups: List[XML.Elem], body: XML.Body): XML.Body =
   237     def make_elems(rev_markups: List[XML.Elem], body: XML.Body): XML.Body =
   244           if (!elements(elem.name)) b
   240           if (!elements(elem.name)) b
   245           else if (elem.body.isEmpty) List(XML.Elem(elem.markup, b))
   241           else if (elem.body.isEmpty) List(XML.Elem(elem.markup, b))
   246           else List(XML.Wrapped_Elem(elem.markup, elem.body, b))
   242           else List(XML.Wrapped_Elem(elem.markup, elem.body, b))
   247       }
   243       }
   248 
   244 
   249     def make_body(elem_range: Text.Range, elem_markup: List[XML.Elem], entries: Branches.T)
   245     def make_body(
   250       : XML.Body =
   246       elem_range: Text.Range,
   251     {
   247       elem_markup: List[XML.Elem],
       
   248       entries: Branches.T
       
   249     ) : XML.Body = {
   252       val body = new mutable.ListBuffer[XML.Tree]
   250       val body = new mutable.ListBuffer[XML.Tree]
   253       var last = elem_range.start
   251       var last = elem_range.start
   254       for ((range, entry) <- entries) {
   252       for ((range, entry) <- entries) {
   255         val subrange = range.restrict(elem_range)
   253         val subrange = range.restrict(elem_range)
   256         body ++= make_text(last, subrange.start)
   254         body ++= make_text(last, subrange.start)