Mercurial > projects > dwt2
comparison org.eclipse.text/src/org/eclipse/jface/text/projection/ProjectionMapping.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children | 5feec68b4556 |
comparison
equal
deleted
inserted
replaced
11:43904fec5dca | 12:bc29606a740c |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.jface.text.projection.ProjectionMapping; | |
14 | |
15 import org.eclipse.jface.text.projection.ChildDocumentManager; // packageimport | |
16 import org.eclipse.jface.text.projection.SegmentUpdater; // packageimport | |
17 import org.eclipse.jface.text.projection.Segment; // packageimport | |
18 import org.eclipse.jface.text.projection.ProjectionDocument; // packageimport | |
19 import org.eclipse.jface.text.projection.FragmentUpdater; // packageimport | |
20 import org.eclipse.jface.text.projection.ProjectionDocumentEvent; // packageimport | |
21 import org.eclipse.jface.text.projection.ChildDocument; // packageimport | |
22 import org.eclipse.jface.text.projection.IMinimalMapping; // packageimport | |
23 import org.eclipse.jface.text.projection.Fragment; // packageimport | |
24 import org.eclipse.jface.text.projection.ProjectionTextStore; // packageimport | |
25 import org.eclipse.jface.text.projection.ProjectionDocumentManager; // packageimport | |
26 | |
27 | |
28 import java.lang.all; | |
29 import java.util.Set; | |
30 | |
31 | |
32 import org.eclipse.core.runtime.Assert; | |
33 import org.eclipse.jface.text.BadLocationException; | |
34 import org.eclipse.jface.text.BadPositionCategoryException; | |
35 import org.eclipse.jface.text.IDocument; | |
36 import org.eclipse.jface.text.IDocumentInformationMapping; | |
37 import org.eclipse.jface.text.IDocumentInformationMappingExtension; | |
38 import org.eclipse.jface.text.IDocumentInformationMappingExtension2; | |
39 import org.eclipse.jface.text.IRegion; | |
40 import org.eclipse.jface.text.Position; | |
41 import org.eclipse.jface.text.Region; | |
42 | |
43 | |
44 /** | |
45 * Internal class. Do not use. Only public for testing purposes. | |
46 * <p> | |
47 * Implementation of {@link org.eclipse.jface.text.IDocumentInformationMapping} | |
48 * for the projection mapping between a master and a slave document. | |
49 * | |
50 * @since 3.0 | |
51 * @noinstantiate This class is not intended to be instantiated by clients. | |
52 * @noextend This class is not intended to be subclassed by clients. | |
53 */ | |
54 public class ProjectionMapping : IDocumentInformationMapping , IDocumentInformationMappingExtension, IDocumentInformationMappingExtension2, IMinimalMapping { | |
55 | |
56 private static const int LEFT= -1; | |
57 private static const int NONE= 0; | |
58 private static const int RIGHT= +1; | |
59 | |
60 /** The master document */ | |
61 private IDocument fMasterDocument; | |
62 /** The position category used to manage the projection fragments inside the master document */ | |
63 private String fFragmentsCategory; | |
64 /** The projection document */ | |
65 private IDocument fSlaveDocument; | |
66 /** The position category to manage the projection segments inside the slave document. */ | |
67 private String fSegmentsCategory; | |
68 /** Cached segments */ | |
69 private Position[] fCachedSegments; | |
70 /** Cached fragments */ | |
71 private Position[] fCachedFragments; | |
72 | |
73 /** | |
74 * Creates a new mapping between the given parent document and the given projection document. | |
75 * | |
76 * @param masterDocument the master document | |
77 * @param fragmentsCategory the position category of the parent document used to manage the projected regions | |
78 * @param slaveDocument the slave document | |
79 * @param segmentsCategory the position category of the projection document used to manage the fragments | |
80 */ | |
81 public this(IDocument masterDocument, String fragmentsCategory, IDocument slaveDocument, String segmentsCategory) { | |
82 fMasterDocument= masterDocument; | |
83 fFragmentsCategory= fragmentsCategory; | |
84 fSlaveDocument= slaveDocument; | |
85 fSegmentsCategory= segmentsCategory; | |
86 } | |
87 | |
88 /** | |
89 * Notifies this projection mapping that there was a projection change. | |
90 */ | |
91 public void projectionChanged() { | |
92 fCachedSegments= null; | |
93 fCachedFragments= null; | |
94 } | |
95 | |
96 private Position[] getSegments() { | |
97 if (fCachedSegments is null) { | |
98 try { | |
99 fCachedSegments= fSlaveDocument.getPositions(fSegmentsCategory); | |
100 } catch (BadPositionCategoryException e) { | |
101 return new Position[0]; | |
102 } | |
103 } | |
104 return fCachedSegments; | |
105 } | |
106 | |
107 private Position[] getFragments() { | |
108 if (fCachedFragments is null) { | |
109 try { | |
110 fCachedFragments= fMasterDocument.getPositions(fFragmentsCategory); | |
111 } catch (BadPositionCategoryException e) { | |
112 return new Position[0]; | |
113 } | |
114 } | |
115 return fCachedFragments; | |
116 } | |
117 | |
118 private int findSegmentIndex(int offset) { | |
119 Position[] segments= getSegments(); | |
120 if (segments.length is 0) { | |
121 if (offset > 0) | |
122 throw new BadLocationException(); | |
123 return -1; | |
124 } | |
125 | |
126 try { | |
127 int index= fSlaveDocument.computeIndexInCategory(fSegmentsCategory, offset); | |
128 if (index is segments.length && offset > exclusiveEnd(segments[index-1])) | |
129 throw new BadLocationException(); | |
130 | |
131 if (index < segments.length && offset is segments[index].offset) | |
132 return index; | |
133 | |
134 if (index > 0) | |
135 index--; | |
136 | |
137 return index; | |
138 | |
139 } catch (BadPositionCategoryException e) { | |
140 throw new IllegalStateException(); | |
141 } | |
142 } | |
143 | |
144 private Segment findSegment(int offset) { | |
145 | |
146 checkImageOffset(offset); | |
147 | |
148 int index= findSegmentIndex(offset); | |
149 if (index is -1) { | |
150 | |
151 Segment s= new Segment(0, 0); | |
152 Fragment f= new Fragment(0, 0); | |
153 s.fragment= f; | |
154 f.segment= s; | |
155 return s; | |
156 } | |
157 | |
158 Position[] segments= getSegments(); | |
159 return cast(Segment) segments[index]; | |
160 } | |
161 | |
162 /** | |
163 * Computes the fragment index given an origin offset. Returns the index of | |
164 * the fragment that contains <code>offset</code>, or <code>-1</code> | |
165 * if no fragment contains <code>offset</code>. | |
166 * <p> | |
167 * If <code>extensionDirection</code> is set to <code>RIGHT</code> or | |
168 * <code>LEFT</code>, the next fragment in that direction is returned if | |
169 * there is no fragment containing <code>offset</code>. Note that if | |
170 * <code>offset</code> occurs before any fragment and | |
171 * <code>extensionDirection</code> is <code>LEFT</code>, | |
172 * <code>-1</code> is also returned. The same applies for an offset after | |
173 * the last fragment and <code>extensionDirection</code> set to | |
174 * <code>RIGHT</code>. | |
175 * </p> | |
176 * | |
177 * @param offset an origin offset | |
178 * @param extensionDirection the direction in which to extend the search, or | |
179 * <code>NONE</code> | |
180 * @return the index of the fragment containing <code>offset</code>, or | |
181 * <code>-1</code> | |
182 * @throws BadLocationException if the index is not valid on the master | |
183 * document | |
184 */ | |
185 private int findFragmentIndex(int offset, int extensionDirection) { | |
186 try { | |
187 | |
188 Position[] fragments= getFragments(); | |
189 if (fragments.length is 0) | |
190 return -1; | |
191 | |
192 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offset); | |
193 | |
194 if (index < fragments.length && offset is fragments[index].offset) | |
195 return index; | |
196 | |
197 if (0 < index && index <= fragments.length && fragments[index - 1].includes(offset)) | |
198 return index - 1; | |
199 | |
200 switch (extensionDirection) { | |
201 case LEFT: | |
202 return index - 1; | |
203 case RIGHT: | |
204 if (index < fragments.length) | |
205 return index; | |
206 default: | |
207 } | |
208 | |
209 return -1; | |
210 | |
211 } catch (BadPositionCategoryException e) { | |
212 throw new IllegalStateException(); | |
213 } | |
214 } | |
215 | |
216 private Fragment findFragment(int offset) { | |
217 checkOriginOffset(offset); | |
218 | |
219 int index= findFragmentIndex(offset, NONE); | |
220 Position[] fragments= getFragments(); | |
221 if (index is -1) { | |
222 if (fragments.length > 0) { | |
223 Fragment last= cast(Fragment) fragments[fragments.length - 1]; | |
224 if (exclusiveEnd(last) is offset) | |
225 return last; | |
226 } | |
227 return null; | |
228 } | |
229 return cast(Fragment) fragments[index]; | |
230 } | |
231 | |
232 /** | |
233 * Returns the image region for <code>originRegion</code>. | |
234 * | |
235 * @param originRegion the region to get the image for | |
236 * @param exact if <code>true</code>, the begin and end offsets of | |
237 * <code>originRegion</code> must be projected, otherwise | |
238 * <code>null</code> is returned. If <code>false</code>, the | |
239 * begin and end range that is not visible is simply clipped. | |
240 * @param takeClosestImage if <code>false</code>, <code>null</code> is | |
241 * returned if <code>originRegion</code> is completely invisible. | |
242 * If <code>true</code>, the zero-length region is returned that | |
243 * "covers" the hidden origin region | |
244 * @return the image region of <code>originRegion</code> | |
245 * @throws BadLocationException if the region is not a valid origin region | |
246 */ | |
247 private IRegion toImageRegion(IRegion originRegion, bool exact, bool takeClosestImage) { | |
248 if (originRegion.getLength() is 0 && !takeClosestImage) { | |
249 int imageOffset= toImageOffset(originRegion.getOffset()); | |
250 return imageOffset is -1 ? null : new Region(imageOffset, 0); | |
251 } | |
252 | |
253 Fragment[] fragments= findFragments(originRegion, exact, takeClosestImage); | |
254 if (fragments is null) { | |
255 if (takeClosestImage) { | |
256 // originRegion may before the first or after the last fragment | |
257 Position[] allFragments= getFragments(); | |
258 if (allFragments.length > 0) { | |
259 // before the first | |
260 if (exclusiveEnd(originRegion) <= allFragments[0].getOffset()) | |
261 return new Region(0, 0); | |
262 // after last | |
263 Position last= allFragments[allFragments.length - 1]; | |
264 if (originRegion.getOffset() >= exclusiveEnd(last)) | |
265 return new Region(exclusiveEnd((cast(Fragment) last).segment), 0); | |
266 } | |
267 return new Region(0, 0); | |
268 } | |
269 return null; | |
270 } | |
271 | |
272 int imageOffset, exclusiveImageEndOffset; | |
273 | |
274 // translate start offset | |
275 int relative= originRegion.getOffset() - fragments[0].getOffset(); | |
276 if (relative < 0) { | |
277 Assert.isTrue(!exact); | |
278 relative= 0; | |
279 } | |
280 imageOffset= fragments[0].segment.getOffset() + relative; | |
281 | |
282 // translate end offset | |
283 relative= exclusiveEnd(originRegion) - fragments[1].getOffset(); | |
284 if (relative > fragments[1].getLength()) { | |
285 Assert.isTrue(!exact); | |
286 relative= fragments[1].getLength(); | |
287 } | |
288 exclusiveImageEndOffset= fragments[1].segment.getOffset() + relative; | |
289 | |
290 return new Region(imageOffset, exclusiveImageEndOffset - imageOffset); | |
291 } | |
292 | |
293 /** | |
294 * Returns the two fragments containing the begin and end offsets of | |
295 * <code>originRegion</code>. | |
296 * | |
297 * @param originRegion the region to get the fragments for | |
298 * @param exact if <code>true</code>, only the fragments that contain the | |
299 * begin and end offsets are returned; if <code>false</code>, the | |
300 * first fragment after the begin offset and the last fragment before | |
301 * the end offset are returned if the offsets are not projected | |
302 * @param takeClosestImage if <code>true</code>, the method will return | |
303 * fragments also if <code>originRegion</code> completely lies in | |
304 * an unprojected region. | |
305 * @return the two fragments containing the begin and end offset of | |
306 * <code>originRegion</code>, or <code>null</code> if these do | |
307 * not exist | |
308 * @throws BadLocationException if the region is not a valid origin region | |
309 */ | |
310 private Fragment[] findFragments(IRegion originRegion, bool exact, bool takeClosestImage) { | |
311 Position[] fragments= getFragments(); | |
312 if (fragments.length is 0) | |
313 return null; | |
314 | |
315 checkOriginRegion(originRegion); | |
316 | |
317 int startFragmentIdx= findFragmentIndex(originRegion.getOffset(), exact ? NONE : RIGHT); | |
318 if (startFragmentIdx is -1) | |
319 return null; | |
320 | |
321 int endFragmentIdx= findFragmentIndex(inclusiveEnd(originRegion), exact ? NONE : LEFT); | |
322 if (!takeClosestImage && startFragmentIdx > endFragmentIdx || endFragmentIdx is -1) | |
323 return null; | |
324 | |
325 Fragment[] result= [cast(Fragment) fragments[startFragmentIdx], cast(Fragment) fragments[endFragmentIdx]]; | |
326 return result; | |
327 } | |
328 | |
329 private IRegion createOriginStartRegion(Segment image, int offsetShift) { | |
330 return new Region(image.fragment.getOffset() + offsetShift, image.fragment.getLength() - offsetShift); | |
331 } | |
332 | |
333 private IRegion createOriginRegion(Segment image) { | |
334 return new Region(image.fragment.getOffset(), image.fragment.getLength()); | |
335 } | |
336 | |
337 private IRegion createOriginEndRegion(Segment image, int lengthReduction) { | |
338 return new Region(image.fragment.getOffset(), image.fragment.getLength() - lengthReduction); | |
339 } | |
340 | |
341 private IRegion createImageStartRegion(Fragment origin, int offsetShift) { | |
342 int shift= offsetShift > 0 ? offsetShift : 0; | |
343 return new Region(origin.segment.getOffset() + shift, origin.segment.getLength() - shift); | |
344 } | |
345 | |
346 private IRegion createImageRegion(Fragment origin) { | |
347 return new Region(origin.segment.getOffset(), origin.segment.getLength()); | |
348 } | |
349 | |
350 private IRegion createImageEndRegion(Fragment origin, int lengthReduction) { | |
351 int reduction= lengthReduction > 0 ? lengthReduction : 0; | |
352 return new Region(origin.segment.getOffset(), origin.segment.getLength() - reduction); | |
353 } | |
354 | |
355 private IRegion createOriginStartRegion(Fragment origin, int offsetShift) { | |
356 int shift= offsetShift > 0 ? offsetShift : 0; | |
357 return new Region(origin.getOffset() + shift, origin.getLength() - shift); | |
358 } | |
359 | |
360 private IRegion createOriginRegion(Fragment origin) { | |
361 return new Region(origin.getOffset(), origin.getLength()); | |
362 } | |
363 | |
364 private IRegion createOriginEndRegion(Fragment origin, int lengthReduction) { | |
365 int reduction= lengthReduction > 0 ? lengthReduction : 0; | |
366 return new Region(origin.getOffset(), origin.getLength() - reduction); | |
367 } | |
368 | |
369 private IRegion getIntersectingRegion(IRegion left, IRegion right) { | |
370 int offset= Math.max(left.getOffset(), right.getOffset()); | |
371 int exclusiveEndOffset= Math.min(exclusiveEnd(left), exclusiveEnd(right)); | |
372 if (exclusiveEndOffset < offset) | |
373 return null; | |
374 return new Region(offset, exclusiveEndOffset - offset); | |
375 } | |
376 | |
377 /* | |
378 * @see org.eclipse.jface.text.IDocumentInformationMapping#getCoverage() | |
379 */ | |
380 public IRegion getCoverage() { | |
381 Position[] fragments= getFragments(); | |
382 if (fragments !is null && fragments.length > 0) { | |
383 Position first=fragments[0]; | |
384 Position last= fragments[fragments.length -1]; | |
385 return new Region(first.offset, exclusiveEnd(last) - first.offset); | |
386 } | |
387 return new Region(0, 0); | |
388 } | |
389 | |
390 /* | |
391 * @see org.eclipse.jface.text.IDocumentInformationMapping#toOriginOffset(int) | |
392 */ | |
393 public int toOriginOffset(int imageOffset) { | |
394 Segment segment= findSegment(imageOffset); | |
395 int relative= imageOffset - segment.offset; | |
396 return segment.fragment.offset + relative; | |
397 } | |
398 | |
399 /* | |
400 * @see org.eclipse.jface.text.IDocumentInformationMapping#toOriginRegion(org.eclipse.jface.text.IRegion) | |
401 */ | |
402 public IRegion toOriginRegion(IRegion imageRegion) { | |
403 int imageOffset= imageRegion.getOffset(); | |
404 int imageLength= imageRegion.getLength(); | |
405 | |
406 if (imageLength is 0) { | |
407 if (imageOffset is 0) { | |
408 Position[] fragments= getFragments(); | |
409 if (fragments.length is 0 || (fragments.length is 1 && fragments[0].getOffset() is 0 && fragments[0].getLength() is 0)) | |
410 return new Region(0, fMasterDocument.getLength()); | |
411 } | |
412 return new Region(toOriginOffset(imageOffset), 0); | |
413 } | |
414 | |
415 int originOffset= toOriginOffset(imageOffset); | |
416 int inclusiveImageEndOffset= imageOffset + imageLength -1; | |
417 int inclusiveOriginEndOffset= toOriginOffset(inclusiveImageEndOffset); | |
418 | |
419 return new Region(originOffset, (inclusiveOriginEndOffset + 1) - originOffset); | |
420 } | |
421 | |
422 /* | |
423 * @see org.eclipse.jface.text.IDocumentInformationMapping#toOriginLines(int) | |
424 */ | |
425 public IRegion toOriginLines(int imageLine) { | |
426 IRegion imageRegion= fSlaveDocument.getLineInformation(imageLine); | |
427 IRegion originRegion= toOriginRegion(imageRegion); | |
428 | |
429 int originStartLine= fMasterDocument.getLineOfOffset(originRegion.getOffset()); | |
430 if (originRegion.getLength() is 0) | |
431 return new Region(originStartLine, 1); | |
432 | |
433 int originEndLine= fMasterDocument.getLineOfOffset(inclusiveEnd(originRegion)); | |
434 return new Region(originStartLine, (originEndLine + 1) - originStartLine); | |
435 } | |
436 | |
437 /* | |
438 * @see org.eclipse.jface.text.IDocumentInformationMapping#toOriginLine(int) | |
439 */ | |
440 public int toOriginLine(int imageLine) { | |
441 IRegion lines= toOriginLines(imageLine); | |
442 return (lines.getLength() > 1 ? -1 : lines.getOffset()); | |
443 } | |
444 | |
445 /* | |
446 * @see org.eclipse.jface.text.IDocumentInformationMapping#toImageOffset(int) | |
447 */ | |
448 public int toImageOffset(int originOffset) { | |
449 Fragment fragment= findFragment(originOffset); | |
450 if (fragment !is null) { | |
451 int relative= originOffset - fragment.offset; | |
452 return fragment.segment.offset + relative; | |
453 } | |
454 return -1; | |
455 } | |
456 | |
457 /* | |
458 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension#toExactImageRegion(org.eclipse.jface.text.IRegion) | |
459 */ | |
460 public IRegion toExactImageRegion(IRegion originRegion) { | |
461 return toImageRegion(originRegion, true, false); | |
462 } | |
463 | |
464 /* | |
465 * @see org.eclipse.jface.text.IDocumentInformationMapping#toImageRegion(org.eclipse.jface.text.IRegion) | |
466 */ | |
467 public IRegion toImageRegion(IRegion originRegion) { | |
468 return toImageRegion(originRegion, false, false); | |
469 } | |
470 | |
471 /* | |
472 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension2#toClosestImageRegion(org.eclipse.jface.text.IRegion) | |
473 * @since 3.1 | |
474 */ | |
475 public IRegion toClosestImageRegion(IRegion originRegion) { | |
476 return toImageRegion(originRegion, false, true); | |
477 } | |
478 | |
479 /* | |
480 * @see org.eclipse.jface.text.IDocumentInformationMapping#toImageLine(int) | |
481 */ | |
482 public int toImageLine(int originLine) { | |
483 IRegion originRegion= fMasterDocument.getLineInformation(originLine); | |
484 IRegion imageRegion= toImageRegion(originRegion); | |
485 if (imageRegion is null) { | |
486 int imageOffset= toImageOffset(originRegion.getOffset()); | |
487 if (imageOffset > -1) | |
488 imageRegion= new Region(imageOffset, 0); | |
489 else | |
490 return -1; | |
491 } | |
492 | |
493 int startLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset()); | |
494 if (imageRegion.getLength() is 0) | |
495 return startLine; | |
496 | |
497 int endLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset() + imageRegion.getLength()); | |
498 if (endLine !is startLine) | |
499 throw new IllegalStateException(); | |
500 | |
501 return startLine; | |
502 } | |
503 | |
504 /* | |
505 * @see org.eclipse.jface.text.IDocumentInformationMapping#toClosestImageLine(int) | |
506 */ | |
507 public int toClosestImageLine(int originLine) { | |
508 try { | |
509 | |
510 int imageLine= toImageLine(originLine); | |
511 if (imageLine > -1) | |
512 return imageLine; | |
513 | |
514 Position[] fragments= getFragments(); | |
515 if (fragments.length is 0) | |
516 return -1; | |
517 | |
518 IRegion originLineRegion= fMasterDocument.getLineInformation(originLine); | |
519 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, originLineRegion.getOffset()); | |
520 | |
521 if (0 < index && index < fragments.length) { | |
522 Fragment left= cast(Fragment) fragments[index - 1]; | |
523 int leftDistance= originLineRegion.getOffset() - (exclusiveEnd(left)); | |
524 Fragment right= cast(Fragment) fragments[index]; | |
525 int rightDistance= right.getOffset() - (exclusiveEnd(originLineRegion)); | |
526 | |
527 if (leftDistance <= rightDistance) | |
528 originLine= fMasterDocument.getLineOfOffset(left.getOffset() + Math.max(left.getLength() - 1, 0)); | |
529 else | |
530 originLine= fMasterDocument.getLineOfOffset(right.getOffset()); | |
531 | |
532 } else if (index is 0) { | |
533 Fragment right= cast(Fragment) fragments[index]; | |
534 originLine= fMasterDocument.getLineOfOffset(right.getOffset()); | |
535 } else if (index is fragments.length) { | |
536 Fragment left= cast(Fragment) fragments[index - 1]; | |
537 originLine= fMasterDocument.getLineOfOffset(exclusiveEnd(left)); | |
538 } | |
539 | |
540 return toImageLine(originLine); | |
541 | |
542 } catch (BadPositionCategoryException x) { | |
543 } | |
544 | |
545 return -1; | |
546 } | |
547 | |
548 /* | |
549 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension#toExactOriginRegions(org.eclipse.jface.text.IRegion) | |
550 */ | |
551 public IRegion[] toExactOriginRegions(IRegion imageRegion) { | |
552 | |
553 if (imageRegion.getLength() is 0) | |
554 return [ new Region(toOriginOffset(imageRegion.getOffset()), 0) ]; | |
555 | |
556 int endOffset= exclusiveEnd(imageRegion); | |
557 Position[] segments= getSegments(); | |
558 int firstIndex= findSegmentIndex(imageRegion.getOffset()); | |
559 int lastIndex= findSegmentIndex(endOffset - 1); | |
560 | |
561 int resultLength= lastIndex - firstIndex + 1; | |
562 IRegion[] result= new IRegion[resultLength]; | |
563 | |
564 // first | |
565 result[0]= createOriginStartRegion(cast(Segment) segments[firstIndex], imageRegion.getOffset() - segments[firstIndex].getOffset()); | |
566 // middles | |
567 for (int i= 1; i < resultLength - 1; i++) | |
568 result[i]= createOriginRegion(cast(Segment) segments[firstIndex + i]); | |
569 // last | |
570 Segment last= cast(Segment) segments[lastIndex]; | |
571 int segmentEndOffset= exclusiveEnd(last); | |
572 IRegion lastRegion= createOriginEndRegion(last, segmentEndOffset - endOffset); | |
573 if (resultLength > 1) { | |
574 // first !is last | |
575 result[resultLength - 1]= lastRegion; | |
576 } else { | |
577 // merge first and last | |
578 IRegion intersection= getIntersectingRegion(result[0], lastRegion); | |
579 if (intersection is null) | |
580 result= new IRegion[0]; | |
581 else | |
582 result[0]= intersection; | |
583 } | |
584 | |
585 return result; | |
586 } | |
587 | |
588 /* | |
589 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension#getImageLength() | |
590 */ | |
591 public int getImageLength() { | |
592 Position[] segments= getSegments(); | |
593 int length= 0; | |
594 for (int i= 0; i < segments.length; i++) | |
595 length += segments[i].length; | |
596 return length; | |
597 } | |
598 | |
599 /* | |
600 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension#toExactImageRegions(org.eclipse.jface.text.IRegion) | |
601 */ | |
602 public IRegion[] toExactImageRegions(IRegion originRegion) { | |
603 | |
604 int offset= originRegion.getOffset(); | |
605 if (originRegion.getLength() is 0) { | |
606 int imageOffset= toImageOffset(offset); | |
607 return imageOffset > -1 ? [ cast(IRegion) new Region(imageOffset, 0) ] : null; | |
608 } | |
609 | |
610 int endOffset= exclusiveEnd(originRegion); | |
611 Position[] fragments= getFragments(); | |
612 int firstIndex= findFragmentIndex(offset, RIGHT); | |
613 int lastIndex= findFragmentIndex(endOffset - 1, LEFT); | |
614 | |
615 if (firstIndex is -1 || firstIndex > lastIndex) | |
616 return null; | |
617 | |
618 int resultLength= lastIndex - firstIndex + 1; | |
619 IRegion[] result= new IRegion[resultLength]; | |
620 | |
621 // first | |
622 result[0]= createImageStartRegion(cast(Fragment) fragments[firstIndex], offset - fragments[firstIndex].getOffset()); | |
623 // middles | |
624 for (int i= 1; i < resultLength - 1; i++) | |
625 result[i]= createImageRegion(cast(Fragment) fragments[firstIndex + i]); | |
626 // last | |
627 Fragment last= cast(Fragment) fragments[lastIndex]; | |
628 int fragmentEndOffset= exclusiveEnd(last); | |
629 IRegion lastRegion= createImageEndRegion(last, fragmentEndOffset - endOffset); | |
630 if (resultLength > 1) { | |
631 // first !is last | |
632 result[resultLength - 1]= lastRegion; | |
633 } else { | |
634 // merge first and last | |
635 IRegion intersection= getIntersectingRegion(result[0], lastRegion); | |
636 if (intersection is null) | |
637 return null; | |
638 result[0]= intersection; | |
639 } | |
640 | |
641 return result; | |
642 } | |
643 | |
644 /* | |
645 * @see org.eclipse.jface.text.IDocumentInformationMappingExtension#getExactCoverage(org.eclipse.jface.text.IRegion) | |
646 */ | |
647 public IRegion[] getExactCoverage(IRegion originRegion) { | |
648 | |
649 int originOffset= originRegion.getOffset(); | |
650 int originLength= originRegion.getLength(); | |
651 | |
652 if (originLength is 0) { | |
653 int imageOffset= toImageOffset(originOffset); | |
654 return imageOffset > -1 ? [ cast(IRegion)new Region(originOffset, 0) ] : null; | |
655 } | |
656 | |
657 int endOffset= originOffset + originLength; | |
658 Position[] fragments= getFragments(); | |
659 int firstIndex= findFragmentIndex(originOffset, RIGHT); | |
660 int lastIndex= findFragmentIndex(endOffset - 1, LEFT); | |
661 | |
662 if (firstIndex is -1 || firstIndex > lastIndex) | |
663 return null; | |
664 | |
665 int resultLength= lastIndex - firstIndex + 1; | |
666 IRegion[] result= new IRegion[resultLength]; | |
667 | |
668 // first | |
669 result[0]= createOriginStartRegion(cast(Fragment) fragments[firstIndex], originOffset - fragments[firstIndex].getOffset()); | |
670 // middles | |
671 for (int i= 1; i < resultLength - 1; i++) | |
672 result[i]= createOriginRegion(cast(Fragment) fragments[firstIndex + i]); | |
673 // last | |
674 Fragment last= cast(Fragment) fragments[lastIndex]; | |
675 int fragmentEndOffset= exclusiveEnd(last); | |
676 IRegion lastRegion= createOriginEndRegion(last, fragmentEndOffset - endOffset); | |
677 if (resultLength > 1) { | |
678 // first !is last | |
679 result[resultLength - 1]= lastRegion; | |
680 } else { | |
681 // merge first and last | |
682 IRegion intersection= getIntersectingRegion(result[0], lastRegion); | |
683 if (intersection is null) | |
684 return null; | |
685 result[0]= intersection; | |
686 } | |
687 | |
688 return result; | |
689 } | |
690 | |
691 private final void checkOriginRegion(IRegion originRegion) { | |
692 int offset= originRegion.getOffset(); | |
693 int endOffset= inclusiveEnd(originRegion); | |
694 int max= fMasterDocument.getLength(); | |
695 if (offset < 0 || offset > max || endOffset < 0 || endOffset > max) | |
696 throw new BadLocationException(); | |
697 } | |
698 | |
699 private final void checkOriginOffset(int originOffset) { | |
700 if (originOffset < 0 || originOffset > fMasterDocument.getLength()) | |
701 throw new BadLocationException(); | |
702 } | |
703 | |
704 private final void checkImageOffset(int imageOffset) { | |
705 if (imageOffset < 0 || imageOffset > getImageLength()) | |
706 throw new BadLocationException(); | |
707 } | |
708 | |
709 private final int exclusiveEnd(Position position) { | |
710 return position.offset + position.length; | |
711 } | |
712 | |
713 private final int exclusiveEnd(IRegion region) { | |
714 return region.getOffset() + region.getLength(); | |
715 } | |
716 | |
717 private final int inclusiveEnd(IRegion region) { | |
718 int length= region.getLength(); | |
719 if (length is 0) | |
720 return region.getOffset(); | |
721 return region.getOffset() + length - 1; | |
722 } | |
723 | |
724 | |
725 } |