| author | wenzelm | 
| Mon, 28 Feb 2022 13:02:40 +0100 | |
| changeset 75166 | 1f6da5d18340 | 
| parent 73361 | ef8c9b3d5355 | 
| child 75393 | 87ebf5a50283 | 
| permissions | -rw-r--r-- | 
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 1 | /* Title: Pure/PIDE/markup_tree.scala | 
| 36676 | 2 | Author: Fabian Immler, TU Munich | 
| 3 | Author: Makarius | |
| 4 | ||
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 5 | Markup trees over nested / non-overlapping text ranges. | 
| 36676 | 6 | */ | 
| 34393 | 7 | |
| 34871 
e596a0b71f3c
incorporate "proofdocument" part into main Isabelle/Pure.jar -- except for html_panel.scala, which depends on external library (Lobo/Cobra browser);
 wenzelm parents: 
34760diff
changeset | 8 | package isabelle | 
| 34393 | 9 | |
| 34701 
80b0add08eef
IsabelleSideKickParser: incorporate former MarkupNode.markup2default_node, observe stopped flag;
 wenzelm parents: 
34676diff
changeset | 10 | |
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 11 | import scala.collection.immutable.SortedMap | 
| 49614 | 12 | import scala.collection.mutable | 
| 49467 | 13 | import scala.annotation.tailrec | 
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 14 | |
| 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 15 | |
| 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 16 | object Markup_Tree | 
| 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 17 | {
 | 
| 50551 | 18 | /* construct trees */ | 
| 19 | ||
| 45456 | 20 | val empty: Markup_Tree = new Markup_Tree(Branches.empty) | 
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 21 | |
| 56743 | 22 | def merge(trees: List[Markup_Tree], range: Text.Range, elements: Markup.Elements): Markup_Tree = | 
| 73359 | 23 | trees.foldLeft(empty)(_.merge(_, range, elements)) | 
| 56299 
8201790fdeb9
more careful treatment of multiple command states (eval + prints): merge content that is actually required;
 wenzelm parents: 
55820diff
changeset | 24 | |
| 49467 | 25 | def merge_disjoint(trees: List[Markup_Tree]): Markup_Tree = | 
| 26 |     trees match {
 | |
| 27 | case Nil => empty | |
| 28 | case head :: tail => | |
| 29 | new Markup_Tree( | |
| 73359 | 30 |           tail.foldLeft(head.branches) {
 | 
| 49467 | 31 | case (branches, tree) => | 
| 73359 | 32 |               tree.branches.foldLeft(branches) {
 | 
| 49467 | 33 | case (bs, (r, entry)) => | 
| 73120 
c3589f2dff31
more informative errors: simplify diagnosis of spurious failures reported by users;
 wenzelm parents: 
72815diff
changeset | 34 | require(!bs.isDefinedAt(r), "cannot merge markup trees") | 
| 49467 | 35 | bs + (r -> entry) | 
| 36 | } | |
| 37 | }) | |
| 38 | } | |
| 39 | ||
| 50551 | 40 | |
| 41 | /* tree building blocks */ | |
| 42 | ||
| 45473 | 43 | object Entry | 
| 44 |   {
 | |
| 45 | def apply(markup: Text.Markup, subtree: Markup_Tree): Entry = | |
| 55652 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 46 | Entry(markup.range, List(markup.info), subtree) | 
| 45473 | 47 | } | 
| 48 | ||
| 45474 
f793dd5d84b2
index markup elements for more efficient cumulate/select operations;
 wenzelm parents: 
45473diff
changeset | 49 | sealed case class Entry( | 
| 
f793dd5d84b2
index markup elements for more efficient cumulate/select operations;
 wenzelm parents: 
45473diff
changeset | 50 | range: Text.Range, | 
| 
f793dd5d84b2
index markup elements for more efficient cumulate/select operations;
 wenzelm parents: 
45473diff
changeset | 51 | rev_markup: List[XML.Elem], | 
| 55652 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 52 | subtree: Markup_Tree) | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 53 |   {
 | 
| 50552 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 54 | def markup: List[XML.Elem] = rev_markup.reverse | 
| 45474 
f793dd5d84b2
index markup elements for more efficient cumulate/select operations;
 wenzelm parents: 
45473diff
changeset | 55 | |
| 56743 | 56 | def filter_markup(elements: Markup.Elements): List[XML.Elem] = | 
| 55645 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 57 |     {
 | 
| 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 58 | var result: List[XML.Elem] = Nil | 
| 60215 | 59 | for (elem <- rev_markup if elements(elem.name)) | 
| 55645 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 60 | result ::= elem | 
| 72815 | 61 | result | 
| 55645 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 62 | } | 
| 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 63 | |
| 55652 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 64 | def + (markup: Text.Markup): Entry = copy(rev_markup = markup.info :: rev_markup) | 
| 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 65 | def \ (markup: Text.Markup): Entry = copy(subtree = subtree + markup) | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 66 | } | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 67 | |
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 68 | object Branches | 
| 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 69 |   {
 | 
| 38578 | 70 | type T = SortedMap[Text.Range, Entry] | 
| 45456 | 71 | val empty: T = SortedMap.empty(Text.Range.Ordering) | 
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 72 | } | 
| 49466 | 73 | |
| 74 | ||
| 75 | /* XML representation */ | |
| 76 | ||
| 49650 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 77 | @tailrec private def strip_elems( | 
| 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 78 | elems: List[XML.Elem], body: XML.Body): (List[XML.Elem], XML.Body) = | 
| 49467 | 79 |     body match {
 | 
| 49650 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 80 | case List(XML.Wrapped_Elem(markup1, body1, body2)) => | 
| 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 81 | strip_elems(XML.Elem(markup1, body1) :: elems, body2) | 
| 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 82 | case List(XML.Elem(markup1, body1)) => | 
| 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 83 | strip_elems(XML.Elem(markup1, Nil) :: elems, body1) | 
| 
9fad6480300d
support for wrapped XML elements, which allows to preserve full markup tree information in to_XML/from_XML conversion;
 wenzelm parents: 
49614diff
changeset | 84 | case _ => (elems, body) | 
| 49467 | 85 | } | 
| 86 | ||
| 87 | private def make_trees(acc: (Int, List[Markup_Tree]), tree: XML.Tree): (Int, List[Markup_Tree]) = | |
| 88 |     {
 | |
| 89 | val (offset, markup_trees) = acc | |
| 90 | ||
| 91 |       strip_elems(Nil, List(tree)) match {
 | |
| 92 | case (Nil, body) => | |
| 93 | (offset + XML.text_length(body), markup_trees) | |
| 49466 | 94 | |
| 49469 | 95 | case (elems, body) => | 
| 73359 | 96 | val (end_offset, subtrees) = | 
| 73361 | 97 | body.foldLeft((offset, List.empty[Markup_Tree]))(make_trees) | 
| 50642 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 98 | if (offset == end_offset) acc | 
| 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 99 |           else {
 | 
| 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 100 | val range = Text.Range(offset, end_offset) | 
| 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 101 | val entry = Entry(range, elems, merge_disjoint(subtrees)) | 
| 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 102 | (end_offset, new Markup_Tree(Branches.empty, entry) :: markup_trees) | 
| 
aca12f646772
ignore markup elements over empty body, which are not well-defined within markup tree and fail to work with merge_disjoint (e.g. multiple inlined positions);
 wenzelm parents: 
50552diff
changeset | 103 | } | 
| 49466 | 104 | } | 
| 49467 | 105 | } | 
| 49466 | 106 | |
| 49467 | 107 | def from_XML(body: XML.Body): Markup_Tree = | 
| 73361 | 108 | merge_disjoint(body.foldLeft((0, List.empty[Markup_Tree]))(make_trees)._2) | 
| 38479 
e628da370072
more efficient Markup_Tree, based on branches sorted by quasi-order;
 wenzelm parents: 
38478diff
changeset | 109 | } | 
| 34554 
7dc6c231da40
abs. stops, markup nodes depend on doc-version;
 immler@in.tum.de parents: 
