1 11 12 package org.eclipse.jface.text.rules; 13 14 15 import java.util.ArrayList ; 16 import java.util.List ; 17 18 import org.eclipse.core.runtime.Assert; 19 20 import org.eclipse.jface.text.BadLocationException; 21 import org.eclipse.jface.text.BadPositionCategoryException; 22 import org.eclipse.jface.text.DefaultPositionUpdater; 23 import org.eclipse.jface.text.DocumentEvent; 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.IRegion; 29 import org.eclipse.jface.text.ITypedRegion; 30 import org.eclipse.jface.text.Position; 31 import org.eclipse.jface.text.Region; 32 import org.eclipse.jface.text.TextUtilities; 33 import org.eclipse.jface.text.TypedPosition; 34 import org.eclipse.jface.text.TypedRegion; 35 36 37 38 51 public class RuleBasedPartitioner implements IDocumentPartitioner, IDocumentPartitionerExtension, IDocumentPartitionerExtension2 { 52 53 57 public final static String CONTENT_TYPES_CATEGORY= "__content_types_category"; 59 60 61 protected RuleBasedScanner 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 82 83 90 public RuleBasedPartitioner(RuleBasedScanner scanner, String [] legalContentTypes) { 91 fScanner= scanner; 92 fLegalContentTypes= TextUtilities.copy(legalContentTypes); 93 fPositionCategory= CONTENT_TYPES_CATEGORY + hashCode(); 94 fPositionUpdater= new DefaultPositionUpdater(fPositionCategory); 95 } 96 97 101 public String [] getManagingPositionCategories() { 102 return new String [] { fPositionCategory }; 103 } 104 105 108 public void connect(IDocument document) { 109 Assert.isNotNull(document); 110 Assert.isTrue(!document.containsPositionCategory(fPositionCategory)); 111 112 fDocument= document; 113 fDocument.addPositionCategory(fPositionCategory); 114 115 initialize(); 116 } 117 118 121 protected void initialize() { 122 123 fScanner.setRange(fDocument, 0, fDocument.getLength()); 124 125 try { 126 IToken token= fScanner.nextToken(); 127 while (!token.isEOF()) { 128 129 String contentType= getTokenContentType(token); 130 131 if (isSupportedContentType(contentType)) { 132 TypedPosition p= new TypedPosition(fScanner.getTokenOffset(), fScanner.getTokenLength(), contentType); 133 fDocument.addPosition(fPositionCategory, p); 134 } 135 136 token= fScanner.nextToken(); 137 } 138 } catch (BadLocationException x) { 139 } catch (BadPositionCategoryException x) { 141 } 143 } 144 145 148 public void disconnect() { 149 150 Assert.isTrue(fDocument.containsPositionCategory(fPositionCategory)); 151 152 try { 153 fDocument.removePositionCategory(fPositionCategory); 154 } catch (BadPositionCategoryException x) { 155 } 157 } 158 159 162 public void documentAboutToBeChanged(DocumentEvent e) { 163 164 Assert.isTrue(e.getDocument() == fDocument); 165 166 fPreviousDocumentLength= e.getDocument().getLength(); 167 fStartOffset= -1; 168 fEndOffset= -1; 169 fDeleteOffset= -1; 170 } 171 172 175 public boolean documentChanged(DocumentEvent e) { 176 IRegion region= documentChanged2(e); 177 return (region != null); 178 } 179 180 189 private void rememberRegion(int offset, int length) { 190 if (fStartOffset == -1) 192 fStartOffset= offset; 193 else if (offset < fStartOffset) 194 fStartOffset= offset; 195 196 int endOffset= offset + length; 198 if (fEndOffset == -1) 199 fEndOffset= endOffset; 200 else if (endOffset > fEndOffset) 201 fEndOffset= endOffset; 202 } 203 204 209 private void rememberDeletedOffset(int offset) { 210 fDeleteOffset= offset; 211 } 212 213 218 private IRegion createRegion() { 219 if (fDeleteOffset == -1) { 220 if (fStartOffset == -1 || fEndOffset == -1) 221 return null; 222 return new Region(fStartOffset, fEndOffset - fStartOffset); 223 } else if (fStartOffset == -1 || fEndOffset == -1) { 224 return new Region(fDeleteOffset, 0); 225 } else { 226 int offset= Math.min(fDeleteOffset, fStartOffset); 227 int endOffset= Math.max(fDeleteOffset, fEndOffset); 228 return new Region(offset, endOffset - offset); 229 } 230 } 231 232 236 public IRegion documentChanged2(DocumentEvent e) { 237 238 try { 239 240 IDocument d= e.getDocument(); 241 Position[] category= d.getPositions(fPositionCategory); 242 int first= 0; 243 int reparseStart= 0; 244 int originalSize= category.length; 245 246 if (originalSize > 0) { 247 248 252 253 first= d.computeIndexInCategory(fPositionCategory, e.getOffset()); 254 255 Position p= null; 256 do { 257 --first; 258 if (first < 0) 259 break; 260 261 p= category[first]; 262 263 } while (p.overlapsWith(e.getOffset(), e.getLength()) || 264 (e.getOffset() == fPreviousDocumentLength && 265 (p.getOffset() + p.getLength() == fPreviousDocumentLength))); 266 267 fPositionUpdater.update(e); 268 for (int i= 0; i < category.length; i++) { 269 p= category[i]; 270 if (p.isDeleted) { 271 rememberDeletedOffset(e.getOffset()); 272 break; 273 } 274 } 275 category= d.getPositions(fPositionCategory); 276 277 if (first >= 0) { 278 p= category[first]; 279 reparseStart= p.getOffset() + p.getLength(); 280 } 281 282 ++first; 283 } 284 285 fScanner.setRange(d, reparseStart, d.getLength() - reparseStart); 286 287 int lastScannedPosition= reparseStart; 288 IToken token= fScanner.nextToken(); 289 290 while (!token.isEOF()) { 291 292 293 String contentType= getTokenContentType(token); 294 295 if (!isSupportedContentType(contentType)) { 296 token= fScanner.nextToken(); 297 continue; 298 } 299 300 int start= fScanner.getTokenOffset(); 301 int length= fScanner.getTokenLength(); 302 303 lastScannedPosition= start + length - 1; 304 305 while (first < category.length) { 307 TypedPosition p= (TypedPosition) category[first]; 308 if (lastScannedPosition >= p.offset + p.length || 309 (p.overlapsWith(start, length) && 310 (!d.containsPosition(fPositionCategory, start, length) || 311 !contentType.equals(p.getType())))) { 312 313 rememberRegion(p.offset, p.length); 314 d.removePosition(fPositionCategory, p); 315 ++ first; 316 317 } else 318 break; 319 } 320 321 if (d.containsPosition(fPositionCategory, start, length)) 323 return createRegion(); 324 325 try { 327 d.addPosition(fPositionCategory, new TypedPosition(start, length, contentType)); 328 rememberRegion(start, length); 329 } catch (BadPositionCategoryException x) { 330 } catch (BadLocationException x) { 331 } 332 333 token= fScanner.nextToken(); 334 } 335 336 337 if (lastScannedPosition != reparseStart) { 339 ++ lastScannedPosition; 341 } 342 first= d.computeIndexInCategory(fPositionCategory, lastScannedPosition); 343 344 TypedPosition p; 345 while (first < category.length) { 346 p= (TypedPosition) category[first++]; 347 d.removePosition(fPositionCategory, p); 348 rememberRegion(p.offset, p.length); 349 } 350 351 } catch (BadPositionCategoryException x) { 352 } catch (BadLocationException x) { 354 } 355 356 return createRegion(); 357 } 358 359 360 370 protected TypedPosition findClosestPosition(int offset) { 371 372 try { 373 374 int index= fDocument.computeIndexInCategory(fPositionCategory, offset); 375 Position[] category= fDocument.getPositions(fPositionCategory); 376 377 if (category.length == 0) 378 return null; 379 380 if (index < category.length) { 381 if (offset == category[index].offset) 382 return (TypedPosition) category[index]; 383 } 384 385 if (index > 0) 386 index--; 387 388 return (TypedPosition) category[index]; 389 390 } catch (BadPositionCategoryException x) { 391 } catch (BadLocationException x) { 392 } 393 394 return null; 395 } 396 397 398 401 public String getContentType(int offset) { 402 403 TypedPosition p= findClosestPosition(offset); 404 if (p != null && p.includes(offset)) 405 return p.getType(); 406 407 return IDocument.DEFAULT_CONTENT_TYPE; 408 } 409 410 413 public ITypedRegion getPartition(int offset) { 414 415 try { 416 417 Position[] category = fDocument.getPositions(fPositionCategory); 418 419 if (category == null || category.length == 0) 420 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE); 421 422 int index= fDocument.computeIndexInCategory(fPositionCategory, offset); 423 424 if (index < category.length) { 425 426 TypedPosition next= (TypedPosition) category[index]; 427 428 if (offset == next.offset) 429 return new TypedRegion(next.getOffset(), next.getLength(), next.getType()); 430 431 if (index == 0) 432 return new TypedRegion(0, next.offset, IDocument.DEFAULT_CONTENT_TYPE); 433 434 TypedPosition previous= (TypedPosition) category[index - 1]; 435 if (previous.includes(offset)) 436 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType()); 437 438 int endOffset= previous.getOffset() + previous.getLength(); 439 return new TypedRegion(endOffset, next.getOffset() - endOffset, IDocument.DEFAULT_CONTENT_TYPE); 440 } 441 442 TypedPosition previous= (TypedPosition) category[category.length - 1]; 443 if (previous.includes(offset)) 444 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType()); 445 446 int endOffset= previous.getOffset() + previous.getLength(); 447 return new TypedRegion(endOffset, fDocument.getLength() - endOffset, IDocument.DEFAULT_CONTENT_TYPE); 448 449 } catch (BadPositionCategoryException x) { 450 } catch (BadLocationException x) { 451 } 452 453 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE); 454 } 455 456 459 public ITypedRegion[] computePartitioning(int offset, int length) { 460 return computePartitioning(offset, length, false); 461 } 462 463 466 public String [] getLegalContentTypes() { 467 return TextUtilities.copy(fLegalContentTypes); 468 } 469 470 476 protected boolean isSupportedContentType(String contentType) { 477 if (contentType != null) { 478 for (int i= 0; i < fLegalContentTypes.length; i++) { 479 if (fLegalContentTypes[i].equals(contentType)) 480 return true; 481 } 482 } 483 484 return false; 485 } 486 487 495 protected String getTokenContentType(IToken token) { 496 Object data= token.getData(); 497 if (data instanceof String ) 498 return (String ) data; 499 return null; 500 } 501 502 503 504 508 public String getContentType(int offset, boolean preferOpenPartitions) { 509 return getPartition(offset, preferOpenPartitions).getType(); 510 } 511 512 516 public ITypedRegion getPartition(int offset, boolean preferOpenPartitions) { 517 ITypedRegion region= getPartition(offset); 518 if (preferOpenPartitions) { 519 if (region.getOffset() == offset && !region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) { 520 if (offset > 0) { 521 region= getPartition(offset - 1); 522 if (region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) 523 return region; 524 } 525 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE); 526 } 527 } 528 return region; 529 } 530 531 535 public ITypedRegion[] computePartitioning(int offset, int length, boolean includeZeroLengthPartitions) { 536 List list= new ArrayList (); 537 538 try { 539 540 int endOffset= offset + length; 541 542 Position[] category= fDocument.getPositions(fPositionCategory); 543 544 TypedPosition previous= null, current= null; 545 int start, end, gapOffset; 546 Position gap= null; 547 548 for (int i= 0; i < category.length; i++) { 549 550 current= (TypedPosition) category[i]; 551 552 gapOffset= (previous != null) ? previous.getOffset() + previous.getLength() : 0; 553 gap= new Position(gapOffset, current.getOffset() - gapOffset); 554 if ((includeZeroLengthPartitions || gap.getLength() > 0) && gap.overlapsWith(offset, length)) { 555 start= Math.max(offset, gapOffset); 556 end= Math.min(endOffset, gap.getOffset() + gap.getLength()); 557 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE)); 558 } 559 560 if (current.overlapsWith(offset, length)) { 561 start= Math.max(offset, current.getOffset()); 562 end= Math.min(endOffset, current.getOffset() + current.getLength()); 563 list.add(new TypedRegion(start, end - start, current.getType())); 564 } 565 566 previous= current; 567 } 568 569 if (previous != null) { 570 gapOffset= previous.getOffset() + previous.getLength(); 571 gap= new Position(gapOffset, fDocument.getLength() - gapOffset); 572 if ((includeZeroLengthPartitions || gap.getLength() > 0) && ((includeZeroLengthPartitions && offset + length == gapOffset && gap.length == 0) || gap.overlapsWith(offset, length))) { 573 start= Math.max(offset, gapOffset); 574 end= Math.min(endOffset, fDocument.getLength()); 575 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE)); 576 } 577 } 578 579 if (list.isEmpty()) 580 list.add(new TypedRegion(offset, length, IDocument.DEFAULT_CONTENT_TYPE)); 581 582 } catch (BadPositionCategoryException x) { 583 } 584 585 TypedRegion[] result= new TypedRegion[list.size()]; 586 list.toArray(result); 587 return result; 588 } 589 } 590 | Popular Tags |