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 }