comparison org.eclipse.jface.text/src/org/eclipse/jface/text/rules/DefaultPartitioner.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
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2006 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.rules.DefaultPartitioner;
14
15 import org.eclipse.jface.text.rules.FastPartitioner; // packageimport
16 import org.eclipse.jface.text.rules.ITokenScanner; // packageimport
17 import org.eclipse.jface.text.rules.Token; // packageimport
18 import org.eclipse.jface.text.rules.RuleBasedScanner; // packageimport
19 import org.eclipse.jface.text.rules.EndOfLineRule; // packageimport
20 import org.eclipse.jface.text.rules.WordRule; // packageimport
21 import org.eclipse.jface.text.rules.WhitespaceRule; // packageimport
22 import org.eclipse.jface.text.rules.WordPatternRule; // packageimport
23 import org.eclipse.jface.text.rules.IPredicateRule; // packageimport
24 import org.eclipse.jface.text.rules.NumberRule; // packageimport
25 import org.eclipse.jface.text.rules.SingleLineRule; // packageimport
26 import org.eclipse.jface.text.rules.PatternRule; // packageimport
27 import org.eclipse.jface.text.rules.RuleBasedDamagerRepairer; // packageimport
28 import org.eclipse.jface.text.rules.ICharacterScanner; // packageimport
29 import org.eclipse.jface.text.rules.IRule; // packageimport
30 import org.eclipse.jface.text.rules.DefaultDamagerRepairer; // packageimport
31 import org.eclipse.jface.text.rules.IToken; // packageimport
32 import org.eclipse.jface.text.rules.IPartitionTokenScanner; // packageimport
33 import org.eclipse.jface.text.rules.MultiLineRule; // packageimport
34 import org.eclipse.jface.text.rules.RuleBasedPartitioner; // packageimport
35 import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; // packageimport
36 import org.eclipse.jface.text.rules.BufferedRuleBasedScanner; // packageimport
37 import org.eclipse.jface.text.rules.IWhitespaceDetector; // packageimport
38
39
40 import java.lang.all;
41 import java.util.List;
42 import java.util.ArrayList;
43 import java.util.Set;
44
45
46
47
48 import org.eclipse.core.runtime.Assert;
49 import org.eclipse.jface.text.BadLocationException;
50 import org.eclipse.jface.text.BadPositionCategoryException;
51 import org.eclipse.jface.text.DefaultPositionUpdater;
52 import org.eclipse.jface.text.DocumentEvent;
53 import org.eclipse.jface.text.DocumentRewriteSession;
54 import org.eclipse.jface.text.IDocument;
55 import org.eclipse.jface.text.IDocumentPartitioner;
56 import org.eclipse.jface.text.IDocumentPartitionerExtension;
57 import org.eclipse.jface.text.IDocumentPartitionerExtension2;
58 import org.eclipse.jface.text.IDocumentPartitionerExtension3;
59 import org.eclipse.jface.text.IRegion;
60 import org.eclipse.jface.text.ITypedRegion;
61 import org.eclipse.jface.text.Position;
62 import org.eclipse.jface.text.Region;
63 import org.eclipse.jface.text.TextUtilities;
64 import org.eclipse.jface.text.TypedPosition;
65 import org.eclipse.jface.text.TypedRegion;
66
67
68
69 /**
70 * A standard implementation of a document partitioner. It uses a partition
71 * token scanner to scan the document and to determine the document's
72 * partitioning. The tokens returned by the scanner are supposed to return the
73 * partition type as their data. The partitioner remembers the document's
74 * partitions in the document itself rather than maintaining its own data
75 * structure.
76 *
77 * @see IPartitionTokenScanner
78 * @since 2.0
79 * @deprecated As of 3.1, replaced by {@link org.eclipse.jface.text.rules.FastPartitioner} instead
80 */
81 public class DefaultPartitioner : IDocumentPartitioner, IDocumentPartitionerExtension, IDocumentPartitionerExtension2, IDocumentPartitionerExtension3 {
82
83 /**
84 * The position category this partitioner uses to store the document's partitioning information.
85 * @deprecated As of 3.0, use <code>getManagingPositionCategories()</code> instead.
86 */
87 public const static String CONTENT_TYPES_CATEGORY= "__content_types_category"; //$NON-NLS-1$
88
89
90 /** The partitioner's scanner */
91 protected IPartitionTokenScanner fScanner;
92 /** The legal content types of this partitioner */
93 protected String[] fLegalContentTypes;
94 /** The partitioner's document */
95 protected IDocument fDocument;
96 /** The document length before a document change occurred */
97 protected int fPreviousDocumentLength;
98 /** The position updater used to for the default updating of partitions */
99 protected DefaultPositionUpdater fPositionUpdater;
100 /** The offset at which the first changed partition starts */
101 protected int fStartOffset;
102 /** The offset at which the last changed partition ends */
103 protected int fEndOffset;
104 /**The offset at which a partition has been deleted */
105 protected int fDeleteOffset;
106 /**
107 * The position category this partitioner uses to store the document's partitioning information.
108 * @since 3.0
109 */
110 private String fPositionCategory;
111 /**
112 * The active document rewrite session.
113 * @since 3.1
114 */
115 private DocumentRewriteSession fActiveRewriteSession;
116 /**
117 * Flag indicating whether this partitioner has been initialized.
118 * @since 3.1
119 */
120 private bool fIsInitialized= false;
121
122 /**
123 * Creates a new partitioner that uses the given scanner and may return
124 * partitions of the given legal content types.
125 *
126 * @param scanner the scanner this partitioner is supposed to use
127 * @param legalContentTypes the legal content types of this partitioner
128 */
129 public this(IPartitionTokenScanner scanner, String[] legalContentTypes) {
130 fScanner= scanner;
131 fLegalContentTypes= TextUtilities.copy(legalContentTypes);
132 fPositionCategory= CONTENT_TYPES_CATEGORY ~ Integer.toString(toHash());
133 fPositionUpdater= new DefaultPositionUpdater(fPositionCategory);
134 }
135
136 /*
137 * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#getManagingPositionCategories()
138 * @since 3.0
139 */
140 public String[] getManagingPositionCategories() {
141 return [ fPositionCategory ];
142 }
143
144 /*
145 * @see org.eclipse.jface.text.IDocumentPartitioner#connect(org.eclipse.jface.text.IDocument)
146 */
147 public void connect(IDocument document) {
148 connect(document, false);
149 }
150
151 /*
152 * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#connect(org.eclipse.jface.text.IDocument, bool)
153 * @since 3.1
154 */
155 public void connect(IDocument document, bool delayInitialization) {
156 Assert.isNotNull(cast(Object)document);
157 Assert.isTrue(!document.containsPositionCategory(fPositionCategory));
158
159 fDocument= document;
160 fDocument.addPositionCategory(fPositionCategory);
161
162 fIsInitialized= false;
163 if (!delayInitialization)
164 checkInitialization();
165 }
166
167 /*
168 * @since 3.1
169 */
170 protected final void checkInitialization() {
171 if (!fIsInitialized)
172 initialize();
173 }
174
175 /**
176 * Performs the initial partitioning of the partitioner's document.
177 */
178 protected void initialize() {
179 fIsInitialized= true;
180 fScanner.setRange(fDocument, 0, fDocument.getLength());
181
182 try {
183 IToken token= fScanner.nextToken();
184 while (!token.isEOF()) {
185
186 String contentType= getTokenContentType(token);
187
188 if (isSupportedContentType(contentType)) {
189 TypedPosition p= new TypedPosition(fScanner.getTokenOffset(), fScanner.getTokenLength(), contentType);
190 fDocument.addPosition(fPositionCategory, p);
191 }
192
193 token= fScanner.nextToken();
194 }
195 } catch (BadLocationException x) {
196 // cannot happen as offsets come from scanner
197 } catch (BadPositionCategoryException x) {
198 // cannot happen if document has been connected before
199 }
200 }
201
202 /*
203 * @see IDocumentPartitioner#disconnect()
204 */
205 public void disconnect() {
206
207 Assert.isTrue(fDocument.containsPositionCategory(fPositionCategory));
208
209 try {
210 fDocument.removePositionCategory(fPositionCategory);
211 } catch (BadPositionCategoryException x) {
212 // can not happen because of Assert
213 }
214 }
215
216 /*
217 * @see IDocumentPartitioner#documentAboutToBeChanged(DocumentEvent)
218 */
219 public void documentAboutToBeChanged(DocumentEvent e) {
220 if (fIsInitialized) {
221
222 Assert.isTrue(e.getDocument() is fDocument);
223
224 fPreviousDocumentLength= e.getDocument().getLength();
225 fStartOffset= -1;
226 fEndOffset= -1;
227 fDeleteOffset= -1;
228 }
229 }
230
231 /*
232 * @see IDocumentPartitioner#documentChanged(DocumentEvent)
233 */
234 public bool documentChanged(DocumentEvent e) {
235 if (fIsInitialized) {
236 IRegion region= documentChanged2(e);
237 return (region !is null);
238 }
239 return false;
240 }
241
242 /**
243 * Helper method for tracking the minimal region containing all partition changes.
244 * If <code>offset</code> is smaller than the remembered offset, <code>offset</code>
245 * will from now on be remembered. If <code>offset + length</code> is greater than
246 * the remembered end offset, it will be remembered from now on.
247 *
248 * @param offset the offset
249 * @param length the length
250 */
251 private void rememberRegion(int offset, int length) {
252 // remember start offset
253 if (fStartOffset is -1)
254 fStartOffset= offset;
255 else if (offset < fStartOffset)
256 fStartOffset= offset;
257
258 // remember end offset
259 int endOffset= offset + length;
260 if (fEndOffset is -1)
261 fEndOffset= endOffset;
262 else if (endOffset > fEndOffset)
263 fEndOffset= endOffset;
264 }
265
266 /**
267 * Remembers the given offset as the deletion offset.
268 *
269 * @param offset the offset
270 */
271 private void rememberDeletedOffset(int offset) {
272 fDeleteOffset= offset;
273 }
274
275 /**
276 * Creates the minimal region containing all partition changes using the
277 * remembered offset, end offset, and deletion offset.
278 *
279 * @return the minimal region containing all the partition changes
280 */
281 private IRegion createRegion() {
282 if (fDeleteOffset is -1) {
283 if (fStartOffset is -1 || fEndOffset is -1)
284 return null;
285 return new Region(fStartOffset, fEndOffset - fStartOffset);
286 } else if (fStartOffset is -1 || fEndOffset is -1) {
287 return new Region(fDeleteOffset, 0);
288 } else {
289 int offset= Math.min(fDeleteOffset, fStartOffset);
290 int endOffset= Math.max(fDeleteOffset, fEndOffset);
291 return new Region(offset, endOffset - offset);
292 }
293 }
294
295 /*
296 * @see IDocumentPartitionerExtension#documentChanged2(DocumentEvent)
297 * @since 2.0
298 */
299 public IRegion documentChanged2(DocumentEvent e) {
300
301 if (!fIsInitialized)
302 return null;
303
304 try {
305
306 IDocument d= e.getDocument();
307 Position[] category= d.getPositions(fPositionCategory);
308 IRegion line= d.getLineInformationOfOffset(e.getOffset());
309 int reparseStart= line.getOffset();
310 int partitionStart= -1;
311 String contentType= null;
312 int newLength= e.getText() is null ? 0 : e.getText().length();
313
314 int first= d.computeIndexInCategory(fPositionCategory, reparseStart);
315 if (first > 0) {
316 TypedPosition partition= cast(TypedPosition) category[first - 1];
317 if (partition.includes(reparseStart)) {
318 partitionStart= partition.getOffset();
319 contentType= partition.getType();
320 if (e.getOffset() is partition.getOffset() + partition.getLength())
321 reparseStart= partitionStart;
322 -- first;
323 } else if (reparseStart is e.getOffset() && reparseStart is partition.getOffset() + partition.getLength()) {
324 partitionStart= partition.getOffset();
325 contentType= partition.getType();
326 reparseStart= partitionStart;
327 -- first;
328 } else {
329 partitionStart= partition.getOffset() + partition.getLength();
330 contentType= IDocument.DEFAULT_CONTENT_TYPE;
331 }
332 }
333
334 fPositionUpdater.update(e);
335 for (int i= first; i < category.length; i++) {
336 Position p= category[i];
337 if (p.isDeleted) {
338 rememberDeletedOffset(e.getOffset());
339 break;
340 }
341 }
342 category= d.getPositions(fPositionCategory);
343
344 fScanner.setPartialRange(d, reparseStart, d.getLength() - reparseStart, contentType, partitionStart);
345
346 int lastScannedPosition= reparseStart;
347 IToken token= fScanner.nextToken();
348
349 while (!token.isEOF()) {
350
351 contentType= getTokenContentType(token);
352
353 if (!isSupportedContentType(contentType)) {
354 token= fScanner.nextToken();
355 continue;
356 }
357
358 int start= fScanner.getTokenOffset();
359 int length= fScanner.getTokenLength();
360
361 lastScannedPosition= start + length - 1;
362
363 // remove all affected positions
364 while (first < category.length) {
365 TypedPosition p= cast(TypedPosition) category[first];
366 if (lastScannedPosition >= p.offset + p.length ||
367 (p.overlapsWith(start, length) &&
368 (!d.containsPosition(fPositionCategory, start, length) ||
369 !contentType.equals(p.getType())))) {
370
371 rememberRegion(p.offset, p.length);
372 d.removePosition(fPositionCategory, p);
373 ++ first;
374
375 } else
376 break;
377 }
378
379 // if position already exists and we have scanned at least the
380 // area covered by the event, we are done
381 if (d.containsPosition(fPositionCategory, start, length)) {
382 if (lastScannedPosition >= e.getOffset() + newLength)
383 return createRegion();
384 ++ first;
385 } else {
386 // insert the new type position
387 try {
388 d.addPosition(fPositionCategory, new TypedPosition(start, length, contentType));
389 rememberRegion(start, length);
390 } catch (BadPositionCategoryException x) {
391 } catch (BadLocationException x) {
392 }
393 }
394
395 token= fScanner.nextToken();
396 }
397
398
399 // remove all positions behind lastScannedPosition since there aren't any further types
400 if (lastScannedPosition !is reparseStart) {
401 // if this condition is not met, nothing has been scanned because of a deletion
402 ++ lastScannedPosition;
403 }
404 first= d.computeIndexInCategory(fPositionCategory, lastScannedPosition);
405 category= d.getPositions(fPositionCategory);
406
407 TypedPosition p;
408 while (first < category.length) {
409 p= cast(TypedPosition) category[first++];
410 d.removePosition(fPositionCategory, p);
411 rememberRegion(p.offset, p.length);
412 }
413
414 } catch (BadPositionCategoryException x) {
415 // should never happen on connected documents
416 } catch (BadLocationException x) {
417 }
418
419 return createRegion();
420 }
421
422
423 /**
424 * Returns the position in the partitoner's position category which is
425 * close to the given offset. This is, the position has either an offset which
426 * is the same as the given offset or an offset which is smaller than the given
427 * offset. This method profits from the knowledge that a partitioning is
428 * a ordered set of disjoint position.
429 *
430 * @param offset the offset for which to search the closest position
431 * @return the closest position in the partitioner's category
432 */
433 protected TypedPosition findClosestPosition(int offset) {
434
435 try {
436
437 int index= fDocument.computeIndexInCategory(fPositionCategory, offset);
438 Position[] category= fDocument.getPositions(fPositionCategory);
439
440 if (category.length is 0)
441 return null;
442
443 if (index < category.length) {
444 if (offset is category[index].offset)
445 return cast(TypedPosition) category[index];
446 }
447
448 if (index > 0)
449 index--;
450
451 return cast(TypedPosition) category[index];
452
453 } catch (BadPositionCategoryException x) {
454 } catch (BadLocationException x) {
455 }
456
457 return null;
458 }
459
460
461 /*
462 * @see IDocumentPartitioner#getContentType(int)
463 */
464 public String getContentType(int offset) {
465 checkInitialization();
466
467 TypedPosition p= findClosestPosition(offset);
468 if (p !is null && p.includes(offset))
469 return p.getType();
470
471 return IDocument.DEFAULT_CONTENT_TYPE;
472 }
473
474 /*
475 * @see IDocumentPartitioner#getPartition(int)
476 */
477 public ITypedRegion getPartition(int offset) {
478 checkInitialization();
479
480 try {
481
482 Position[] category = fDocument.getPositions(fPositionCategory);
483
484 if (category is null || category.length is 0)
485 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE);
486
487 int index= fDocument.computeIndexInCategory(fPositionCategory, offset);
488
489 if (index < category.length) {
490
491 TypedPosition next= cast(TypedPosition) category[index];
492
493 if (offset is next.offset)
494 return new TypedRegion(next.getOffset(), next.getLength(), next.getType());
495
496 if (index is 0)
497 return new TypedRegion(0, next.offset, IDocument.DEFAULT_CONTENT_TYPE);
498
499 TypedPosition previous= cast(TypedPosition) category[index - 1];
500 if (previous.includes(offset))
501 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType());
502
503 int endOffset= previous.getOffset() + previous.getLength();
504 return new TypedRegion(endOffset, next.getOffset() - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
505 }
506
507 TypedPosition previous= cast(TypedPosition) category[category.length - 1];
508 if (previous.includes(offset))
509 return new TypedRegion(previous.getOffset(), previous.getLength(), previous.getType());
510
511 int endOffset= previous.getOffset() + previous.getLength();
512 return new TypedRegion(endOffset, fDocument.getLength() - endOffset, IDocument.DEFAULT_CONTENT_TYPE);
513
514 } catch (BadPositionCategoryException x) {
515 } catch (BadLocationException x) {
516 }
517
518 return new TypedRegion(0, fDocument.getLength(), IDocument.DEFAULT_CONTENT_TYPE);
519 }
520
521 /*
522 * @see IDocumentPartitioner#computePartitioning(int, int)
523 */
524 public ITypedRegion[] computePartitioning(int offset, int length) {
525 return computePartitioning(offset, length, false);
526 }
527
528 /*
529 * @see IDocumentPartitioner#getLegalContentTypes()
530 */
531 public String[] getLegalContentTypes() {
532 return TextUtilities.copy(fLegalContentTypes);
533 }
534
535 /**
536 * Returns whether the given type is one of the legal content types.
537 *
538 * @param contentType the content type to check
539 * @return <code>true</code> if the content type is a legal content type
540 */
541 protected bool isSupportedContentType(String contentType) {
542 if (contentType !is null) {
543 for (int i= 0; i < fLegalContentTypes.length; i++) {
544 if (fLegalContentTypes[i].equals(contentType))
545 return true;
546 }
547 }
548
549 return false;
550 }
551
552 /**
553 * Returns a content type encoded in the given token. If the token's
554 * data is not <code>null</code> and a string it is assumed that
555 * it is the encoded content type.
556 *
557 * @param token the token whose content type is to be determined
558 * @return the token's content type
559 */
560 protected String getTokenContentType(IToken token) {
561 Object data= token.getData();
562 if ( auto str = cast(ArrayWrapperString)data )
563 return str.array;
564 return null;
565 }
566
567 /* zero-length partition support */
568
569 /*
570 * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#getContentType(int)
571 * @since 3.0
572 */
573 public String getContentType(int offset, bool preferOpenPartitions) {
574 return getPartition(offset, preferOpenPartitions).getType();
575 }
576
577 /*
578 * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#getPartition(int)
579 * @since 3.0
580 */
581 public ITypedRegion getPartition(int offset, bool preferOpenPartitions) {
582 ITypedRegion region= getPartition(offset);
583 if (preferOpenPartitions) {
584 if (region.getOffset() is offset && !region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) {
585 if (offset > 0) {
586 region= getPartition(offset - 1);
587 if (region.getType().equals(IDocument.DEFAULT_CONTENT_TYPE))
588 return region;
589 }
590 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE);
591 }
592 }
593 return region;
594 }
595
596 /*
597 * @see org.eclipse.jface.text.IDocumentPartitionerExtension2#computePartitioning(int, int, bool)
598 * @since 3.0
599 */
600 public ITypedRegion[] computePartitioning(int offset, int length, bool includeZeroLengthPartitions) {
601 checkInitialization();
602 List list= new ArrayList();
603
604 try {
605
606 int endOffset= offset + length;
607
608 Position[] category= fDocument.getPositions(fPositionCategory);
609
610 TypedPosition previous= null, current= null;
611 int start, end, gapOffset;
612 Position gap= new Position(0);
613
614 int startIndex= getFirstIndexEndingAfterOffset(category, offset);
615 int endIndex= getFirstIndexStartingAfterOffset(category, endOffset);
616 for (int i= startIndex; i < endIndex; i++) {
617
618 current= cast(TypedPosition) category[i];
619
620 gapOffset= (previous !is null) ? previous.getOffset() + previous.getLength() : 0;
621 gap.setOffset(gapOffset);
622 gap.setLength(current.getOffset() - gapOffset);
623 if ((includeZeroLengthPartitions && overlapsOrTouches(gap, offset, length)) ||
624 (gap.getLength() > 0 && gap.overlapsWith(offset, length))) {
625 start= Math.max(offset, gapOffset);
626 end= Math.min(endOffset, gap.getOffset() + gap.getLength());
627 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE));
628 }
629
630 if (current.overlapsWith(offset, length)) {
631 start= Math.max(offset, current.getOffset());
632 end= Math.min(endOffset, current.getOffset() + current.getLength());
633 list.add(new TypedRegion(start, end - start, current.getType()));
634 }
635
636 previous= current;
637 }
638
639 if (previous !is null) {
640 gapOffset= previous.getOffset() + previous.getLength();
641 gap.setOffset(gapOffset);
642 gap.setLength(fDocument.getLength() - gapOffset);
643 if ((includeZeroLengthPartitions && overlapsOrTouches(gap, offset, length)) ||
644 (gap.getLength() > 0 && gap.overlapsWith(offset, length))) {
645 start= Math.max(offset, gapOffset);
646 end= Math.min(endOffset, fDocument.getLength());
647 list.add(new TypedRegion(start, end - start, IDocument.DEFAULT_CONTENT_TYPE));
648 }
649 }
650
651 if (list.isEmpty())
652 list.add(new TypedRegion(offset, length, IDocument.DEFAULT_CONTENT_TYPE));
653
654 } catch (BadPositionCategoryException x) {
655 }
656
657 return arraycast!(ITypedRegion)(list.toArray());
658 }
659
660 /**
661 * Returns <code>true</code> if the given ranges overlap with or touch each other.
662 *
663 * @param gap the first range
664 * @param offset the offset of the second range
665 * @param length the length of the second range
666 * @return <code>true</code> if the given ranges overlap with or touch each other
667 * @since 3.0
668 */
669 private bool overlapsOrTouches(Position gap, int offset, int length) {
670 return gap.getOffset() <= offset + length && offset <= gap.getOffset() + gap.getLength();
671 }
672
673 /**
674 * Returns the index of the first position which ends after the given offset.
675 *
676 * @param positions the positions in linear order
677 * @param offset the offset
678 * @return the index of the first position which ends after the offset
679 *
680 * @since 3.0
681 */
682 private int getFirstIndexEndingAfterOffset(Position[] positions, int offset) {
683 int i= -1, j= positions.length;
684 while (j - i > 1) {
685 int k= (i + j) >> 1;
686 Position p= positions[k];
687 if (p.getOffset() + p.getLength() > offset)
688 j= k;
689 else
690 i= k;
691 }
692 return j;
693 }
694
695 /**
696 * Returns the index of the first position which starts at or after the given offset.
697 *
698 * @param positions the positions in linear order
699 * @param offset the offset
700 * @return the index of the first position which starts after the offset
701 *
702 * @since 3.0
703 */
704 private int getFirstIndexStartingAfterOffset(Position[] positions, int offset) {
705 int i= -1, j= positions.length;
706 while (j - i > 1) {
707 int k= (i + j) >> 1;
708 Position p= positions[k];
709 if (p.getOffset() >= offset)
710 j= k;
711 else
712 i= k;
713 }
714 return j;
715 }
716
717 /*
718 * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#startRewriteSession(org.eclipse.jface.text.DocumentRewriteSession)
719 * @since 3.1
720 */
721 public void startRewriteSession(DocumentRewriteSession session) {
722 if (fActiveRewriteSession !is null)
723 throw new IllegalStateException();
724 fActiveRewriteSession= session;
725 }
726
727 /*
728 * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#stopRewriteSession(org.eclipse.jface.text.DocumentRewriteSession)
729 * @since 3.1
730 */
731 public void stopRewriteSession(DocumentRewriteSession session) {
732 if (fActiveRewriteSession is session)
733 flushRewriteSession();
734 }
735
736 /*
737 * @see org.eclipse.jface.text.IDocumentPartitionerExtension3#getActiveRewriteSession()
738 * @since 3.1
739 */
740 public DocumentRewriteSession getActiveRewriteSession() {
741 return fActiveRewriteSession;
742 }
743
744 /**
745 * Flushes the active rewrite session.
746 *
747 * @since 3.1
748 */
749 protected final void flushRewriteSession() {
750 fActiveRewriteSession= null;
751
752 // remove all position belonging to the partitioner position category
753 try {
754 fDocument.removePositionCategory(fPositionCategory);
755 } catch (BadPositionCategoryException x) {
756 }
757 fDocument.addPositionCategory(fPositionCategory);
758
759 fIsInitialized= false;
760 }
761 }