Mercurial > projects > dwt2
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 } |