comparison org.eclipse.jface.text/src/org/eclipse/jface/text/formatter/MultiPassContentFormatter.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
14
15 module org.eclipse.jface.text.formatter.MultiPassContentFormatter;
16
17 import org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy; // packageimport
18 import org.eclipse.jface.text.formatter.FormattingContext; // packageimport
19 import org.eclipse.jface.text.formatter.IFormattingStrategy; // packageimport
20 import org.eclipse.jface.text.formatter.IContentFormatterExtension; // packageimport
21 import org.eclipse.jface.text.formatter.IFormattingStrategyExtension; // packageimport
22 import org.eclipse.jface.text.formatter.IContentFormatter; // packageimport
23 import org.eclipse.jface.text.formatter.FormattingContextProperties; // packageimport
24 import org.eclipse.jface.text.formatter.ContentFormatter; // packageimport
25 import org.eclipse.jface.text.formatter.IFormattingContext; // packageimport
26
27 import java.lang.all;
28 import java.util.Map;
29 import java.util.HashMap;
30 import java.util.Set;
31
32 import org.eclipse.core.runtime.Assert;
33 import org.eclipse.jface.text.BadLocationException;
34 import org.eclipse.jface.text.DefaultPositionUpdater;
35 import org.eclipse.jface.text.IDocument;
36 import org.eclipse.jface.text.IRegion;
37 import org.eclipse.jface.text.ITypedRegion;
38 import org.eclipse.jface.text.TextUtilities;
39 import org.eclipse.jface.text.TypedPosition;
40
41 /**
42 * Content formatter for edit-based formatting strategies.
43 * <p>
44 * Two kinds of formatting strategies can be registered with this formatter:
45 * <ul>
46 * <li>one master formatting strategy for the default content type</li>
47 * <li>one formatting strategy for each non-default content type</li>
48 * </ul>
49 * The master formatting strategy always formats the whole region to be
50 * formatted in the first pass. In a second pass, all partitions of the region
51 * to be formatted that are not of master content type are formatted using the
52 * slave formatting strategy registered for the underlying content type. All
53 * formatting strategies must implement {@link IFormattingStrategyExtension}.
54 * <p>
55 * Regions to be formatted with the master formatting strategy always have
56 * an offset aligned to the line start. Regions to be formatted with slave formatting
57 * strategies are aligned on partition boundaries.
58 *
59 * @see IFormattingStrategyExtension
60 * @since 3.0
61 */
62 public class MultiPassContentFormatter : IContentFormatter, IContentFormatterExtension {
63
64 /**
65 * Position updater that shifts otherwise deleted positions to the next
66 * non-whitespace character. The length of the positions are truncated to
67 * one if the position was shifted.
68 */
69 protected class NonDeletingPositionUpdater : DefaultPositionUpdater {
70
71 /**
72 * Creates a new non-deleting position updater.
73 *
74 * @param category The position category to update its positions
75 */
76 public this(String category) {
77 super(category);
78 }
79
80 /*
81 * @see org.eclipse.jface.text.DefaultPositionUpdater#notDeleted()
82 */
83 protected final bool notDeleted() {
84
85 if (fOffset < fPosition.offset && (fPosition.offset + fPosition.length < fOffset + fLength)) {
86
87 int offset= fOffset + fLength;
88 if (offset < fDocument.getLength()) {
89
90 try {
91
92 bool moved= false;
93 char character= fDocument.getChar(offset);
94
95 while (offset < fDocument.getLength() && Character.isWhitespace(character)) {
96
97 moved= true;
98 character= fDocument.getChar(offset++);
99 }
100
101 if (moved)
102 offset--;
103
104 } catch (BadLocationException exception) {
105 // Can not happen
106 }
107
108 fPosition.offset= offset;
109 fPosition.length= 0;
110 }
111 }
112 return true;
113 }
114 }
115
116 /** The master formatting strategy */
117 private IFormattingStrategyExtension fMaster= null;
118 /** The partitioning of this content formatter */
119 private const String fPartitioning;
120 /** The slave formatting strategies */
121 private const Map fSlaves;
122 /** The default content type */
123 private const String fType;
124
125 /**
126 * Creates a new content formatter.
127 *
128 * @param partitioning the document partitioning for this formatter
129 * @param type the default content type
130 */
131 public this(String partitioning, String type) {
132 fSlaves= new HashMap();
133
134 fPartitioning= partitioning;
135 fType= type;
136 }
137
138 /*
139 * @see org.eclipse.jface.text.formatter.IContentFormatterExtension#format(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.formatter.IFormattingContext)
140 */
141 public final void format(IDocument medium, IFormattingContext context) {
142
143 context.setProperty(stringcast(FormattingContextProperties.CONTEXT_MEDIUM), cast(Object)medium);
144
145 final Boolean document= cast(Boolean)context.getProperty(stringcast(FormattingContextProperties.CONTEXT_DOCUMENT));
146 if (document is null || !document.booleanValue()) {
147
148 final IRegion region= cast(IRegion)context.getProperty(stringcast(FormattingContextProperties.CONTEXT_REGION));
149 if (region !is null) {
150 try {
151 formatMaster(context, medium, region.getOffset(), region.getLength());
152 } finally {
153 formatSlaves(context, medium, region.getOffset(), region.getLength());
154 }
155 }
156 } else {
157 try {
158 formatMaster(context, medium, 0, medium.getLength());
159 } finally {
160 formatSlaves(context, medium, 0, medium.getLength());
161 }
162 }
163 }
164
165 /*
166 * @see org.eclipse.jface.text.formatter.IContentFormatter#format(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion)
167 */
168 public final void format(IDocument medium, IRegion region) {
169
170 final FormattingContext context= new FormattingContext();
171
172 context.setProperty(stringcast(FormattingContextProperties.CONTEXT_DOCUMENT), Boolean.FALSE);
173 context.setProperty(stringcast(FormattingContextProperties.CONTEXT_REGION), cast(Object)region);
174
175 format(medium, context);
176 }
177
178 /**
179 * Formats the document specified in the formatting context with the master
180 * formatting strategy.
181 * <p>
182 * The master formatting strategy covers all regions of the document. The
183 * offset of the region to be formatted is aligned on line start boundaries,
184 * whereas the end index of the region remains the same. For this formatting
185 * type the document partitioning is not taken into account.
186 *
187 * @param context The formatting context to use
188 * @param document The document to operate on
189 * @param offset The offset of the region to format
190 * @param length The length of the region to format
191 */
192 protected void formatMaster(IFormattingContext context, IDocument document, int offset, int length) {
193
194 try {
195
196 final int delta= offset - document.getLineInformationOfOffset(offset).getOffset();
197 offset -= delta;
198 length += delta;
199
200 } catch (BadLocationException exception) {
201 // Do nothing
202 }
203
204 if (fMaster !is null) {
205
206 context.setProperty(stringcast(FormattingContextProperties.CONTEXT_PARTITION), new TypedPosition(offset, length, fType));
207
208 fMaster.formatterStarts(context);
209 fMaster.format();
210 fMaster.formatterStops();
211 }
212 }
213
214 /**
215 * Formats the document specified in the formatting context with the
216 * formatting strategy registered for the content type.
217 * <p>
218 * For this formatting type only slave strategies are used. The region to be
219 * formatted is aligned on partition boundaries of the underlying content
220 * type. The exact formatting strategy is determined by the underlying
221 * content type of the document partitioning.
222 *
223 * @param context The formatting context to use
224 * @param document The document to operate on
225 * @param offset The offset of the region to format
226 * @param length The length of the region to format
227 * @param type The content type of the region to format
228 */
229 protected void formatSlave(IFormattingContext context, IDocument document, int offset, int length, String type) {
230
231 final IFormattingStrategyExtension strategy= cast(IFormattingStrategyExtension)fSlaves.get(type);
232 if (strategy !is null) {
233
234 context.setProperty(stringcast(FormattingContextProperties.CONTEXT_PARTITION), new TypedPosition(offset, length, type));
235
236 strategy.formatterStarts(context);
237 strategy.format();
238 strategy.formatterStops();
239 }
240 }
241
242 /**
243 * Formats the document specified in the formatting context with the slave
244 * formatting strategies.
245 * <p>
246 * For each content type of the region to be formatted in the document
247 * partitioning, the registered slave formatting strategy is used to format
248 * that particular region. The region to be formatted is aligned on
249 * partition boundaries of the underlying content type. If the content type
250 * is the document's default content type, nothing happens.
251 *
252 * @param context The formatting context to use
253 * @param document The document to operate on
254 * @param offset The offset of the region to format
255 * @param length The length of the region to format
256 */
257 protected void formatSlaves(IFormattingContext context, IDocument document, int offset, int length) {
258
259 Map partitioners= new HashMap(0);
260 try {
261
262 final ITypedRegion[] partitions= TextUtilities.computePartitioning(document, fPartitioning, offset, length, false);
263
264 if (!fType.equals(partitions[0].getType()))
265 partitions[0]= TextUtilities.getPartition(document, fPartitioning, partitions[0].getOffset(), false);
266
267 if (partitions.length > 1) {
268
269 if (!fType.equals(partitions[partitions.length - 1].getType()))
270 partitions[partitions.length - 1]= TextUtilities.getPartition(document, fPartitioning, partitions[partitions.length - 1].getOffset(), false);
271 }
272
273 String type= null;
274 ITypedRegion partition= null;
275
276 partitioners= TextUtilities.removeDocumentPartitioners(document);
277
278 for (int index= partitions.length - 1; index >= 0; index--) {
279
280 partition= partitions[index];
281 type= partition.getType();
282
283 if (!fType.equals(type))
284 formatSlave(context, document, partition.getOffset(), partition.getLength(), type);
285 }
286
287 } catch (BadLocationException exception) {
288 // Should not happen
289 } finally {
290 TextUtilities.addDocumentPartitioners(document, partitioners);
291 }
292 }
293
294 /*
295 * @see org.eclipse.jface.text.formatter.IContentFormatter#getFormattingStrategy(java.lang.String)
296 */
297 public final IFormattingStrategy getFormattingStrategy(String type) {
298 return null;
299 }
300
301 /**
302 * Registers a master formatting strategy.
303 * <p>
304 * The strategy may already be registered with a certain content type as
305 * slave strategy. The master strategy is registered for the default content
306 * type of documents. If a master strategy has already been registered, it
307 * is overridden by the new one.
308 *
309 * @param strategy The master formatting strategy, must implement
310 * {@link IFormattingStrategyExtension}
311 */
312 public final void setMasterStrategy(IFormattingStrategy strategy) {
313 Assert.isTrue( null !is cast(IFormattingStrategyExtension)strategy );
314 fMaster= cast(IFormattingStrategyExtension) strategy;
315 }
316
317 /**
318 * Registers a slave formatting strategy for a certain content type.
319 * <p>
320 * The strategy may already be registered as master strategy. An
321 * already registered slave strategy for the specified content type
322 * will be replaced. However, the same strategy may be registered with
323 * several content types. Slave strategies cannot be registered for the
324 * default content type of documents.
325 *
326 * @param strategy The slave formatting strategy
327 * @param type The content type to register this strategy with,
328 * must implement {@link IFormattingStrategyExtension}
329 */
330 public final void setSlaveStrategy(IFormattingStrategy strategy, String type) {
331 Assert.isTrue( null !is cast(IFormattingStrategyExtension)strategy );
332 if (!fType.equals(type))
333 fSlaves.put(type, cast(Object)strategy);
334 }
335 }