1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.corext.util;
15 import net.sourceforge.phpdt.core.ToolFactory;
16 import net.sourceforge.phpdt.core.formatter.DefaultCodeFormatterConstants;
17 import net.sourceforge.phpdt.internal.corext.Assert;
18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
20 import org.eclipse.core.runtime.Preferences;
21 import org.eclipse.jface.text.BadLocationException;
22 import org.eclipse.jface.text.BadPositionCategoryException;
23 import org.eclipse.jface.text.DefaultPositionUpdater;
24 import org.eclipse.jface.text.Document;
25 import org.eclipse.jface.text.Position;
26 import org.eclipse.text.edits.DeleteEdit;
27 import org.eclipse.text.edits.InsertEdit;
28 import org.eclipse.text.edits.MultiTextEdit;
29 import org.eclipse.text.edits.ReplaceEdit;
30 import org.eclipse.text.edits.TextEdit;
32 public class CodeFormatterUtil {
35 * Creates a string that represents the given number of indents (can be
38 public static String createIndentString(int indent) {
39 // axelcl change start
40 // String str= format(CodeFormatter.K_EXPRESSION, "x", indent, null, "",
41 // (Map) null); //$NON-NLS-1$ //$NON-NLS-2$
42 String str = ToolFactory.createCodeFormatter().format("x", indent,
44 return str.substring(0, str.indexOf('x'));
48 public static int getTabWidth() {
49 Preferences preferences = PHPeclipsePlugin.getDefault()
50 .getPluginPreferences();
52 .getInt(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE);
58 * Old API. Consider to use format2 (TextEdit)
60 // public static String format(int kind, String string, int
61 // indentationLevel, int[] positions, String lineSeparator, Map options) {
62 // return format(kind, string, 0, string.length(), indentationLevel,
63 // positions, lineSeparator, options);
66 // public static String format(int kind, String string, int
67 // indentationLevel, int[] positions, String lineSeparator, IJavaProject
69 // Map options= project != null ? project.getOptions(true) : null;
70 // return format(kind, string, 0, string.length(), indentationLevel,
71 // positions, lineSeparator, options);
75 * Old API. Consider to use format2 (TextEdit)
77 // public static String format(int kind, String string, int offset, int
78 // length, int indentationLevel, int[] positions, String lineSeparator, Map
80 // TextEdit edit= format2(kind, string, offset, length, indentationLevel,
81 // lineSeparator, options);
82 // if (edit == null) {
83 // //JavaPlugin.logErrorMessage("formatter failed to format (no edit
84 // returned). Will use unformatted text instead. kind: " + kind + ", string:
85 // " + string); //$NON-NLS-1$ //$NON-NLS-2$
86 // return string.substring(offset, offset + length);
88 // String formatted= getOldAPICompatibleResult(string, edit,
89 // indentationLevel, positions, lineSeparator, options);
90 // return formatted.substring(offset, formatted.length() - (string.length()
91 // - (offset + length)));
94 * Old API. Consider to use format2 (TextEdit)
96 // public static String format(ASTNode node, String string, int
97 // indentationLevel, int[] positions, String lineSeparator, Map options) {
99 // TextEdit edit= format2(node, string, indentationLevel, lineSeparator,
101 // if (edit == null) {
102 // //JavaPlugin.logErrorMessage("formatter failed to format (no edit
103 // returned). Will use unformatted text instead. node: " +
104 // node.getNodeType() + ", string: " + string); //$NON-NLS-1$ //$NON-NLS-2$
107 // return getOldAPICompatibleResult(string, edit, indentationLevel,
108 // positions, lineSeparator, options);
110 private static String getOldAPICompatibleResult(String string,
111 TextEdit edit, int indentationLevel, int[] positions,
112 String lineSeparator, Map options) {
115 if (positions != null) {
116 p = new Position[positions.length];
117 for (int i = 0; i < positions.length; i++) {
118 p[i] = new Position(positions[i], 0);
121 String res = evaluateFormatterEdit(string, edit, p);
123 if (positions != null) {
124 for (int i = 0; i < positions.length; i++) {
125 Position curr = p[i];
126 positions[i] = curr.getOffset();
133 * Evaluates the edit on the given string.
135 * @throws IllegalArgumentException
136 * If the positions are not inside the string, a
137 * IllegalArgumentException is thrown.
139 public static String evaluateFormatterEdit(String string, TextEdit edit,
140 Position[] positions) {
142 Document doc = createDocument(string, positions);
144 if (positions != null) {
145 for (int i = 0; i < positions.length; i++) {
146 Assert.isTrue(!positions[i].isDeleted,
147 "Position got deleted"); //$NON-NLS-1$
151 } catch (BadLocationException e) {
152 PHPeclipsePlugin.log(e); // bug in the formatter
156 "Fromatter created edits with wrong positions: " + e.getMessage()); //$NON-NLS-1$
162 * Creates edits that describe how to format the given string. Returns
163 * <code>null</code> if the code could not be formatted for the given
166 * @throws IllegalArgumentException
167 * If the offset and length are not inside the string, a
168 * IllegalArgumentException is thrown.
170 // public static TextEdit format2(int kind, String string, int offset, int
171 // length, int indentationLevel, String lineSeparator, Map options) {
172 // if (offset < 0 || length < 0 || offset + length > string.length()) {
173 // throw new IllegalArgumentException("offset or length outside of string.
174 // offset: " + offset + ", length: " + length + ", string size: " +
175 // string.length()); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
178 // return createCodeFormatter(options).format(kind, string, offset, length,
179 // indentationLevel, lineSeparator);
182 // public static TextEdit format2(int kind, String string, int
183 // indentationLevel, String lineSeparator, Map options) {
184 // return format2(kind, string, 0, string.length(), indentationLevel,
185 // lineSeparator, options);
188 * Creates edits that describe how to format the given string. Returns
189 * <code>null</code> if the code could not be formatted for the given
192 * @throws IllegalArgumentException
193 * If the offset and length are not inside the string, a
194 * IllegalArgumentException is thrown.
196 // public static TextEdit format2(ASTNode node, String str, int
197 // indentationLevel, String lineSeparator, Map options) {
199 // String prefix= ""; //$NON-NLS-1$
200 // String suffix= ""; //$NON-NLS-1$
201 // if (node instanceof Statement) {
202 // code= CodeFormatter.K_STATEMENTS;
203 // if (node.getNodeType() == ASTNode.SWITCH_CASE) {
204 // prefix= "switch(1) {"; //$NON-NLS-1$
205 // suffix= "}"; //$NON-NLS-1$
206 // code= CodeFormatter.K_STATEMENTS;
208 // } else if (node instanceof Expression && node.getNodeType() !=
209 // ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
210 // code= CodeFormatter.K_EXPRESSION;
212 // switch (node.getNodeType()) {
213 // case ASTNode.METHOD_DECLARATION:
214 // case ASTNode.TYPE_DECLARATION:
215 // case ASTNode.FIELD_DECLARATION:
216 // case ASTNode.INITIALIZER:
217 // code= CodeFormatter.K_CLASS_BODY_DECLARATIONS;
219 // case ASTNode.ARRAY_TYPE:
220 // case ASTNode.PRIMITIVE_TYPE:
221 // case ASTNode.SIMPLE_TYPE:
222 // suffix= " x;"; //$NON-NLS-1$
223 // code= CodeFormatter.K_EXPRESSION;
225 // case ASTNode.COMPILATION_UNIT:
226 // code= CodeFormatter.K_COMPILATION_UNIT;
228 // case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
229 // case ASTNode.SINGLE_VARIABLE_DECLARATION:
230 // suffix= ";"; //$NON-NLS-1$
231 // code= CodeFormatter.K_STATEMENTS;
233 // case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
234 // prefix= "A "; //$NON-NLS-1$
235 // suffix= ";"; //$NON-NLS-1$
236 // code= CodeFormatter.K_STATEMENTS;
238 // case ASTNode.PACKAGE_DECLARATION:
239 // case ASTNode.IMPORT_DECLARATION:
240 // suffix= "\nclass A {}"; //$NON-NLS-1$
241 // code= CodeFormatter.K_COMPILATION_UNIT;
243 // case ASTNode.JAVADOC:
244 // suffix= "void foo();"; //$NON-NLS-1$
245 // code= CodeFormatter.K_CLASS_BODY_DECLARATIONS;
247 // case ASTNode.CATCH_CLAUSE:
248 // prefix= "try {}"; //$NON-NLS-1$
249 // code= CodeFormatter.K_STATEMENTS;
251 // case ASTNode.ANONYMOUS_CLASS_DECLARATION:
252 // prefix= "new A()"; //$NON-NLS-1$
253 // suffix= ";"; //$NON-NLS-1$
254 // code= CodeFormatter.K_STATEMENTS;
256 // case ASTNode.MEMBER_REF:
257 // case ASTNode.METHOD_REF:
258 // case ASTNode.METHOD_REF_PARAMETER:
259 // case ASTNode.TAG_ELEMENT:
260 // case ASTNode.TEXT_ELEMENT:
261 // // not yet supported
264 // Assert.isTrue(false, "Node type not covered: " +
265 // node.getClass().getName()); //$NON-NLS-1$
270 // String concatStr= prefix + str + suffix;
271 // TextEdit edit= format2(code, concatStr, prefix.length(), str.length(),
272 // indentationLevel, lineSeparator, options);
273 // if (prefix.length() > 0) {
274 // edit= shifEdit(edit, prefix.length());
278 private static TextEdit shifEdit(TextEdit oldEdit, int diff) {
280 if (oldEdit instanceof ReplaceEdit) {
281 ReplaceEdit edit = (ReplaceEdit) oldEdit;
282 newEdit = new ReplaceEdit(edit.getOffset() - diff,
283 edit.getLength(), edit.getText());
284 } else if (oldEdit instanceof InsertEdit) {
285 InsertEdit edit = (InsertEdit) oldEdit;
286 newEdit = new InsertEdit(edit.getOffset() - diff, edit.getText());
287 } else if (oldEdit instanceof DeleteEdit) {
288 DeleteEdit edit = (DeleteEdit) oldEdit;
289 newEdit = new DeleteEdit(edit.getOffset() - diff, edit.getLength());
290 } else if (oldEdit instanceof MultiTextEdit) {
291 newEdit = new MultiTextEdit();
293 return null; // not supported
295 TextEdit[] children = oldEdit.getChildren();
296 for (int i = 0; i < children.length; i++) {
297 TextEdit shifted = shifEdit(children[i], diff);
298 if (shifted != null) {
299 newEdit.addChild(shifted);
305 private static Document createDocument(String string, Position[] positions)
306 throws IllegalArgumentException {
307 Document doc = new Document(string);
309 if (positions != null) {
310 final String POS_CATEGORY = "myCategory"; //$NON-NLS-1$
312 doc.addPositionCategory(POS_CATEGORY);
314 .addPositionUpdater(new DefaultPositionUpdater(
316 protected boolean notDeleted() {
317 if (fOffset < fPosition.offset
318 && (fPosition.offset + fPosition.length < fOffset
320 fPosition.offset = fOffset + fLength; // deleted
332 for (int i = 0; i < positions.length; i++) {
334 doc.addPosition(POS_CATEGORY, positions[i]);
335 } catch (BadLocationException e) {
336 throw new IllegalArgumentException(
337 "Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length()); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
341 } catch (BadPositionCategoryException cannotHappen) {
342 // can not happen: category is correctly set up