34517diff
changeset | 110 | |
| 34393 | 111 | |
| 51618 
a3577cd80c41
tuned signature -- avoid intrusion of slightly odd Swing structures into pure Markup_Tree;
 wenzelm parents: 
50642diff
changeset | 112 | final class Markup_Tree private(val branches: Markup_Tree.Branches.T) | 
| 34717 
3f32e08bbb6c
sidekick root data: set buffer length to avoid crash of initial caret move;
 wenzelm parents: 
34708diff
changeset | 113 | {
 | 
| 49417 | 114 | import Markup_Tree._ | 
| 115 | ||
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 116 | private def this(branches: Markup_Tree.Branches.T, entry: Markup_Tree.Entry) = | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 117 | this(branches + (entry.range -> entry)) | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 118 | |
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 119 | private def overlapping(range: Text.Range): Branches.T = | 
| 56311 | 120 | if (branches.isEmpty || | 
| 56313 | 121 | (range.contains(branches.firstKey.start) && branches.lastKey.stop <= range.stop)) | 
| 56311 | 122 | branches | 
| 123 |     else {
 | |
| 124 | val start = Text.Range(range.start) | |
| 125 | val stop = Text.Range(range.stop) | |
| 126 | val bs = branches.range(start, stop) | |
| 127 |       branches.get(stop) match {
 | |
| 128 | case Some(end) if range overlaps end.range => bs + (end.range -> end) | |
| 129 | case _ => bs | |
| 130 | } | |
| 45457 | 131 | } | 
| 132 | ||
| 56307 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 133 | def restrict(range: Text.Range): Markup_Tree = | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 134 | new Markup_Tree(overlapping(range)) | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 135 | |
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 136 | def is_empty: Boolean = branches.isEmpty | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 137 | |
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 138 | def + (new_markup: Text.Markup): Markup_Tree = | 
| 34703 | 139 |   {
 | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 140 | val new_range = new_markup.range | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 141 | |
| 38578 | 142 |     branches.get(new_range) match {
 | 
| 45473 | 143 | case None => new Markup_Tree(branches, Entry(new_markup, empty)) | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 144 | case Some(entry) => | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 145 | if (entry.range == new_range) | 
| 50552 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 146 | new Markup_Tree(branches, entry + new_markup) | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 147 | else if (entry.range.contains(new_range)) | 
| 50552 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 148 | new Markup_Tree(branches, entry \ new_markup) | 
| 38578 | 149 | else if (new_range.contains(branches.head._1) && new_range.contains(branches.last._1)) | 
| 45473 | 150 | new Markup_Tree(Branches.empty, Entry(new_markup, this)) | 
| 38482 
7b6ee937b75f
tuned Markup_Tree, using SortedMap more carefully;
 wenzelm parents: 
38479diff
changeset | 151 |         else {
 | 
| 45457 | 152 | val body = overlapping(new_range) | 
| 49607 
b610c0d52bfa
updated to consolidated SortedMap in scala-2.9.x;
 wenzelm parents: 
49469diff
changeset | 153 | if (body.forall(e => new_range.contains(e._1))) | 
| 
b610c0d52bfa
updated to consolidated SortedMap in scala-2.9.x;
 wenzelm parents: 
49469diff
changeset | 154 | new Markup_Tree(branches -- body.keys, Entry(new_markup, new Markup_Tree(body))) | 
| 49608 | 155 |           else {
 | 
| 58463 | 156 |             Output.warning("Ignored overlapping markup information: " + new_markup + "\n" +
 | 
| 71383 | 157 |               body.filter(e => !new_range.contains(e._1)).values.mkString("\n"))
 | 
| 38482 
7b6ee937b75f
tuned Markup_Tree, using SortedMap more carefully;
 wenzelm parents: 
38479diff
changeset | 158 | this | 
| 
7b6ee937b75f
tuned Markup_Tree, using SortedMap more carefully;
 wenzelm parents: 
38479diff
changeset | 159 | } | 
| 
7b6ee937b75f
tuned Markup_Tree, using SortedMap more carefully;
 wenzelm parents: 
38479diff
changeset | 160 | } | 
| 34703 | 161 | } | 
| 162 | } | |
| 163 | ||
| 56743 | 164 | def merge(other: Markup_Tree, root_range: Text.Range, elements: Markup.Elements): Markup_Tree = | 
| 49614 | 165 |   {
 | 
| 56301 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 166 | def merge_trees(tree1: Markup_Tree, tree2: Markup_Tree): Markup_Tree = | 
| 73359 | 167 |       tree2.branches.foldLeft(tree1) {
 | 
| 168 | case (tree, (range, entry)) => | |
| 169 | if (!range.overlaps(root_range)) tree | |
| 170 |           else {
 | |
| 171 |             entry.filter_markup(elements).foldLeft(merge_trees(tree, entry.subtree)) {
 | |
| 172 | case (t, elem) => t + Text.Info(range, elem) | |
| 173 | } | |
| 174 | } | |
| 175 | } | |
| 49614 | 176 | |
| 56307 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 177 | if (this eq other) this | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 178 |     else {
 | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 179 | val tree1 = this.restrict(root_range) | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 180 | val tree2 = other.restrict(root_range) | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 181 | if (tree1.is_empty) tree2 | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 182 | else merge_trees(tree1, tree2) | 
| 
2bdf8261677a
more frugal merge of markup trees: restrict to expected range before checking trivial cases, e.g. relevant for sporadic warnings (eval_exec) within big ML reports (print_exec);
 wenzelm parents: 
56302diff
changeset | 183 | } | 
| 49614 | 184 | } | 
| 185 | ||
| 56743 | 186 | def cumulate[A](root_range: Text.Range, root_info: A, elements: Markup.Elements, | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 187 | result: (A, Text.Markup) => Option[A]): List[Text.Info[A]] = | 
| 45459 | 188 |   {
 | 
| 46178 
1c5c88f6feb5
clarified Isabelle_Rendering vs. physical painting;
 wenzelm parents: 
46165diff
changeset | 189 | def results(x: A, entry: Entry): Option[A] = | 
| 50552 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 190 |     {
 | 
| 52889 
ea3338812e67
more tight interface for markup cumulate/select: avoid duplicate application, allow to defer decision about definedness;
 wenzelm parents: 
52642diff
changeset | 191 | var y = x | 
| 
ea3338812e67
more tight interface for markup cumulate/select: avoid duplicate application, allow to defer decision about definedness;
 wenzelm parents: 
52642diff
changeset | 192 | var changed = false | 
| 
ea3338812e67
more tight interface for markup cumulate/select: avoid duplicate application, allow to defer decision about definedness;
 wenzelm parents: 
52642diff
changeset | 193 |       for {
 | 
| 55645 
561754277494
tuned -- remaining rev_markup is rather short after filter;
 wenzelm parents: 
55622diff
changeset | 194 | elem <- entry.filter_markup(elements) | 
| 55620 | 195 | y1 <- result(y, Text.Info(entry.range, elem)) | 
| 52889 
ea3338812e67
more tight interface for markup cumulate/select: avoid duplicate application, allow to defer decision about definedness;
 wenzelm parents: 
52642diff
changeset | 196 |       } { y = y1; changed = true }
 | 
| 50552 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 197 | if (changed) Some(y) else None | 
| 
2b7fd8c9c4ac
maintain subtree_elements for improved performance of cumulate operator;
 wenzelm parents: 
50551diff
changeset | 198 | } | 
| 45467 | 199 | |
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 200 | def traverse( | 
| 45459 | 201 | last: Text.Offset, | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 202 | stack: List[(Text.Info[A], List[(Text.Range, Entry)])]): List[Text.Info[A]] = | 
| 45459 | 203 |     {
 | 
| 204 |       stack match {
 | |
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 205 | case (parent, (range, entry) :: more) :: rest => | 
| 45467 | 206 | val subrange = range.restrict(root_range) | 
| 55652 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 207 | val subtree = entry.subtree.overlapping(subrange).toList | 
| 45459 | 208 | val start = subrange.start | 
| 209 | ||
| 55652 
33ad12ef79ff
eliminated somewhat pointless elements index (see also f793dd5d84b2, 2b7fed8c9c4ac): less memory and more speed (avoid linear "exists" of 19dffae33cde);
 wenzelm parents: 
55645diff
changeset | 210 |           results(parent.info, entry) match {
 | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 211 | case Some(res) => | 
| 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 212 | val next = Text.Info(subrange, res) | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 213 | val nexts = traverse(start, (next, subtree) :: (parent, more) :: rest) | 
| 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 214 | if (last < start) parent.restrict(Text.Range(last, start)) :: nexts | 
| 45469 
25306d92f4ad
refined Markup_Tree implementation: stacked markup within each entry;
 wenzelm parents: 
45468diff
changeset | 215 | else nexts | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 216 | case None => traverse(last, (parent, subtree ::: more) :: rest) | 
| 45459 | 217 | } | 
| 218 | ||
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 219 | case (parent, Nil) :: rest => | 
| 45459 | 220 | val stop = parent.range.stop | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 221 | val nexts = traverse(stop, rest) | 
| 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 222 | if (last < stop) parent.restrict(Text.Range(last, stop)) :: nexts | 
| 45459 | 223 | else nexts | 
| 224 | ||
| 225 | case Nil => | |
| 45467 | 226 | val stop = root_range.stop | 
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 227 | if (last < stop) List(Text.Info(Text.Range(last, stop), root_info)) | 
| 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 228 | else Nil | 
| 45459 | 229 | } | 
| 230 | } | |
| 52900 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 231 | traverse(root_range.start, | 
| 
d29bf6db8a2d
more elementary list structures for markup tree traversal;
 wenzelm parents: 
52889diff
changeset | 232 | List((Text.Info(root_range, root_info), overlapping(root_range).toList))) | 
| 45459 | 233 | } | 
| 56301 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 234 | |
| 56743 | 235 | def to_XML(root_range: Text.Range, text: CharSequence, elements: Markup.Elements): XML.Body = | 
| 56301 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 236 |   {
 | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 237 | def make_text(start: Text.Offset, stop: Text.Offset): XML.Body = | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 238 | if (start == stop) Nil | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 239 | else List(XML.Text(text.subSequence(start, stop).toString)) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 240 | |
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 241 | def make_elems(rev_markups: List[XML.Elem], body: XML.Body): XML.Body = | 
| 73359 | 242 |       rev_markups.foldLeft(body) {
 | 
| 56301 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 243 | case (b, elem) => | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 244 | if (!elements(elem.name)) b | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 245 | else if (elem.body.isEmpty) List(XML.Elem(elem.markup, b)) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 246 | else List(XML.Wrapped_Elem(elem.markup, elem.body, b)) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 247 | } | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 248 | |
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 249 | def make_body(elem_range: Text.Range, elem_markup: List[XML.Elem], entries: Branches.T) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 250 | : XML.Body = | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 251 |     {
 | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 252 | val body = new mutable.ListBuffer[XML.Tree] | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 253 | var last = elem_range.start | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 254 |       for ((range, entry) <- entries) {
 | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 255 | val subrange = range.restrict(elem_range) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 256 | body ++= make_text(last, subrange.start) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 257 | body ++= make_body(subrange, entry.rev_markup, entry.subtree.overlapping(subrange)) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 258 | last = subrange.stop | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 259 | } | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 260 | body ++= make_text(last, elem_range.stop) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 261 | make_elems(elem_markup, body.toList) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 262 | } | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 263 | make_body(root_range, Nil, overlapping(root_range)) | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 264 | } | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 265 | |
| 57912 | 266 | override def toString: String = | 
| 56301 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 267 |     branches.toList.map(_._2) match {
 | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 268 | case Nil => "Empty" | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 269 |       case list => list.mkString("Tree(", ",", ")")
 | 
| 
1da7b4c33db9
more frugal merge of markup trees: filter wrt. subsequent query;
 wenzelm parents: 
56300diff
changeset | 270 | } | 
| 34717 
3f32e08bbb6c
sidekick root data: set buffer length to avoid crash of initial caret move;
 wenzelm parents: 
34708diff
changeset | 271 | } |