1 11 package org.eclipse.jface.text.projection; 12 13 14 import org.eclipse.core.runtime.Assert; 15 16 import org.eclipse.jface.text.BadLocationException; 17 import org.eclipse.jface.text.BadPositionCategoryException; 18 import org.eclipse.jface.text.IDocument; 19 import org.eclipse.jface.text.IDocumentInformationMapping; 20 import org.eclipse.jface.text.IDocumentInformationMappingExtension; 21 import org.eclipse.jface.text.IDocumentInformationMappingExtension2; 22 import org.eclipse.jface.text.IRegion; 23 import org.eclipse.jface.text.Position; 24 import org.eclipse.jface.text.Region; 25 26 27 35 public class ProjectionMapping implements IDocumentInformationMapping , IDocumentInformationMappingExtension, IDocumentInformationMappingExtension2, IMinimalMapping { 36 37 private static final int LEFT= -1; 38 private static final int NONE= 0; 39 private static final int RIGHT= +1; 40 41 42 private IDocument fMasterDocument; 43 44 private String fFragmentsCategory; 45 46 private IDocument fSlaveDocument; 47 48 private String fSegmentsCategory; 49 50 private Position[] fCachedSegments; 51 52 private Position[] fCachedFragments; 53 54 62 public ProjectionMapping(IDocument masterDocument, String fragmentsCategory, IDocument slaveDocument, String segmentsCategory) { 63 fMasterDocument= masterDocument; 64 fFragmentsCategory= fragmentsCategory; 65 fSlaveDocument= slaveDocument; 66 fSegmentsCategory= segmentsCategory; 67 } 68 69 72 public void projectionChanged() { 73 fCachedSegments= null; 74 fCachedFragments= null; 75 } 76 77 private Position[] getSegments() { 78 if (fCachedSegments == null) { 79 try { 80 fCachedSegments= fSlaveDocument.getPositions(fSegmentsCategory); 81 } catch (BadPositionCategoryException e) { 82 return new Position[0]; 83 } 84 } 85 return fCachedSegments; 86 } 87 88 private Position[] getFragments() { 89 if (fCachedFragments == null) { 90 try { 91 fCachedFragments= fMasterDocument.getPositions(fFragmentsCategory); 92 } catch (BadPositionCategoryException e) { 93 return new Position[0]; 94 } 95 } 96 return fCachedFragments; 97 } 98 99 private int findSegmentIndex(int offset) throws BadLocationException { 100 Position[] segments= getSegments(); 101 if (segments.length == 0) { 102 if (offset > 0) 103 throw new BadLocationException(); 104 return -1; 105 } 106 107 try { 108 int index= fSlaveDocument.computeIndexInCategory(fSegmentsCategory, offset); 109 if (index == segments.length && offset > exclusiveEnd(segments[index-1])) 110 throw new BadLocationException(); 111 112 if (index < segments.length && offset == segments[index].offset) 113 return index; 114 115 if (index > 0) 116 index--; 117 118 return index; 119 120 } catch (BadPositionCategoryException e) { 121 throw new IllegalStateException (); 122 } 123 } 124 125 private Segment findSegment(int offset) throws BadLocationException { 126 127 checkImageOffset(offset); 128 129 int index= findSegmentIndex(offset); 130 if (index == -1) { 131 132 Segment s= new Segment(0, 0); 133 Fragment f= new Fragment(0, 0); 134 s.fragment= f; 135 f.segment= s; 136 return s; 137 } 138 139 Position[] segments= getSegments(); 140 return (Segment) segments[index]; 141 } 142 143 166 private int findFragmentIndex(int offset, int extensionDirection) throws BadLocationException { 167 try { 168 169 Position[] fragments= getFragments(); 170 if (fragments.length == 0) 171 return -1; 172 173 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offset); 174 175 if (index < fragments.length && offset == fragments[index].offset) 176 return index; 177 178 if (0 < index && index <= fragments.length && fragments[index - 1].includes(offset)) 179 return index - 1; 180 181 switch (extensionDirection) { 182 case LEFT: 183 return index - 1; 184 case RIGHT: 185 if (index < fragments.length) 186 return index; 187 } 188 189 return -1; 190 191 } catch (BadPositionCategoryException e) { 192 throw new IllegalStateException (); 193 } 194 } 195 196 private Fragment findFragment(int offset) throws BadLocationException { 197 checkOriginOffset(offset); 198 199 int index= findFragmentIndex(offset, NONE); 200 Position[] fragments= getFragments(); 201 if (index == -1) { 202 if (fragments.length > 0) { 203 Fragment last= (Fragment) fragments[fragments.length - 1]; 204 if (exclusiveEnd(last) == offset) 205 return last; 206 } 207 return null; 208 } 209 return (Fragment) fragments[index]; 210 } 211 212 227 private IRegion toImageRegion(IRegion originRegion, boolean exact, boolean takeClosestImage) throws BadLocationException { 228 if (originRegion.getLength() == 0 && !takeClosestImage) { 229 int imageOffset= toImageOffset(originRegion.getOffset()); 230 return imageOffset == -1 ? null : new Region(imageOffset, 0); 231 } 232 233 Fragment[] fragments= findFragments(originRegion, exact, takeClosestImage); 234 if (fragments == null) { 235 if (takeClosestImage) { 236 Position[] allFragments= getFragments(); 238 if (allFragments.length > 0) { 239 if (exclusiveEnd(originRegion) <= allFragments[0].getOffset()) 241 return new Region(0, 0); 242 Position last= allFragments[allFragments.length - 1]; 244 if (originRegion.getOffset() >= exclusiveEnd(last)) 245 return new Region(exclusiveEnd(((Fragment) last).segment), 0); 246 } 247 return new Region(0, 0); 248 } 249 return null; 250 } 251 252 int imageOffset, exclusiveImageEndOffset; 253 254 int relative= originRegion.getOffset() - fragments[0].getOffset(); 256 if (relative < 0) { 257 Assert.isTrue(!exact); 258 relative= 0; 259 } 260 imageOffset= fragments[0].segment.getOffset() + relative; 261 262 relative= exclusiveEnd(originRegion) - fragments[1].getOffset(); 264 if (relative > fragments[1].getLength()) { 265 Assert.isTrue(!exact); 266 relative= fragments[1].getLength(); 267 } 268 exclusiveImageEndOffset= fragments[1].segment.getOffset() + relative; 269 270 return new Region(imageOffset, exclusiveImageEndOffset - imageOffset); 271 } 272 273 290 private Fragment[] findFragments(IRegion originRegion, boolean exact, boolean takeClosestImage) throws BadLocationException { 291 Position[] fragments= getFragments(); 292 if (fragments.length == 0) 293 return null; 294 295 checkOriginRegion(originRegion); 296 297 int startFragmentIdx= findFragmentIndex(originRegion.getOffset(), exact ? NONE : RIGHT); 298 if (startFragmentIdx == -1) 299 return null; 300 301 int endFragmentIdx= findFragmentIndex(inclusiveEnd(originRegion), exact ? NONE : LEFT); 302 if (!takeClosestImage && startFragmentIdx > endFragmentIdx || endFragmentIdx == -1) 303 return null; 304 305 Fragment[] result= {(Fragment) fragments[startFragmentIdx], (Fragment) fragments[endFragmentIdx]}; 306 return result; 307 } 308 309 private IRegion createOriginStartRegion(Segment image, int offsetShift) { 310 return new Region(image.fragment.getOffset() + offsetShift, image.fragment.getLength() - offsetShift); 311 } 312 313 private IRegion createOriginRegion(Segment image) { 314 return new Region(image.fragment.getOffset(), image.fragment.getLength()); 315 } 316 317 private IRegion createOriginEndRegion(Segment image, int lengthReduction) { 318 return new Region(image.fragment.getOffset(), image.fragment.getLength() - lengthReduction); 319 } 320 321 private IRegion createImageStartRegion(Fragment origin, int offsetShift) { 322 int shift= offsetShift > 0 ? offsetShift : 0; 323 return new Region(origin.segment.getOffset() + shift, origin.segment.getLength() - shift); 324 } 325 326 private IRegion createImageRegion(Fragment origin) { 327 return new Region(origin.segment.getOffset(), origin.segment.getLength()); 328 } 329 330 private IRegion createImageEndRegion(Fragment origin, int lengthReduction) { 331 int reduction= lengthReduction > 0 ? lengthReduction : 0; 332 return new Region(origin.segment.getOffset(), origin.segment.getLength() - reduction); 333 } 334 335 private IRegion createOriginStartRegion(Fragment origin, int offsetShift) { 336 int shift= offsetShift > 0 ? offsetShift : 0; 337 return new Region(origin.getOffset() + shift, origin.getLength() - shift); 338 } 339 340 private IRegion createOriginRegion(Fragment origin) { 341 return new Region(origin.getOffset(), origin.getLength()); 342 } 343 344 private IRegion createOriginEndRegion(Fragment origin, int lengthReduction) { 345 int reduction= lengthReduction > 0 ? lengthReduction : 0; 346 return new Region(origin.getOffset(), origin.getLength() - reduction); 347 } 348 349 private IRegion getIntersectingRegion(IRegion left, IRegion right) { 350 int offset= Math.max(left.getOffset(), right.getOffset()); 351 int exclusiveEndOffset= Math.min(exclusiveEnd(left), exclusiveEnd(right)); 352 if (exclusiveEndOffset < offset) 353 return null; 354 return new Region(offset, exclusiveEndOffset - offset); 355 } 356 357 360 public IRegion getCoverage() { 361 Position[] fragments= getFragments(); 362 if (fragments != null && fragments.length > 0) { 363 Position first=fragments[0]; 364 Position last= fragments[fragments.length -1]; 365 return new Region(first.offset, exclusiveEnd(last) - first.offset); 366 } 367 return new Region(0, 0); 368 } 369 370 373 public int toOriginOffset(int imageOffset) throws BadLocationException { 374 Segment segment= findSegment(imageOffset); 375 int relative= imageOffset - segment.offset; 376 return segment.fragment.offset + relative; 377 } 378 379 382 public IRegion toOriginRegion(IRegion imageRegion) throws BadLocationException { 383 int imageOffset= imageRegion.getOffset(); 384 int imageLength= imageRegion.getLength(); 385 386 if (imageLength == 0) { 387 if (imageOffset == 0) { 388 Position[] fragments= getFragments(); 389 if (fragments.length == 0 || (fragments.length == 1 && fragments[0].getOffset() == 0 && fragments[0].getLength() == 0)) 390 return new Region(0, fMasterDocument.getLength()); 391 } 392 return new Region(toOriginOffset(imageOffset), 0); 393 } 394 395 int originOffset= toOriginOffset(imageOffset); 396 int inclusiveImageEndOffset= imageOffset + imageLength -1; 397 int inclusiveOriginEndOffset= toOriginOffset(inclusiveImageEndOffset); 398 399 return new Region(originOffset, (inclusiveOriginEndOffset + 1) - originOffset); 400 } 401 402 405 public IRegion toOriginLines(int imageLine) throws BadLocationException { 406 IRegion imageRegion= fSlaveDocument.getLineInformation(imageLine); 407 IRegion originRegion= toOriginRegion(imageRegion); 408 409 int originStartLine= fMasterDocument.getLineOfOffset(originRegion.getOffset()); 410 if (originRegion.getLength() == 0) 411 return new Region(originStartLine, 1); 412 413 int originEndLine= fMasterDocument.getLineOfOffset(inclusiveEnd(originRegion)); 414 return new Region(originStartLine, (originEndLine + 1) - originStartLine); 415 } 416 417 420 public int toOriginLine(int imageLine) throws BadLocationException { 421 IRegion lines= toOriginLines(imageLine); 422 return (lines.getLength() > 1 ? -1 : lines.getOffset()); 423 } 424 425 428 public int toImageOffset(int originOffset) throws BadLocationException { 429 Fragment fragment= findFragment(originOffset); 430 if (fragment != null) { 431 int relative= originOffset - fragment.offset; 432 return fragment.segment.offset + relative; 433 } 434 return -1; 435 } 436 437 440 public IRegion toExactImageRegion(IRegion originRegion) throws BadLocationException { 441 return toImageRegion(originRegion, true, false); 442 } 443 444 447 public IRegion toImageRegion(IRegion originRegion) throws BadLocationException { 448 return toImageRegion(originRegion, false, false); 449 } 450 451 455 public IRegion toClosestImageRegion(IRegion originRegion) throws BadLocationException { 456 return toImageRegion(originRegion, false, true); 457 } 458 459 462 public int toImageLine(int originLine) throws BadLocationException { 463 IRegion originRegion= fMasterDocument.getLineInformation(originLine); 464 IRegion imageRegion= toImageRegion(originRegion); 465 if (imageRegion == null) { 466 int imageOffset= toImageOffset(originRegion.getOffset()); 467 if (imageOffset > -1) 468 imageRegion= new Region(imageOffset, 0); 469 else 470 return -1; 471 } 472 473 int startLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset()); 474 if (imageRegion.getLength() == 0) 475 return startLine; 476 477 int endLine= fSlaveDocument.getLineOfOffset(imageRegion.getOffset() + imageRegion.getLength()); 478 if (endLine != startLine) 479 throw new IllegalStateException (); 480 481 return startLine; 482 } 483 484 487 public int toClosestImageLine(int originLine) throws BadLocationException { 488 try { 489 490 int imageLine= toImageLine(originLine); 491 if (imageLine > -1) 492 return imageLine; 493 494 Position[] fragments= getFragments(); 495 if (fragments.length == 0) 496 return -1; 497 498 IRegion originLineRegion= fMasterDocument.getLineInformation(originLine); 499 int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, originLineRegion.getOffset()); 500 501 if (0 < index && index < fragments.length) { 502 Fragment left= (Fragment) fragments[index - 1]; 503 int leftDistance= originLineRegion.getOffset() - (exclusiveEnd(left)); 504 Fragment right= (Fragment) fragments[index]; 505 int rightDistance= right.getOffset() - (exclusiveEnd(originLineRegion)); 506 507 if (leftDistance <= rightDistance) 508 originLine= fMasterDocument.getLineOfOffset(left.getOffset() + Math.max(left.getLength() - 1, 0)); 509 else 510 originLine= fMasterDocument.getLineOfOffset(right.getOffset()); 511 512 } else if (index == 0) { 513 Fragment right= (Fragment) fragments[index]; 514 originLine= fMasterDocument.getLineOfOffset(right.getOffset()); 515 } else if (index == fragments.length) { 516 Fragment left= (Fragment) fragments[index - 1]; 517 originLine= fMasterDocument.getLineOfOffset(exclusiveEnd(left)); 518 } 519 520 return toImageLine(originLine); 521 522 } catch (BadPositionCategoryException x) { 523 } 524 525 return -1; 526 } 527 528 531 public IRegion[] toExactOriginRegions(IRegion imageRegion) throws BadLocationException { 532 533 if (imageRegion.getLength() == 0) 534 return new IRegion[] { new Region(toOriginOffset(imageRegion.getOffset()), 0) }; 535 536 int endOffset= exclusiveEnd(imageRegion); 537 Position[] segments= getSegments(); 538 int firstIndex= findSegmentIndex(imageRegion.getOffset()); 539 int lastIndex= findSegmentIndex(endOffset - 1); 540 541 int resultLength= lastIndex - firstIndex + 1; 542 IRegion[] result= new IRegion[resultLength]; 543 544 result[0]= createOriginStartRegion((Segment) segments[firstIndex], imageRegion.getOffset() - segments[firstIndex].getOffset()); 546 for (int i= 1; i < resultLength - 1; i++) 548 result[i]= createOriginRegion((Segment) segments[firstIndex + i]); 549 Segment last= (Segment) segments[lastIndex]; 551 int segmentEndOffset= exclusiveEnd(last); 552 IRegion lastRegion= createOriginEndRegion(last, segmentEndOffset - endOffset); 553 if (resultLength > 1) { 554 result[resultLength - 1]= lastRegion; 556 } else { 557 IRegion intersection= getIntersectingRegion(result[0], lastRegion); 559 if (intersection == null) 560 result= new IRegion[0]; 561 else 562 result[0]= intersection; 563 } 564 565 return result; 566 } 567 568 571 public int getImageLength() { 572 Position[] segments= getSegments(); 573 int length= 0; 574 for (int i= 0; i < segments.length; i++) 575 length += segments[i].length; 576 return length; 577 } 578 579 582 public IRegion[] toExactImageRegions(IRegion originRegion) throws BadLocationException { 583 584 int offset= originRegion.getOffset(); 585 if (originRegion.getLength() == 0) { 586 int imageOffset= toImageOffset(offset); 587 return imageOffset > -1 ? new IRegion[] { new Region(imageOffset, 0) } : null; 588 } 589 590 int endOffset= exclusiveEnd(originRegion); 591 Position[] fragments= getFragments(); 592 int firstIndex= findFragmentIndex(offset, RIGHT); 593 int lastIndex= findFragmentIndex(endOffset - 1, LEFT); 594 595 if (firstIndex == -1 || firstIndex > lastIndex) 596 return null; 597 598 int resultLength= lastIndex - firstIndex + 1; 599 IRegion[] result= new IRegion[resultLength]; 600 601 result[0]= createImageStartRegion((Fragment) fragments[firstIndex], offset - fragments[firstIndex].getOffset()); 603 for (int i= 1; i < resultLength - 1; i++) 605 result[i]= createImageRegion((Fragment) fragments[firstIndex + i]); 606 Fragment last= (Fragment) fragments[lastIndex]; 608 int fragmentEndOffset= exclusiveEnd(last); 609 IRegion lastRegion= createImageEndRegion(last, fragmentEndOffset - endOffset); 610 if (resultLength > 1) { 611 result[resultLength - 1]= lastRegion; 613 } else { 614 IRegion intersection= getIntersectingRegion(result[0], lastRegion); 616 if (intersection == null) 617 return null; 618 result[0]= intersection; 619 } 620 621 return result; 622 } 623 624 627 public IRegion[] getExactCoverage(IRegion originRegion) throws BadLocationException { 628 629 int originOffset= originRegion.getOffset(); 630 int originLength= originRegion.getLength(); 631 632 if (originLength == 0) { 633 int imageOffset= toImageOffset(originOffset); 634 return imageOffset > -1 ? new IRegion[] { new Region(originOffset, 0) } : null; 635 } 636 637 int endOffset= originOffset + originLength; 638 Position[] fragments= getFragments(); 639 int firstIndex= findFragmentIndex(originOffset, RIGHT); 640 int lastIndex= findFragmentIndex(endOffset - 1, LEFT); 641 642 if (firstIndex == -1 || firstIndex > lastIndex) 643 return null; 644 645 int resultLength= lastIndex - firstIndex + 1; 646 IRegion[] result= new IRegion[resultLength]; 647 648 result[0]= createOriginStartRegion((Fragment) fragments[firstIndex], originOffset - fragments[firstIndex].getOffset()); 650 for (int i= 1; i < resultLength - 1; i++) 652 result[i]= createOriginRegion((Fragment) fragments[firstIndex + i]); 653 Fragment last= (Fragment) fragments[lastIndex]; 655 int fragmentEndOffset= exclusiveEnd(last); 656 IRegion lastRegion= createOriginEndRegion(last, fragmentEndOffset - endOffset); 657 if (resultLength > 1) { 658 result[resultLength - 1]= lastRegion; 660 } else { 661 IRegion intersection= getIntersectingRegion(result[0], lastRegion); 663 if (intersection == null) 664 return null; 665 result[0]= intersection; 666 } 667 668 return result; 669 } 670 671 private final void checkOriginRegion(IRegion originRegion) throws BadLocationException { 672 int offset= originRegion.getOffset(); 673 int endOffset= inclusiveEnd(originRegion); 674 int max= fMasterDocument.getLength(); 675 if (offset < 0 || offset > max || endOffset < 0 || endOffset > max) 676 throw new BadLocationException(); 677 } 678 679 private final void checkOriginOffset(int originOffset) throws BadLocationException { 680 if (originOffset < 0 || originOffset > fMasterDocument.getLength()) 681 throw new BadLocationException(); 682 } 683 684 private final void checkImageOffset(int imageOffset) throws BadLocationException { 685 if (imageOffset < 0 || imageOffset > getImageLength()) 686 throw new BadLocationException(); 687 } 688 689 private final int exclusiveEnd(Position position) { 690 return position.offset + position.length; 691 } 692 693 private final int exclusiveEnd(IRegion region) { 694 return region.getOffset() + region.getLength(); 695 } 696 697 private final int inclusiveEnd(IRegion region) { 698 int length= region.getLength(); 699 if (length == 0) 700 return region.getOffset(); 701 return region.getOffset() + length - 1; 702 } 703 704 705 } 706 | Popular Tags |