1 11 package org.eclipse.jface.text.rules; 12 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.core.runtime.Assert; 18 19 import org.eclipse.jface.text.BadLocationException; 20 import org.eclipse.jface.text.BadPositionCategoryException; 21 import org.eclipse.jface.text.DefaultPositionUpdater; 22 import org.eclipse.jface.text.DocumentEvent; 23 import org.eclipse.jface.text.DocumentRewriteSession; 24 import org.eclipse.jface.text.IDocument; 25 import org.eclipse.jface.text.IDocumentPartitioner; 26 import org.eclipse.jface.text.IDocumentPartitionerExtension; 27 import org.eclipse.jface.text.IDocumentPartitionerExtension2; 28 import org.eclipse.jface.text.IDocumentPartitionerExtension3; 29 import org.eclipse.jface.text.IRegion; 30 import org.eclipse.jface.text.ITypedRegion; 31 import org.eclipse.jface.text.Position; 32 import org.eclipse.jface.text.Region; 33 import org.eclipse.jface.text.TextUtilities; 34 import org.eclipse.jface.text.TypedPosition; 35 import org.eclipse.jface.text.TypedRegion; 36 37 38 39 51 public class DefaultPartitioner implements IDocumentPartitioner, IDocumentPartitionerExtension, IDocumentPartitionerExtension2, IDocumentPartitionerExtension3 { 52 53 57 public final static String CONTENT_TYPES_CATEGORY= "__content_types_category"; 59 60 61 protected IPartitionTokenScanner fScanner; 62 63 protected String [] fLegalContentTypes; 64 65 protected IDocument fDocument; 66 67 protected int fPreviousDocumentLength; 68 69 protected DefaultPositionUpdater fPositionUpdater; 70 71 protected int fStartOffset; 72 73 protected int fEndOffset; 74 75 protected int fDeleteOffset; 76 80 private String fPositionCategory; 81 85 private DocumentRewriteSession fActiveRewriteSession; 86 90 private boolean fIsInitialized= false; 91 92 99 public DefaultPartitioner(IPartitionTokenScanner scanner, String [] legalContentTypes) { 100 fScanner= scanner; 101 fLegalContentTypes= TextUtilities.copy(legalContentTypes); 102 fPositionCategory= CONTENT_TYPES_CATEGORY + hashCode(); 103 fPositionUpdater= new DefaultPositionUpdater(fPositionCategory); 104 } 105 106 110 public String [] getManagingPositionCategories() { 111 return new String [] { fPositionCategory }; 112 } 113 114 117 public void connect(IDocument document) { 118 connect(document, false); 119 } 120 121 125 public void connect(IDocument document, boolean delayInitialization) { 126 Assert.isNotNull(document); 127 Assert.isTrue(!document.containsPositionCategory(fPositionCategory)); 128 129 fDocument= document; 130 fDocument.addPositionCategory(fPositionCategory); 131 132 fIsInitialized= false; 133 if (!delayInitialization) 134 checkInitialization(); 135 } 136 137 140 protected final void checkInitialization() { 141 if (!fIsInitialized) 142 initialize(); 143 } 144 145 148 protected void initialize() { 149 fIsInitialized= true; 150 fScanner.setRange(fDocument, 0, fDocument.getLength()); 151 152 try { 153 IToken token= fScanner.nextToken(); 154 while (!token.isEOF()) { 155 156 String contentType= getTokenContentType(token); 157 158 if (isSupportedContentType(contentType)) { 159 TypedPosition p= new TypedPosition(fScanner.getTokenOffset(), fScanner.getTokenLength(), contentType); 160 fDocument.addPosition(fPositionCategory, p); 161 } 162 163 token= fScanner.nextToken(); 164 } 165 } catch (BadLocationException x) { 166 } catch (BadPositionCategoryException x) { 168 } 170 } 171 172 175 public void disconnect() { 176 177 Assert.isTrue(fDocument.containsPositionCategory(fPositionCategory)); 178 179 try { 180 fDocument.removePositionCategory(fPositionCategory); 181 } catch (BadPositionCategoryException x) { 182 } 184 } 185 186 189 public void documentAboutToBeChanged(DocumentEvent e) { 190 if (fIsInitialized) { 191 192 Assert.isTrue(e.getDocument() == fDocument); 193 194 fPreviousDocumentLength= e.getDocument().getLength(); 195 fStartOffset= -1; 196 fEndOffset= -1; 197 fDeleteOffset= -1; 198 } 199 } 200 201 204 public boolean documentChanged(DocumentEvent e) { 205 if (fIsInitialized) { 206 IRegion region= documentChanged2(e); 207 return (region != null); 208 } 209 return false; 210 } 211 212 221 private void rememberRegion(int offset, int length) { 222 if (fStartOffset == -1) 224 fStartOffset= offset; 225 else if (offset < fStartOffset) 226 fStartOffset= offset; 227 228 int endOffset= offset + length; 230 if (fEndOffset == -1) 231 fEndOffset= endOffset; 232 else if (endOffset > fEndOffset) 233 fEndOffset= endOffset; 234 } 235 236 241 private void rememberDeletedOffset(int offset) { 242 fDeleteOffset= offset; 243 } 244 245 251 private IRegion createRegion() { 252 if (fDeleteOffset == -1) { 253 if (fStartOffset == -1 || fEndOffset == -1) 254 return null; 255 return new Region(fStartOffset, fEndOffset - fStartOffset); 256 } else if (fStartOffset == -1 || fEndOffset == -1) { 257 return new Region(fDeleteOffset, 0); 258 } else { 259 int offset= Math.min(fDeleteOffset, fStartOffset); 260 int endOffset= Math.max(fDeleteOffset, fEndOffset); 261 return new Region(offset, endOffset - offset); 262 } 263 } 264 265 269 public IRegion documentChanged2(DocumentEvent e) { 270 271 if (!fIsInitialized) 272 return null; 273 274 try { 275 276 IDocument d= e.getDocument(); 277 Position[] category= d.getPositions(fPositionCategory); 278 IRegion line= d.getLineInformationOfOffset(e.getOffset()); 279 int reparseStart= line.getOffset(); 280 int partitionStart= -1; 281 String contentType= null; 282 int newLength= e.getText() == null ? 0 : e.getText().length(); 283 284 int first= d.computeIndexInCategory(fPositionCategory, reparseStart); 285 if (first > 0) { 286 TypedPosition partition= (TypedPosition) category[first - 1]; 287 if (partition.includes(reparseStart)) { 288 partitionStart= partition.getOffset(); 289 contentType= partition.getType(); 290 if (e.getOffset() == partition.getOffset() + partition.getLength()) 291 reparseStart= partitionStart; 292 -- first; 293 } else if (reparseStart == e.getOffset() && reparseStart == partition.getOffset() + partition.getLength()) { 294 partitionStart= partition.getOffset(); 295 contentType= partition.getType(); 296 reparseStart= partitionStart; 297 -- first; 298 } else { 299 partitionStart= partition.getOffset() + partition.getLength(); 300 contentType= IDocument.DEFAULT_CONTENT_TYPE; 301 } 302 } 303 304 fPositionUpdater.update(e); 305 for (int i= first; i < category.length; i++) { 306 Position p= category[i]; 307 if (p.isDeleted) { 308 rememberDeletedOffset(e.getOffset()); 309 break; 310 } 311 } 312 category= d.getPositions(fPositionCategory); 313 314 fScanner.setPartialRange(d, reparseStart, d.getLength() - reparseStart, contentType, partitionStart); 315 316 int lastScannedPosition= reparseStart; 317 IToken token= fScanner.nextToken(); 318 319 while (!token.isEOF()) { 320 321 contentType= getTokenContentType(token); 322 323 if (!isSupportedContentType(contentType)) { 324 token= fScanner.nextToken(); 325 continue; 326 } 327 328 int start= fScanner.getTokenOffset(); 329 int length= fScanner.getTokenLength(); 330 331 lastScannedPosition= start + length - 1; 332 333 while (first < category.length) { 335 TypedPosition p= (TypedPosition) category[first]; 336 if (lastScannedPosition >= p.offset + p.length || 337 (p.overlapsWith(start, length) && 338 (!d.containsPosition(fPositionCategory, start, length) || 339 !contentType.equals(p.getType())))) { 340 341 rememberRegion(p.offset, p.length); 342 d.removePosition(fPositionCategory, p); 343 ++ first; 344 345 } else 346 break; 347 } 348 349 if (d.containsPosition(fPositionCategory, start, length)) { 352 if (lastScannedPosition >= e.getOffset() + newLength) 353 return createRegion(); 354 ++ first; 355 } else { 356 try { 358 d.addPosition(fPositionCategory, new TypedPosition(start, length, contentType)); 359 rememberRegion(start, length); 360 } catch (BadPositionCategoryException x) { 361 } catch (BadLocationException x) { 362 } 363 } 364 365 token= fScanner.nextToken(); 366 } 367 368 369 if (lastScannedPosition != reparseStart) { 371 ++ lastScannedPosition; 373 } 374 first= d.computeIndexInCategory(fPositionCategory, lastScannedPosition); 375 category= d.getPositions(fPositionCategory); 376 377 TypedPosition p; 378 while (first < category.length) { 379 p= (TypedPosition) category[first++]; 380 d.removePosition(fPositionCategory, p); 381 rememberRegion(p.offset, p.length); 382 } 383 384 } catch (BadPositionCategoryException x) { 385 } catch (BadLocationException x) { 387 } 388 389 return createRegion(); 390 } 391 392 393 403 protected TypedPosition findClosestPosition(int offset) { 404 405 try { 406 407 int index= fDocument.computeIndexInCategory(fPositionCategory, offset); 408 Position[] category= fDocument.getPositions(fPositionCategory); 409 410 if (category.length == 0) 411 return null; 412 413 if (index < category.length) { 414 if (offset == category[index].offset) 415 return (TypedPosition) category[index]; 416 } 417 418 if (index > 0) 419 index--; 420 421 return (TypedPosition) category[index]; 422 423 } catch (BadPositionCategoryException x) { 424 } catch (BadLocationException x) { 425 } 426 427 return null; 428 } 429 430 431 434 public String getContentType(int offset) { 435 checkInitialization(); 436 437 TypedPosition p= findClosestPosition(offset); 438 if (p != null && p.includes(offset)) 439 return p.getType(); 440 441 return IDocument.DEFAULT_CONTENT_TYPE; 442 } 443 444 447 public ITypedRegion getPartition(int offset) { 448 checkInitialization(); 449 450 try { 451 452 Position[] category = fDocument.getPositions(fPositionCategory); 453 454 if (category == null || category.length == 0) 455 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE); 456 457 int index= fDocument.computeIndexInCategory(fPositionCategory, offset); 458 459 if (index < category.length) { 460 461 TypedPosition next= (TypedPosition) category[index]; 462 463 if (offset == next.offset) 464 return new TypedRegion(next.getOffset(), next.getLength(), next.getType()); 465 466 if (index == 0) 467 return new TypedRegion(0, next.offset, IDocument.DEFAULT_CONTENT_TYPE); 468 469 TypedPosition previous= (TypedPosition) category[index - 1]; 470 if (previous.includes(offset)) 471 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType()); 472 473 int endOffset= previous.getOffset() + previous.getLength(); 474 return new TypedRegion(endOffset, next.getOffset() - endOffset, IDocument.DEFAULT_CONTENT_TYPE); 475 } 476 477 TypedPosition previous= (TypedPosition) category[category.length - 1]; 478 if (previous.includes(offset)) 479 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType()); 480 481 int endOffset= previous.getOffset() + previous.getLength(); 482 return new TypedRegion(endOffset, fDocument.getLength() - endOffset, IDocument.DEFAULT_CONTENT_TYPE); 483 484 } catch (BadPositionCategoryException x) { 485 } catch (BadLocationException x) { 486 } 487 488 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE); 489 } 490 491 494 public ITypedRegion[] computePartitioning(int offset, int length) { 495 return computePartitioning(offset, length, false); 496 } 497 498 501 public String [] getLegalContentTypes() { 502 return TextUtilities.copy(fLegalContentTypes); 503 } 504 505 511 protected boolean isSupportedContentType(String contentType) { 512 if (contentType != null) { 513 for (int i= 0; i < fLegalContentTypes.length; i++) { 514 if (fLegalContentTypes[i].equals(contentType)) 515 return true; 516 } 517 } 518 519 return false; 520 } 521 522 530 protected String getTokenContentType(IToken token) { 531 Object data= token.getData(); 532 if (data instanceof String ) 533 return (String ) data; 534 return null; 535 } 536 537 538 539 543 public String getContentType(int offset, boolean preferOpenPartitions) { 544 return getPartition(offset, preferOpenPartitions).getType(); 545 } 546 547 551 public ITypedRegion getPartition(int offset, boolean preferOpenPartitions) { 552 ITypedRegion region= getPartition(offset); 553 if (preferOpenPartitions) { 554 if (region.getOffset() == offset && !region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) { 555 if (offset > 0) { 556 region= getPartition(offset - 1); 557 if (region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) 558 return region; 559 } 560 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE); 561 } 562 } 563 return region; 564 } 565 566 570 public ITypedRegion[] computePartitioning(int offset, int length, boolean includeZeroLengthPartitions) { 571 checkInitialization(); 572 List list= new ArrayList (); 573 574 try { 575 576 int endOffset= offset + length; 577 578 Position[] category= fDocument.getPositions(fPositionCategory); 579 580 TypedPosition previous= null, current= null; 581 int start, end, gapOffset; 582 Position gap= new Position(0); 583 584 int startIndex= getFirstIndexEndingAfterOffset(category, offset); 585 int endIndex= getFirstIndexStartingAfterOffset(category, endOffset); 586 for (int i= startIndex; i < endIndex; i++) { 587 588 current= (TypedPosition) category[i]; 589 590 gapOffset= (previous != null) ? previous.getOffset() + previous.getLength() : 0; 591 gap.setOffset(gapOffset); 592 gap.setLength(current.getOffset() - gapOffset); 593 if ((includeZeroLengthPartitions && overlapsOrTouches(gap, offset, length)) || 594 (gap.getLength() > 0 && gap.overlapsWith(offset, length))) { 595 start= Math.max(offset, gapOffset); 596 end= Math.min(endOffset, gap.getOffset() + gap.getLength()); 597 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE)); 598 } 599 600 if (current.overlapsWith(offset, length)) { 601 start= Math.max(offset, current.getOffset()); 602 end= Math.min(endOffset, current.getOffset() + current.getLength()); 603 list.add(new TypedRegion(start, end - start, current.getType())); 604 } 605 606 previous= current; 607 } 608 609 if (previous != null) { 610 gapOffset= previous.getOffset() + previous.getLength(); 611 gap.setOffset(gapOffset); 612 gap.setLength(fDocument.getLength() - gapOffset); 613 if ((includeZeroLengthPartitions && overlapsOrTouches(gap, offset, length)) || 614 (gap.getLength() > 0 && gap.overlapsWith(offset, length))) { 615 start= Math.max(offset, gapOffset); 616 end= Math.min(endOffset, fDocument.getLength()); 617 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE)); 618 } 619 } 620 621 if (list.isEmpty()) 622 list.add(new TypedRegion(offset, length, IDocument.DEFAULT_CONTENT_TYPE)); 623 624 } catch (BadPositionCategoryException x) { 625 } 626 627 TypedRegion[] result= new TypedRegion[list.size()]; 628 list.toArray(result); 629 return result; 630 } 631 632 641 private boolean overlapsOrTouches(Position gap, int offset, int length) { 642 return gap.getOffset() <= offset + length && offset <= gap.getOffset() + gap.getLength(); 643 } 644 645 654 private int getFirstIndexEndingAfterOffset(Position[] positions, int offset) { 655 int i= -1, j= positions.length; 656 while (j - i > 1) { 657 int k= (i + j) >> 1; 658 Position p= positions[k]; 659 if (p.getOffset() + p.getLength() > offset) 660 j= k; 661 else 662 i= k; 663 } 664 return j; 665 } 666 667 676 private int getFirstIndexStartingAfterOffset(Position[] positions, int offset) { 677 int i= -1, j= positions.length; 678 while (j - i > 1) { 679 int k= (i + j) >> 1; 680 Position p= positions[k]; 681 if (p.getOffset() >= offset) 682 j= k; 683 else 684 i= k; 685 } 686 return j; 687 } 688 689 693 public void startRewriteSession(DocumentRewriteSession session) throws IllegalStateException { 694 if (fActiveRewriteSession != null) 695 throw new IllegalStateException (); 696 fActiveRewriteSession= session; 697 } 698 699 703 public void stopRewriteSession(DocumentRewriteSession session) { 704 if (fActiveRewriteSession == session) 705 flushRewriteSession(); 706 } 707 708 712 public DocumentRewriteSession getActiveRewriteSession() { 713 return fActiveRewriteSession; 714 } 715 716 721 protected final void flushRewriteSession() { 722 fActiveRewriteSession= null; 723 724 try { 726 fDocument.removePositionCategory(fPositionCategory); 727 } catch (BadPositionCategoryException x) { 728 } 729 fDocument.addPositionCategory(fPositionCategory); 730 731 fIsInitialized= false; 732 } 733 } 734 | Popular Tags |