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 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package net.sourceforge.phpdt.internal.corext.util; 12 13 import java.util.Map; 14 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; 19 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; 31 32 public class CodeFormatterUtil { 33 34 /** 35 * Creates a string that represents the given number of indents (can be 36 * spaces or tabs..) 37 */ createIndentString(int indent)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, 43 null, ""); 44 return str.substring(0, str.indexOf('x')); 45 // axelcl change end 46 } 47 getTabWidth()48 public static int getTabWidth() { 49 Preferences preferences = PHPeclipsePlugin.getDefault() 50 .getPluginPreferences(); 51 return preferences 52 .getInt(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE); 53 } 54 55 // transition code 56 57 /** 58 * Old API. Consider to use format2 (TextEdit) 59 */ 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); 64 // } 65 // 66 // public static String format(int kind, String string, int 67 // indentationLevel, int[] positions, String lineSeparator, IJavaProject 68 // project) { 69 // Map options= project != null ? project.getOptions(true) : null; 70 // return format(kind, string, 0, string.length(), indentationLevel, 71 // positions, lineSeparator, options); 72 // } 73 74 /** 75 * Old API. Consider to use format2 (TextEdit) 76 */ 77 // public static String format(int kind, String string, int offset, int 78 // length, int indentationLevel, int[] positions, String lineSeparator, Map 79 // options) { 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); 87 // } 88 // String formatted= getOldAPICompatibleResult(string, edit, 89 // indentationLevel, positions, lineSeparator, options); 90 // return formatted.substring(offset, formatted.length() - (string.length() 91 // - (offset + length))); 92 // } 93 /** 94 * Old API. Consider to use format2 (TextEdit) 95 */ 96 // public static String format(ASTNode node, String string, int 97 // indentationLevel, int[] positions, String lineSeparator, Map options) { 98 // 99 // TextEdit edit= format2(node, string, indentationLevel, lineSeparator, 100 // options); 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$ 105 // return string; 106 // } 107 // return getOldAPICompatibleResult(string, edit, indentationLevel, 108 // positions, lineSeparator, options); 109 // } getOldAPICompatibleResult(String string, TextEdit edit, int indentationLevel, int[] positions, String lineSeparator, Map options)110 private static String getOldAPICompatibleResult(String string, 111 TextEdit edit, int indentationLevel, int[] positions, 112 String lineSeparator, Map options) { 113 Position[] p = null; 114 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); 119 } 120 } 121 String res = evaluateFormatterEdit(string, edit, p); 122 123 if (positions != null) { 124 for (int i = 0; i < positions.length; i++) { 125 Position curr = p[i]; 126 positions[i] = curr.getOffset(); 127 } 128 } 129 return res; 130 } 131 132 /** 133 * Evaluates the edit on the given string. 134 * 135 * @throws IllegalArgumentException 136 * If the positions are not inside the string, a 137 * IllegalArgumentException is thrown. 138 */ evaluateFormatterEdit(String string, TextEdit edit, Position[] positions)139 public static String evaluateFormatterEdit(String string, TextEdit edit, 140 Position[] positions) { 141 try { 142 Document doc = createDocument(string, positions); 143 edit.apply(doc, 0); 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$ 148 } 149 } 150 return doc.get(); 151 } catch (BadLocationException e) { 152 PHPeclipsePlugin.log(e); // bug in the formatter 153 Assert 154 .isTrue( 155 false, 156 "Fromatter created edits with wrong positions: " + e.getMessage()); //$NON-NLS-1$ 157 } 158 return null; 159 } 160 161 /** 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 164 * kind. 165 * 166 * @throws IllegalArgumentException 167 * If the offset and length are not inside the string, a 168 * IllegalArgumentException is thrown. 169 */ 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$ 176 // } 177 // 178 // return createCodeFormatter(options).format(kind, string, offset, length, 179 // indentationLevel, lineSeparator); 180 // 181 // } 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); 186 // } 187 /** 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 190 * kind. 191 * 192 * @throws IllegalArgumentException 193 * If the offset and length are not inside the string, a 194 * IllegalArgumentException is thrown. 195 */ 196 // public static TextEdit format2(ASTNode node, String str, int 197 // indentationLevel, String lineSeparator, Map options) { 198 // int code; 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; 207 // } 208 // } else if (node instanceof Expression && node.getNodeType() != 209 // ASTNode.VARIABLE_DECLARATION_EXPRESSION) { 210 // code= CodeFormatter.K_EXPRESSION; 211 // } else { 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; 218 // break; 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; 224 // break; 225 // case ASTNode.COMPILATION_UNIT: 226 // code= CodeFormatter.K_COMPILATION_UNIT; 227 // break; 228 // case ASTNode.VARIABLE_DECLARATION_EXPRESSION: 229 // case ASTNode.SINGLE_VARIABLE_DECLARATION: 230 // suffix= ";"; //$NON-NLS-1$ 231 // code= CodeFormatter.K_STATEMENTS; 232 // break; 233 // case ASTNode.VARIABLE_DECLARATION_FRAGMENT: 234 // prefix= "A "; //$NON-NLS-1$ 235 // suffix= ";"; //$NON-NLS-1$ 236 // code= CodeFormatter.K_STATEMENTS; 237 // break; 238 // case ASTNode.PACKAGE_DECLARATION: 239 // case ASTNode.IMPORT_DECLARATION: 240 // suffix= "\nclass A {}"; //$NON-NLS-1$ 241 // code= CodeFormatter.K_COMPILATION_UNIT; 242 // break; 243 // case ASTNode.JAVADOC: 244 // suffix= "void foo();"; //$NON-NLS-1$ 245 // code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; 246 // break; 247 // case ASTNode.CATCH_CLAUSE: 248 // prefix= "try {}"; //$NON-NLS-1$ 249 // code= CodeFormatter.K_STATEMENTS; 250 // break; 251 // case ASTNode.ANONYMOUS_CLASS_DECLARATION: 252 // prefix= "new A()"; //$NON-NLS-1$ 253 // suffix= ";"; //$NON-NLS-1$ 254 // code= CodeFormatter.K_STATEMENTS; 255 // break; 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 262 // return null; 263 // default: 264 // Assert.isTrue(false, "Node type not covered: " + 265 // node.getClass().getName()); //$NON-NLS-1$ 266 // return null; 267 // } 268 // } 269 // 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()); 275 // } 276 // return edit; 277 // } shifEdit(TextEdit oldEdit, int diff)278 private static TextEdit shifEdit(TextEdit oldEdit, int diff) { 279 TextEdit newEdit; 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(); 292 } else { 293 return null; // not supported 294 } 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); 300 } 301 } 302 return newEdit; 303 } 304 createDocument(String string, Position[] positions)305 private static Document createDocument(String string, Position[] positions) 306 throws IllegalArgumentException { 307 Document doc = new Document(string); 308 try { 309 if (positions != null) { 310 final String POS_CATEGORY = "myCategory"; //$NON-NLS-1$ 311 312 doc.addPositionCategory(POS_CATEGORY); 313 doc 314 .addPositionUpdater(new DefaultPositionUpdater( 315 POS_CATEGORY) { 316 protected boolean notDeleted() { 317 if (fOffset < fPosition.offset 318 && (fPosition.offset + fPosition.length < fOffset 319 + fLength)) { 320 fPosition.offset = fOffset + fLength; // deleted 321 // positions: 322 // set 323 // to 324 // end 325 // of 326 // remove 327 return false; 328 } 329 return true; 330 } 331 }); 332 for (int i = 0; i < positions.length; i++) { 333 try { 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$ 338 } 339 } 340 } 341 } catch (BadPositionCategoryException cannotHappen) { 342 // can not happen: category is correctly set up 343 } 344 return doc; 345 } 346 347 } 348