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) |