1 11 package org.eclipse.jdt.internal.corext.util; 12 13 import java.util.Map ; 14 15 import org.eclipse.text.edits.DeleteEdit; 16 import org.eclipse.text.edits.InsertEdit; 17 import org.eclipse.text.edits.MultiTextEdit; 18 import org.eclipse.text.edits.ReplaceEdit; 19 import org.eclipse.text.edits.TextEdit; 20 21 import org.eclipse.core.runtime.Assert; 22 23 import org.eclipse.jface.text.BadLocationException; 24 import org.eclipse.jface.text.BadPositionCategoryException; 25 import org.eclipse.jface.text.DefaultPositionUpdater; 26 import org.eclipse.jface.text.Document; 27 import org.eclipse.jface.text.Position; 28 29 import org.eclipse.jdt.core.IJavaProject; 30 import org.eclipse.jdt.core.JavaCore; 31 import org.eclipse.jdt.core.ToolFactory; 32 import org.eclipse.jdt.core.formatter.CodeFormatter; 33 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; 34 35 import org.eclipse.jdt.core.dom.ASTNode; 36 import org.eclipse.jdt.core.dom.BodyDeclaration; 37 import org.eclipse.jdt.core.dom.Expression; 38 import org.eclipse.jdt.core.dom.Statement; 39 40 import org.eclipse.jdt.internal.ui.JavaPlugin; 41 42 public class CodeFormatterUtil { 43 44 54 public static String createIndentString(int indentationUnits, IJavaProject project) { 55 Map options= project != null ? project.getOptions(true) : JavaCore.getOptions(); 56 return ToolFactory.createCodeFormatter(options).createIndentationString(indentationUnits); 57 } 58 59 67 public static int getTabWidth(IJavaProject project) { 68 74 String key; 75 if (JavaCore.SPACE.equals(getCoreOption(project, DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) 76 key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; 77 else 78 key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; 79 80 return getCoreOption(project, key, 4); 81 } 82 83 91 public static int getIndentWidth(IJavaProject project) { 92 String key; 93 if (DefaultCodeFormatterConstants.MIXED.equals(getCoreOption(project, DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) 94 key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; 95 else 96 key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; 97 98 return getCoreOption(project, key, 4); 99 } 100 101 111 private static String getCoreOption(IJavaProject project, String key) { 112 if (project == null) 113 return JavaCore.getOption(key); 114 return project.getOption(key, true); 115 } 116 117 129 private static int getCoreOption(IJavaProject project, String key, int def) { 130 try { 131 return Integer.parseInt(getCoreOption(project, key)); 132 } catch (NumberFormatException e) { 133 return def; 134 } 135 } 136 137 139 142 public static String format(int kind, String string, int indentationLevel, int[] positions, String lineSeparator, Map options) { 143 return format(kind, string, 0, string.length(), indentationLevel, positions, lineSeparator, options); 144 } 145 146 public static String format(int kind, String string, int indentationLevel, int[] positions, String lineSeparator, IJavaProject project) { 147 Map options= project != null ? project.getOptions(true) : null; 148 return format(kind, string, 0, string.length(), indentationLevel, positions, lineSeparator, options); 149 } 150 151 152 155 public static String format(int kind, String string, int offset, int length, int indentationLevel, int[] positions, String lineSeparator, Map options) { 156 TextEdit edit= format2(kind, string, offset, length, indentationLevel, lineSeparator, options); 157 if (edit == null) { 158 return string.substring(offset, offset + length); 160 } 161 String formatted= getOldAPICompatibleResult(string, edit, indentationLevel, positions, lineSeparator, options); 162 return formatted.substring(offset, formatted.length() - (string.length() - (offset + length))); 163 } 164 165 168 public static String format(ASTNode node, String string, int indentationLevel, int[] positions, String lineSeparator, Map options) { 169 170 TextEdit edit= format2(node, string, indentationLevel, lineSeparator, options); 171 if (edit == null) { 172 return string; 174 } 175 return getOldAPICompatibleResult(string, edit, indentationLevel, positions, lineSeparator, options); 176 } 177 178 private static String getOldAPICompatibleResult(String string, TextEdit edit, int indentationLevel, int[] positions, String lineSeparator, Map options) { 179 Position[] p= null; 180 181 if (positions != null) { 182 p= new Position[positions.length]; 183 for (int i= 0; i < positions.length; i++) { 184 p[i]= new Position(positions[i], 0); 185 } 186 } 187 String res= evaluateFormatterEdit(string, edit, p); 188 189 if (positions != null) { 190 for (int i= 0; i < positions.length; i++) { 191 Position curr= p[i]; 192 positions[i]= curr.getOffset(); 193 } 194 } 195 return res; 196 } 197 198 203 public static String evaluateFormatterEdit(String string, TextEdit edit, Position[] positions) { 204 try { 205 Document doc= createDocument(string, positions); 206 edit.apply(doc, 0); 207 if (positions != null) { 208 for (int i= 0; i < positions.length; i++) { 209 Assert.isTrue(!positions[i].isDeleted, "Position got deleted"); } 211 } 212 return doc.get(); 213 } catch (BadLocationException e) { 214 JavaPlugin.log(e); Assert.isTrue(false, "Formatter created edits with wrong positions: " + e.getMessage()); } 217 return null; 218 } 219 220 225 public static TextEdit format2(int kind, String string, int offset, int length, int indentationLevel, String lineSeparator, Map options) { 226 if (offset < 0 || length < 0 || offset + length > string.length()) { 227 throw new IllegalArgumentException ("offset or length outside of string. offset: " + offset + ", length: " + length + ", string size: " + string.length()); } 229 return ToolFactory.createCodeFormatter(options).format(kind, string, offset, length, indentationLevel, lineSeparator); 230 } 231 232 public static TextEdit format2(int kind, String string, int indentationLevel, String lineSeparator, Map options) { 233 return format2(kind, string, 0, string.length(), indentationLevel, lineSeparator, options); 234 } 235 236 public static TextEdit reformat(int kind, String string, int offset, int length, int indentationLevel, String lineSeparator, Map options) { 237 if (offset < 0 || length < 0 || offset + length > string.length()) { 238 throw new IllegalArgumentException ("offset or length outside of string. offset: " + offset + ", length: " + length + ", string size: " + string.length()); } 240 return ToolFactory.createCodeFormatter(options, ToolFactory.M_FORMAT_EXISTING).format(kind, string, offset, length, indentationLevel, lineSeparator); 241 } 242 243 public static TextEdit reformat(int kind, String string, int indentationLevel, String lineSeparator, Map options) { 244 return reformat(kind, string, 0, string.length(), indentationLevel, lineSeparator, options); 245 } 246 247 252 public static TextEdit format2(ASTNode node, String str, int indentationLevel, String lineSeparator, Map options) { 253 int code; 254 String prefix= ""; String suffix= ""; if (node instanceof Statement) { 257 code= CodeFormatter.K_STATEMENTS; 258 if (node.getNodeType() == ASTNode.SWITCH_CASE) { 259 prefix= "switch(1) {"; suffix= "}"; code= CodeFormatter.K_STATEMENTS; 262 } 263 } else if (node instanceof Expression && node.getNodeType() != ASTNode.VARIABLE_DECLARATION_EXPRESSION) { 264 code= CodeFormatter.K_EXPRESSION; 265 } else if (node instanceof BodyDeclaration) { 266 code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; 267 } else { 268 switch (node.getNodeType()) { 269 case ASTNode.ARRAY_TYPE: 270 case ASTNode.PARAMETERIZED_TYPE: 271 case ASTNode.PRIMITIVE_TYPE: 272 case ASTNode.QUALIFIED_TYPE: 273 case ASTNode.SIMPLE_TYPE: 274 suffix= " x;"; code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; 276 break; 277 case ASTNode.WILDCARD_TYPE: 278 prefix= "A<"; suffix= "> x;"; code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; 281 break; 282 case ASTNode.COMPILATION_UNIT: 283 code= CodeFormatter.K_COMPILATION_UNIT; 284 break; 285 case ASTNode.VARIABLE_DECLARATION_EXPRESSION: 286 case ASTNode.SINGLE_VARIABLE_DECLARATION: 287 suffix= ";"; code= CodeFormatter.K_STATEMENTS; 289 break; 290 case ASTNode.VARIABLE_DECLARATION_FRAGMENT: 291 prefix= "A "; suffix= ";"; code= CodeFormatter.K_STATEMENTS; 294 break; 295 case ASTNode.PACKAGE_DECLARATION: 296 case ASTNode.IMPORT_DECLARATION: 297 suffix= "\nclass A {}"; code= CodeFormatter.K_COMPILATION_UNIT; 299 break; 300 case ASTNode.JAVADOC: 301 suffix= "void foo();"; code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; 303 break; 304 case ASTNode.CATCH_CLAUSE: 305 prefix= "try {}"; code= CodeFormatter.K_STATEMENTS; 307 break; 308 case ASTNode.ANONYMOUS_CLASS_DECLARATION: 309 prefix= "new A()"; suffix= ";"; code= CodeFormatter.K_STATEMENTS; 312 break; 313 case ASTNode.MEMBER_VALUE_PAIR: 314 prefix= "@Author("; suffix= ") class x {}"; code= CodeFormatter.K_COMPILATION_UNIT; 317 break; 318 case ASTNode.MODIFIER: 319 suffix= " class x {}"; code= CodeFormatter.K_COMPILATION_UNIT; 321 break; 322 case ASTNode.TYPE_PARAMETER: 323 prefix= "class X<"; suffix= "> {}"; code= CodeFormatter.K_COMPILATION_UNIT; 326 break; 327 case ASTNode.MEMBER_REF: 328 case ASTNode.METHOD_REF: 329 case ASTNode.METHOD_REF_PARAMETER: 330 case ASTNode.TAG_ELEMENT: 331 case ASTNode.TEXT_ELEMENT: 332 return null; 334 default: 335 return null; 337 } 338 } 339 340 String concatStr= prefix + str + suffix; 341 TextEdit edit= ToolFactory.createCodeFormatter(options).format(code, concatStr, prefix.length(), str.length(), indentationLevel, lineSeparator); 342 if (prefix.length() > 0) { 343 edit= shifEdit(edit, prefix.length()); 344 } 345 return edit; 346 } 347 348 private static TextEdit shifEdit(TextEdit oldEdit, int diff) { 349 TextEdit newEdit; 350 if (oldEdit instanceof ReplaceEdit) { 351 ReplaceEdit edit= (ReplaceEdit) oldEdit; 352 newEdit= new ReplaceEdit(edit.getOffset() - diff, edit.getLength(), edit.getText()); 353 } else if (oldEdit instanceof InsertEdit) { 354 InsertEdit edit= (InsertEdit) oldEdit; 355 newEdit= new InsertEdit(edit.getOffset() - diff, edit.getText()); 356 } else if (oldEdit instanceof DeleteEdit) { 357 DeleteEdit edit= (DeleteEdit) oldEdit; 358 newEdit= new DeleteEdit(edit.getOffset() - diff, edit.getLength()); 359 } else if (oldEdit instanceof MultiTextEdit) { 360 newEdit= new MultiTextEdit(); 361 } else { 362 return null; } 364 TextEdit[] children= oldEdit.getChildren(); 365 for (int i= 0; i < children.length; i++) { 366 TextEdit shifted= shifEdit(children[i], diff); 367 if (shifted != null) { 368 newEdit.addChild(shifted); 369 } 370 } 371 return newEdit; 372 } 373 374 private static Document createDocument(String string, Position[] positions) throws IllegalArgumentException { 375 Document doc= new Document(string); 376 try { 377 if (positions != null) { 378 final String POS_CATEGORY= "myCategory"; 380 doc.addPositionCategory(POS_CATEGORY); 381 doc.addPositionUpdater(new DefaultPositionUpdater(POS_CATEGORY) { 382 protected boolean notDeleted() { 383 if (fOffset < fPosition.offset && (fPosition.offset + fPosition.length < fOffset + fLength)) { 384 fPosition.offset= fOffset + fLength; return false; 386 } 387 return true; 388 } 389 }); 390 for (int i= 0; i < positions.length; i++) { 391 try { 392 doc.addPosition(POS_CATEGORY, positions[i]); 393 } catch (BadLocationException e) { 394 throw new IllegalArgumentException ("Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length()); } 396 } 397 } 398 } catch (BadPositionCategoryException cannotHappen) { 399 } 401 return doc; 402 } 403 404 } 405 | Popular Tags |