Mercurial > projects > dwt2
comparison org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/ContentFormatter.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 | 634e4380db78 |
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 | |
14 | |
15 module org.eclipse.jface.text.formatter.ContentFormatter; | |
16 | |
17 import org.eclipse.jface.text.formatter.MultiPassContentFormatter; // packageimport | |
18 import org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy; // packageimport | |
19 import org.eclipse.jface.text.formatter.FormattingContext; // packageimport | |
20 import org.eclipse.jface.text.formatter.IFormattingStrategy; // packageimport | |
21 import org.eclipse.jface.text.formatter.IContentFormatterExtension; // packageimport | |
22 import org.eclipse.jface.text.formatter.IFormattingStrategyExtension; // packageimport | |
23 import org.eclipse.jface.text.formatter.IContentFormatter; // packageimport | |
24 import org.eclipse.jface.text.formatter.FormattingContextProperties; // packageimport | |
25 import org.eclipse.jface.text.formatter.IFormattingContext; // packageimport | |
26 | |
27 import java.lang.all; | |
28 import java.util.Collections; | |
29 import java.util.List; | |
30 import java.util.ArrayList; | |
31 import java.util.Map; | |
32 import java.util.HashMap; | |
33 import java.util.Set; | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 import org.eclipse.core.runtime.Assert; | |
42 import org.eclipse.jface.text.BadLocationException; | |
43 import org.eclipse.jface.text.BadPositionCategoryException; | |
44 import org.eclipse.jface.text.DefaultPositionUpdater; | |
45 import org.eclipse.jface.text.DocumentEvent; | |
46 import org.eclipse.jface.text.IDocument; | |
47 import org.eclipse.jface.text.IDocumentExtension3; | |
48 import org.eclipse.jface.text.IPositionUpdater; | |
49 import org.eclipse.jface.text.IRegion; | |
50 import org.eclipse.jface.text.ITypedRegion; | |
51 import org.eclipse.jface.text.Position; | |
52 import org.eclipse.jface.text.TextUtilities; | |
53 import org.eclipse.jface.text.TypedPosition; | |
54 | |
55 | |
56 /** | |
57 * Standard implementation of <code>IContentFormatter</code>. | |
58 * The formatter supports two operation modes: partition aware and | |
59 * partition unaware. <p> | |
60 * In the partition aware mode, the formatter determines the | |
61 * partitioning of the document region to be formatted. For each | |
62 * partition it determines all document positions which are affected | |
63 * when text changes are applied to the partition. Those which overlap | |
64 * with the partition are remembered as character positions. These | |
65 * character positions are passed over to the formatting strategy | |
66 * registered for the partition's content type. The formatting strategy | |
67 * returns a string containing the formatted document partition as well | |
68 * as the adapted character positions. The formatted partition replaces | |
69 * the old content of the partition. The remembered document positions | |
70 * are updated with the adapted character positions. In addition, all | |
71 * other document positions are accordingly adapted to the formatting | |
72 * changes.<p> | |
73 * In the partition unaware mode, the document's partitioning is ignored | |
74 * and the document is considered consisting of only one partition of | |
75 * the content type <code>IDocument.DEFAULT_CONTENT_TYPE</code>. The | |
76 * formatting process is similar to the partition aware mode, with the | |
77 * exception of having only one partition.<p> | |
78 * Usually, clients instantiate this class and configure it before using it. | |
79 * | |
80 * @see IContentFormatter | |
81 * @see IDocument | |
82 * @see ITypedRegion | |
83 * @see Position | |
84 */ | |
85 public class ContentFormatter : IContentFormatter { | |
86 | |
87 /** | |
88 * Defines a reference to either the offset or the end offset of | |
89 * a particular position. | |
90 */ | |
91 static class PositionReference : Comparable { | |
92 | |
93 /** The referenced position */ | |
94 protected Position fPosition; | |
95 /** The reference to either the offset or the end offset */ | |
96 protected bool fRefersToOffset; | |
97 /** The original category of the referenced position */ | |
98 protected String fCategory; | |
99 | |
100 /** | |
101 * Creates a new position reference. | |
102 * | |
103 * @param position the position to be referenced | |
104 * @param refersToOffset <code>true</code> if position offset should be referenced | |
105 * @param category the category the given position belongs to | |
106 */ | |
107 protected this(Position position, bool refersToOffset, String category) { | |
108 fPosition= position; | |
109 fRefersToOffset= refersToOffset; | |
110 fCategory= category; | |
111 } | |
112 | |
113 /** | |
114 * Returns the offset of the referenced position. | |
115 * | |
116 * @return the offset of the referenced position | |
117 */ | |
118 protected int getOffset() { | |
119 return fPosition.getOffset(); | |
120 } | |
121 | |
122 /** | |
123 * Manipulates the offset of the referenced position. | |
124 * | |
125 * @param offset the new offset of the referenced position | |
126 */ | |
127 protected void setOffset(int offset) { | |
128 fPosition.setOffset(offset); | |
129 } | |
130 | |
131 /** | |
132 * Returns the length of the referenced position. | |
133 * | |
134 * @return the length of the referenced position | |
135 */ | |
136 protected int getLength() { | |
137 return fPosition.getLength(); | |
138 } | |
139 | |
140 /** | |
141 * Manipulates the length of the referenced position. | |
142 * | |
143 * @param length the new length of the referenced position | |
144 */ | |
145 protected void setLength(int length) { | |
146 fPosition.setLength(length); | |
147 } | |
148 | |
149 /** | |
150 * Returns whether this reference points to the offset or end offset | |
151 * of the references position. | |
152 * | |
153 * @return <code>true</code> if the offset of the position is referenced, <code>false</code> otherwise | |
154 */ | |
155 protected bool refersToOffset() { | |
156 return fRefersToOffset; | |
157 } | |
158 | |
159 /** | |
160 * Returns the category of the referenced position. | |
161 * | |
162 * @return the category of the referenced position | |
163 */ | |
164 protected String getCategory() { | |
165 return fCategory; | |
166 } | |
167 | |
168 /** | |
169 * Returns the referenced position. | |
170 * | |
171 * @return the referenced position | |
172 */ | |
173 protected Position getPosition() { | |
174 return fPosition; | |
175 } | |
176 | |
177 /** | |
178 * Returns the referenced character position | |
179 * | |
180 * @return the referenced character position | |
181 */ | |
182 protected int getCharacterPosition() { | |
183 if (fRefersToOffset) | |
184 return getOffset(); | |
185 return getOffset() + getLength(); | |
186 } | |
187 | |
188 /* | |
189 * @see Comparable#compareTo(Object) | |
190 */ | |
191 public int compareTo(Object obj) { | |
192 | |
193 if ( cast(PositionReference)obj ) { | |
194 PositionReference r= cast(PositionReference) obj; | |
195 return getCharacterPosition() - r.getCharacterPosition(); | |
196 } | |
197 | |
198 throw new ClassCastException(); | |
199 } | |
200 } | |
201 | |
202 /** | |
203 * The position updater used to update the remembered partitions. | |
204 * | |
205 * @see IPositionUpdater | |
206 * @see DefaultPositionUpdater | |
207 */ | |
208 class NonDeletingPositionUpdater : DefaultPositionUpdater { | |
209 | |
210 /** | |
211 * Creates a new updater for the given category. | |
212 * | |
213 * @param category the category | |
214 */ | |
215 protected this(String category) { | |
216 super(category); | |
217 } | |
218 | |
219 /* | |
220 * @see DefaultPositionUpdater#notDeleted() | |
221 */ | |
222 protected bool notDeleted() { | |
223 return true; | |
224 } | |
225 } | |
226 | |
227 /** | |
228 * The position updater which runs as first updater on the document's positions. | |
229 * Used to remove all affected positions from their categories to avoid them | |
230 * from being regularly updated. | |
231 * | |
232 * @see IPositionUpdater | |
233 */ | |
234 class RemoveAffectedPositions : IPositionUpdater { | |
235 /* | |
236 * @see IPositionUpdater#update(DocumentEvent) | |
237 */ | |
238 public void update(DocumentEvent event) { | |
239 removeAffectedPositions(event.getDocument()); | |
240 } | |
241 } | |
242 | |
243 /** | |
244 * The position updater which runs as last updater on the document's positions. | |
245 * Used to update all affected positions and adding them back to their | |
246 * original categories. | |
247 * | |
248 * @see IPositionUpdater | |
249 */ | |
250 class UpdateAffectedPositions : IPositionUpdater { | |
251 | |
252 /** The affected positions */ | |
253 private int[] fPositions; | |
254 /** The offset */ | |
255 private int fOffset; | |
256 | |
257 /** | |
258 * Creates a new updater. | |
259 * | |
260 * @param positions the affected positions | |
261 * @param offset the offset | |
262 */ | |
263 public this(int[] positions, int offset) { | |
264 fPositions= positions; | |
265 fOffset= offset; | |
266 } | |
267 | |
268 /* | |
269 * @see IPositionUpdater#update(DocumentEvent) | |
270 */ | |
271 public void update(DocumentEvent event) { | |
272 updateAffectedPositions(event.getDocument(), fPositions, fOffset); | |
273 } | |
274 } | |
275 | |
276 | |
277 /** Internal position category used for the formatter partitioning */ | |
278 private const static String PARTITIONING= "__formatter_partitioning"; //$NON-NLS-1$ | |
279 | |
280 /** The map of <code>IFormattingStrategy</code> objects */ | |
281 private Map fStrategies; | |
282 /** The indicator of whether the formatter operates in partition aware mode or not */ | |
283 private bool fIsPartitionAware= true; | |
284 | |
285 /** The partition information managing document position categories */ | |
286 private String[] fPartitionManagingCategories; | |
287 /** The list of references to offset and end offset of all overlapping positions */ | |
288 private List fOverlappingPositionReferences; | |
289 /** Position updater used for partitioning positions */ | |
290 private IPositionUpdater fPartitioningUpdater; | |
291 /** | |
292 * The document partitioning used by this formatter. | |
293 * @since 3.0 | |
294 */ | |
295 private String fPartitioning; | |
296 /** | |
297 * The document this formatter works on. | |
298 * @since 3.0 | |
299 */ | |
300 private IDocument fDocument; | |
301 /** | |
302 * The external partition managing categories. | |
303 * @since 3.0 | |
304 */ | |
305 private String[] fExternalPartitonManagingCategories; | |
306 /** | |
307 * Indicates whether <code>fPartitionManagingCategories</code> must be computed. | |
308 * @since 3.0 | |
309 */ | |
310 private bool fNeedsComputation= true; | |
311 | |
312 | |
313 /** | |
314 * Creates a new content formatter. The content formatter operates by default | |
315 * in the partition-aware mode. There are no preconfigured formatting strategies. | |
316 * Will use the default document partitioning if not further configured. | |
317 */ | |
318 public this() { | |
319 fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; | |
320 } | |
321 | |
322 /** | |
323 * Registers a strategy for a particular content type. If there is already a strategy | |
324 * registered for this type, the new strategy is registered instead of the old one. | |
325 * If the given content type is <code>null</code> the given strategy is registered for | |
326 * all content types as is called only once per formatting session. | |
327 * | |
328 * @param strategy the formatting strategy to register, or <code>null</code> to remove an existing one | |
329 * @param contentType the content type under which to register | |
330 */ | |
331 public void setFormattingStrategy(IFormattingStrategy strategy, String contentType) { | |
332 | |
333 Assert.isNotNull(contentType); | |
334 | |
335 if (fStrategies is null) | |
336 fStrategies= new HashMap(); | |
337 | |
338 if (strategy is null) | |
339 fStrategies.remove(contentType); | |
340 else | |
341 fStrategies.put(contentType, cast(Object)strategy); | |
342 } | |
343 | |
344 /** | |
345 * Informs this content formatter about the names of those position categories | |
346 * which are used to manage the document's partitioning information and thus should | |
347 * be ignored when this formatter updates positions. | |
348 * | |
349 * @param categories the categories to be ignored | |
350 * @deprecated incompatible with an open set of document partitionings. The provided information is only used | |
351 * if this formatter can not compute the partition managing position categories. | |
352 */ | |
353 public void setPartitionManagingPositionCategories(String[] categories) { | |
354 fExternalPartitonManagingCategories= TextUtilities.copy(categories); | |
355 } | |
356 | |
357 /** | |
358 * Sets the document partitioning to be used by this formatter. | |
359 * | |
360 * @param partitioning the document partitioning | |
361 * @since 3.0 | |
362 */ | |
363 public void setDocumentPartitioning(String partitioning) { | |
364 fPartitioning= partitioning; | |
365 } | |
366 | |
367 /** | |
368 * Sets the formatter's operation mode. | |
369 * | |
370 * @param enable indicates whether the formatting process should be partition ware | |
371 */ | |
372 public void enablePartitionAwareFormatting(bool enable) { | |
373 fIsPartitionAware= enable; | |
374 } | |
375 | |
376 /* | |
377 * @see IContentFormatter#getFormattingStrategy(String) | |
378 */ | |
379 public IFormattingStrategy getFormattingStrategy(String contentType) { | |
380 | |
381 Assert.isNotNull(contentType); | |
382 | |
383 if (fStrategies is null) | |
384 return null; | |
385 | |
386 return cast(IFormattingStrategy) fStrategies.get(contentType); | |
387 } | |
388 | |
389 /* | |
390 * @see IContentFormatter#format(IDocument, IRegion) | |
391 */ | |
392 public void format(IDocument document, IRegion region) { | |
393 fNeedsComputation= true; | |
394 fDocument= document; | |
395 try { | |
396 | |
397 if (fIsPartitionAware) | |
398 formatPartitions(region); | |
399 else | |
400 formatRegion(region); | |
401 | |
402 } finally { | |
403 fNeedsComputation= true; | |
404 fDocument= null; | |
405 } | |
406 } | |
407 | |
408 /** | |
409 * Determines the partitioning of the given region of the document. | |
410 * Informs the formatting strategies of each partition about the start, | |
411 * the process, and the termination of the formatting session. | |
412 * | |
413 * @param region the document region to be formatted | |
414 * @since 3.0 | |
415 */ | |
416 private void formatPartitions(IRegion region) { | |
417 | |
418 addPartitioningUpdater(); | |
419 | |
420 try { | |
421 | |
422 TypedPosition[] ranges= getPartitioning(region); | |
423 if (ranges !is null) { | |
424 start(ranges, getIndentation(region.getOffset())); | |
425 format(ranges); | |
426 stop(ranges); | |
427 } | |
428 | |
429 } catch (BadLocationException x) { | |
430 } | |
431 | |
432 removePartitioningUpdater(); | |
433 } | |
434 | |
435 /** | |
436 * Formats the given region with the strategy registered for the default | |
437 * content type. The strategy is informed about the start, the process, and | |
438 * the termination of the formatting session. | |
439 * | |
440 * @param region the region to be formatted | |
441 * @since 3.0 | |
442 */ | |
443 private void formatRegion(IRegion region) { | |
444 | |
445 IFormattingStrategy strategy= getFormattingStrategy(IDocument.DEFAULT_CONTENT_TYPE); | |
446 if (strategy !is null) { | |
447 strategy.formatterStarts(getIndentation(region.getOffset())); | |
448 format(strategy, new TypedPosition(region.getOffset(), region.getLength(), IDocument.DEFAULT_CONTENT_TYPE)); | |
449 strategy.formatterStops(); | |
450 } | |
451 } | |
452 | |
453 /** | |
454 * Returns the partitioning of the given region of the document to be formatted. | |
455 * As one partition after the other will be formatted and formatting will | |
456 * probably change the length of the formatted partition, it must be kept | |
457 * track of the modifications in order to submit the correct partition to all | |
458 * formatting strategies. For this, all partitions are remembered as positions | |
459 * in a dedicated position category. (As formatting strategies might rely on each | |
460 * other, calling them in reversed order is not an option.) | |
461 * | |
462 * @param region the region for which the partitioning must be determined | |
463 * @return the partitioning of the specified region | |
464 * @exception BadLocationException of region is invalid in the document | |
465 * @since 3.0 | |
466 */ | |
467 private TypedPosition[] getPartitioning(IRegion region) { | |
468 | |
469 ITypedRegion[] regions= TextUtilities.computePartitioning(fDocument, fPartitioning, region.getOffset(), region.getLength(), false); | |
470 TypedPosition[] positions= new TypedPosition[regions.length]; | |
471 | |
472 for (int i= 0; i < regions.length; i++) { | |
473 positions[i]= new TypedPosition(regions[i]); | |
474 try { | |
475 fDocument.addPosition(PARTITIONING, positions[i]); | |
476 } catch (BadPositionCategoryException x) { | |
477 // should not happen | |
478 } | |
479 } | |
480 | |
481 return positions; | |
482 } | |
483 | |
484 /** | |
485 * Fires <code>formatterStarts</code> to all formatter strategies | |
486 * which will be involved in the forthcoming formatting process. | |
487 * | |
488 * @param regions the partitioning of the document to be formatted | |
489 * @param indentation the initial indentation | |
490 */ | |
491 private void start(TypedPosition[] regions, String indentation) { | |
492 for (int i= 0; i < regions.length; i++) { | |
493 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); | |
494 if (s !is null) | |
495 s.formatterStarts(indentation); | |
496 } | |
497 } | |
498 | |
499 /** | |
500 * Formats one partition after the other using the formatter strategy registered for | |
501 * the partition's content type. | |
502 * | |
503 * @param ranges the partitioning of the document region to be formatted | |
504 * @since 3.0 | |
505 */ | |
506 private void format(TypedPosition[] ranges) { | |
507 for (int i= 0; i < ranges.length; i++) { | |
508 IFormattingStrategy s= getFormattingStrategy(ranges[i].getType()); | |
509 if (s !is null) { | |
510 format(s, ranges[i]); | |
511 } | |
512 } | |
513 } | |
514 | |
515 /** | |
516 * Formats the given region of the document using the specified formatting | |
517 * strategy. In order to maintain positions correctly, first all affected | |
518 * positions determined, after all document listeners have been informed about | |
519 * the coming change, the affected positions are removed to avoid that they | |
520 * are regularly updated. After all position updaters have run, the affected | |
521 * positions are updated with the formatter's information and added back to | |
522 * their categories, right before the first document listener is informed about | |
523 * that a change happened. | |
524 * | |
525 * @param strategy the strategy to be used | |
526 * @param region the region to be formatted | |
527 * @since 3.0 | |
528 */ | |
529 private void format(IFormattingStrategy strategy, TypedPosition region) { | |
530 try { | |
531 | |
532 final int offset= region.getOffset(); | |
533 int length= region.getLength(); | |
534 | |
535 String content= fDocument.get(offset, length); | |
536 final int[] positions= getAffectedPositions(offset, length); | |
537 String formatted= strategy.format(content, isLineStart(offset), getIndentation(offset), positions); | |
538 | |
539 if (formatted !is null && !formatted.equals(content)) { | |
540 | |
541 IPositionUpdater first= new RemoveAffectedPositions(); | |
542 fDocument.insertPositionUpdater(first, 0); | |
543 IPositionUpdater last= new UpdateAffectedPositions(positions, offset); | |
544 fDocument.addPositionUpdater(last); | |
545 | |
546 fDocument.replace(offset, length, formatted); | |
547 | |
548 fDocument.removePositionUpdater(first); | |
549 fDocument.removePositionUpdater(last); | |
550 } | |
551 | |
552 } catch (BadLocationException x) { | |
553 // should not happen | |
554 } | |
555 } | |
556 | |
557 /** | |
558 * Fires <code>formatterStops</code> to all formatter strategies which were | |
559 * involved in the formatting process which is about to terminate. | |
560 * | |
561 * @param regions the partitioning of the document which has been formatted | |
562 */ | |
563 private void stop(TypedPosition[] regions) { | |
564 for (int i= 0; i < regions.length; i++) { | |
565 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); | |
566 if (s !is null) | |
567 s.formatterStops(); | |
568 } | |
569 } | |
570 | |
571 /** | |
572 * Installs those updaters which the formatter needs to keep track of the partitions. | |
573 * @since 3.0 | |
574 */ | |
575 private void addPartitioningUpdater() { | |
576 fPartitioningUpdater= new NonDeletingPositionUpdater(PARTITIONING); | |
577 fDocument.addPositionCategory(PARTITIONING); | |
578 fDocument.addPositionUpdater(fPartitioningUpdater); | |
579 } | |
580 | |
581 /** | |
582 * Removes the formatter's internal position updater and category. | |
583 * | |
584 * @since 3.0 | |
585 */ | |
586 private void removePartitioningUpdater() { | |
587 | |
588 try { | |
589 | |
590 fDocument.removePositionUpdater(fPartitioningUpdater); | |
591 fDocument.removePositionCategory(PARTITIONING); | |
592 fPartitioningUpdater= null; | |
593 | |
594 } catch (BadPositionCategoryException x) { | |
595 // should not happen | |
596 } | |
597 } | |
598 | |
599 /** | |
600 * Returns the partition managing position categories for the formatted document. | |
601 * | |
602 * @return the position managing position categories | |
603 * @since 3.0 | |
604 */ | |
605 private String[] getPartitionManagingCategories() { | |
606 if (fNeedsComputation) { | |
607 fNeedsComputation= false; | |
608 fPartitionManagingCategories= TextUtilities.computePartitionManagingCategories(fDocument); | |
609 if (fPartitionManagingCategories is null) | |
610 fPartitionManagingCategories= fExternalPartitonManagingCategories; | |
611 } | |
612 return fPartitionManagingCategories; | |
613 } | |
614 | |
615 /** | |
616 * Determines whether the given document position category should be ignored | |
617 * by this formatter's position updating. | |
618 * | |
619 * @param category the category to check | |
620 * @return <code>true</code> if the category should be ignored, <code>false</code> otherwise | |
621 */ | |
622 private bool ignoreCategory(String category) { | |
623 | |
624 if (PARTITIONING.equals(category)) | |
625 return true; | |
626 | |
627 String[] categories= getPartitionManagingCategories(); | |
628 if (categories !is null) { | |
629 for (int i= 0; i < categories.length; i++) { | |
630 if (categories[i].equals(category)) | |
631 return true; | |
632 } | |
633 } | |
634 | |
635 return false; | |
636 } | |
637 | |
638 /** | |
639 * Determines all embracing, overlapping, and follow up positions | |
640 * for the given region of the document. | |
641 * | |
642 * @param offset the offset of the document region to be formatted | |
643 * @param length the length of the document to be formatted | |
644 * @since 3.0 | |
645 */ | |
646 private void determinePositionsToUpdate(int offset, int length) { | |
647 | |
648 String[] categories= fDocument.getPositionCategories(); | |
649 if (categories !is null) { | |
650 for (int i= 0; i < categories.length; i++) { | |
651 | |
652 if (ignoreCategory(categories[i])) | |
653 continue; | |
654 | |
655 try { | |
656 | |
657 Position[] positions= fDocument.getPositions(categories[i]); | |
658 | |
659 for (int j= 0; j < positions.length; j++) { | |
660 | |
661 Position p= positions[j]; | |
662 if (p.overlapsWith(offset, length)) { | |
663 | |
664 if (offset < p.getOffset()) | |
665 fOverlappingPositionReferences.add(new PositionReference(p, true, categories[i])); | |
666 | |
667 if (p.getOffset() + p.getLength() < offset + length) | |
668 fOverlappingPositionReferences.add(new PositionReference(p, false, categories[i])); | |
669 } | |
670 } | |
671 | |
672 } catch (BadPositionCategoryException x) { | |
673 // can not happen | |
674 } | |
675 } | |
676 } | |
677 } | |
678 | |
679 /** | |
680 * Returns all offset and the end offset of all positions overlapping with the | |
681 * specified document range. | |
682 * | |
683 * @param offset the offset of the document region to be formatted | |
684 * @param length the length of the document to be formatted | |
685 * @return all character positions of the interleaving positions | |
686 * @since 3.0 | |
687 */ | |
688 private int[] getAffectedPositions(int offset, int length) { | |
689 | |
690 fOverlappingPositionReferences= new ArrayList(); | |
691 | |
692 determinePositionsToUpdate(offset, length); | |
693 | |
694 Collections.sort(fOverlappingPositionReferences); | |
695 | |
696 int[] positions= new int[fOverlappingPositionReferences.size()]; | |
697 for (int i= 0; i < positions.length; i++) { | |
698 PositionReference r= cast(PositionReference) fOverlappingPositionReferences.get(i); | |
699 positions[i]= r.getCharacterPosition() - offset; | |
700 } | |
701 | |
702 return positions; | |
703 } | |
704 | |
705 /** | |
706 * Removes the affected positions from their categories to avoid | |
707 * that they are invalidly updated. | |
708 * | |
709 * @param document the document | |
710 */ | |
711 private void removeAffectedPositions(IDocument document) { | |
712 int size= fOverlappingPositionReferences.size(); | |
713 for (int i= 0; i < size; i++) { | |
714 PositionReference r= cast(PositionReference) fOverlappingPositionReferences.get(i); | |
715 try { | |
716 document.removePosition(r.getCategory(), r.getPosition()); | |
717 } catch (BadPositionCategoryException x) { | |
718 // can not happen | |
719 } | |
720 } | |
721 } | |
722 | |
723 /** | |
724 * Updates all the overlapping positions. Note, all other positions are | |
725 * automatically updated by their document position updaters. | |
726 * | |
727 * @param document the document to has been formatted | |
728 * @param positions the adapted character positions to be used to update the document positions | |
729 * @param offset the offset of the document region that has been formatted | |
730 */ | |
731 protected void updateAffectedPositions(IDocument document, int[] positions, int offset) { | |
732 | |
733 if (document !is fDocument) | |
734 return; | |
735 | |
736 if (positions.length is 0) | |
737 return; | |
738 | |
739 for (int i= 0; i < positions.length; i++) { | |
740 | |
741 PositionReference r= cast(PositionReference) fOverlappingPositionReferences.get(i); | |
742 | |
743 if (r.refersToOffset()) | |
744 r.setOffset(offset + positions[i]); | |
745 else | |
746 r.setLength((offset + positions[i]) - r.getOffset()); | |
747 | |
748 Position p= r.getPosition(); | |
749 String category= r.getCategory(); | |
750 if (!document.containsPosition(category, p.offset, p.length)) { | |
751 try { | |
752 if (positionAboutToBeAdded(document, category, p)) | |
753 document.addPosition(r.getCategory(), p); | |
754 } catch (BadPositionCategoryException x) { | |
755 // can not happen | |
756 } catch (BadLocationException x) { | |
757 // should not happen | |
758 } | |
759 } | |
760 | |
761 } | |
762 | |
763 fOverlappingPositionReferences= null; | |
764 } | |
765 | |
766 /** | |
767 * The given position is about to be added to the given position category of the given document. <p> | |
768 * This default implementation return <code>true</code>. | |
769 * | |
770 * @param document the document | |
771 * @param category the position category | |
772 * @param position the position that will be added | |
773 * @return <code>true</code> if the position can be added, <code>false</code> if it should be ignored | |
774 */ | |
775 protected bool positionAboutToBeAdded(IDocument document, String category, Position position) { | |
776 return true; | |
777 } | |
778 | |
779 /** | |
780 * Returns the indentation of the line of the given offset. | |
781 * | |
782 * @param offset the offset | |
783 * @return the indentation of the line of the offset | |
784 * @since 3.0 | |
785 */ | |
786 private String getIndentation(int offset) { | |
787 | |
788 try { | |
789 int start= fDocument.getLineOfOffset(offset); | |
790 start= fDocument.getLineOffset(start); | |
791 | |
792 int end= start; | |
793 char c= fDocument.getChar(end); | |
794 while ('\t' is c || ' ' is c) | |
795 c= fDocument.getChar(++end); | |
796 | |
797 return fDocument.get(start, end - start); | |
798 } catch (BadLocationException x) { | |
799 } | |
800 | |
801 return ""; //$NON-NLS-1$ | |
802 } | |
803 | |
804 /** | |
805 * Determines whether the offset is the beginning of a line in the given document. | |
806 * | |
807 * @param offset the offset | |
808 * @return <code>true</code> if offset is the beginning of a line | |
809 * @exception BadLocationException if offset is invalid in document | |
810 * @since 3.0 | |
811 */ | |
812 private bool isLineStart(int offset) { | |
813 int start= fDocument.getLineOfOffset(offset); | |
814 start= fDocument.getLineOffset(start); | |
815 return (start is offset); | |
816 } | |
817 } |