1 11 12 package org.eclipse.jdt.internal.ui.text.comment; 13 14 import java.util.LinkedList ; 15 import java.util.Map ; 16 17 import org.eclipse.text.edits.MalformedTreeException; 18 import org.eclipse.text.edits.TextEdit; 19 20 import org.eclipse.jface.text.BadLocationException; 21 import org.eclipse.jface.text.IDocument; 22 import org.eclipse.jface.text.TextUtilities; 23 import org.eclipse.jface.text.TypedPosition; 24 import org.eclipse.jface.text.formatter.ContextBasedFormattingStrategy; 25 import org.eclipse.jface.text.formatter.FormattingContextProperties; 26 import org.eclipse.jface.text.formatter.IFormattingContext; 27 28 import org.eclipse.jdt.core.JavaCore; 29 import org.eclipse.jdt.core.ToolFactory; 30 import org.eclipse.jdt.core.compiler.IScanner; 31 import org.eclipse.jdt.core.compiler.ITerminalSymbols; 32 import org.eclipse.jdt.core.compiler.InvalidInputException; 33 import org.eclipse.jdt.core.formatter.CodeFormatter; 34 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; 35 36 import org.eclipse.jdt.ui.text.IJavaPartitions; 37 38 import org.eclipse.jdt.internal.ui.JavaPlugin; 39 40 45 public class CommentFormattingStrategy extends ContextBasedFormattingStrategy { 46 47 48 private final LinkedList fDocuments= new LinkedList (); 49 50 51 private final LinkedList fPartitions= new LinkedList (); 52 53 54 private int fLastDocumentHash; 55 56 57 private int fLastHeaderHash; 58 59 60 private int fLastMainTokenEnd= -1; 61 62 63 private int fLastDocumentsHeaderEnd; 64 65 66 69 public void format() { 70 71 final IDocument document= (IDocument) fDocuments.getFirst(); 72 73 TextEdit edit= calculateTextEdit(); 74 if (edit == null) 75 return; 76 77 try { 78 edit.apply(document); 79 } catch (MalformedTreeException x) { 80 JavaPlugin.log(x); 81 } catch (BadLocationException x) { 82 JavaPlugin.log(x); 83 } 84 } 85 86 95 public TextEdit calculateTextEdit() { 96 super.format(); 97 98 final IDocument document= (IDocument) fDocuments.removeFirst(); 99 final TypedPosition position= (TypedPosition)fPartitions.removeFirst(); 100 if (document == null || position == null) 101 return null; 102 103 Map preferences= getPreferences(); 104 final boolean isFormattingHeader= DefaultCodeFormatterConstants.TRUE.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_HEADER)); 105 int documentsHeaderEnd= computeHeaderEnd(document, preferences); 106 107 TextEdit edit= null; 108 if (position.offset >= documentsHeaderEnd) { 109 try { 111 int sourceOffset= document.getLineOffset(document.getLineOfOffset(position.getOffset())); 113 114 int partitionOffset= position.getOffset() - sourceOffset; 116 int sourceLength= partitionOffset + position.getLength(); 117 String source= document.get(sourceOffset, sourceLength); 118 CodeFormatter commentFormatter= ToolFactory.createCodeFormatter(preferences, ToolFactory.M_FORMAT_EXISTING); 119 int indentationLevel= inferIndentationLevel(source.substring(0, partitionOffset), getTabSize(preferences), getIndentSize(preferences)); 120 edit= commentFormatter.format(getKindForPartitionType(position.getType()), source, partitionOffset, position.getLength(), indentationLevel, TextUtilities.getDefaultLineDelimiter(document)); 121 122 if (edit != null) 124 edit.moveTree(sourceOffset); 125 } catch (BadLocationException x) { 126 JavaPlugin.log(x); 127 } 128 } else if (isFormattingHeader) { 129 boolean wasJavaDoc= DefaultCodeFormatterConstants.TRUE.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_JAVADOC_COMMENT)); 130 if (!wasJavaDoc) 131 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_JAVADOC_COMMENT, DefaultCodeFormatterConstants.TRUE); 132 133 boolean wasBlockComment= DefaultCodeFormatterConstants.TRUE.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_BLOCK_COMMENT)); 134 if (!wasBlockComment) 135 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_BLOCK_COMMENT, DefaultCodeFormatterConstants.TRUE); 136 137 boolean wasLineComment= DefaultCodeFormatterConstants.TRUE.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_LINE_COMMENT)); 138 if (!wasLineComment) 139 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_LINE_COMMENT, DefaultCodeFormatterConstants.TRUE); 140 141 try { 142 int sourceOffset= document.getLineOffset(document.getLineOfOffset(position.getOffset())); 144 145 int partitionOffset= position.getOffset() - sourceOffset; 147 int sourceLength= partitionOffset + position.getLength(); 148 String source= document.get(sourceOffset, sourceLength); 149 CodeFormatter commentFormatter= ToolFactory.createCodeFormatter(preferences); 150 int indentationLevel= inferIndentationLevel(source.substring(0, partitionOffset), getTabSize(preferences), getIndentSize(preferences)); 151 edit= commentFormatter.format(getKindForPartitionType(position.getType()), source, partitionOffset, position.getLength(), indentationLevel, TextUtilities.getDefaultLineDelimiter(document)); 152 153 if (edit != null) 155 edit.moveTree(sourceOffset); 156 } catch (BadLocationException x) { 157 JavaPlugin.log(x); 158 } finally { 159 if (!wasJavaDoc) 160 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_JAVADOC_COMMENT, DefaultCodeFormatterConstants.FALSE); 161 if (!wasBlockComment) 162 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_BLOCK_COMMENT, DefaultCodeFormatterConstants.FALSE); 163 if (!wasLineComment) 164 preferences.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_LINE_COMMENT, DefaultCodeFormatterConstants.FALSE); 165 } 166 167 } 168 return edit; 169 } 170 171 174 public void formatterStarts(IFormattingContext context) { 175 super.formatterStarts(context); 176 177 fPartitions.addLast(context.getProperty(FormattingContextProperties.CONTEXT_PARTITION)); 178 fDocuments.addLast(context.getProperty(FormattingContextProperties.CONTEXT_MEDIUM)); 179 } 180 181 184 public void formatterStops() { 185 fPartitions.clear(); 186 fDocuments.clear(); 187 188 super.formatterStops(); 189 } 190 191 199 private static int getKindForPartitionType(String type) { 200 if (IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(type)) 201 return CodeFormatter.K_SINGLE_LINE_COMMENT; 202 if (IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) 203 return CodeFormatter.K_MULTI_LINE_COMMENT; 204 if (IJavaPartitions.JAVA_DOC.equals(type)) 205 return CodeFormatter.K_JAVA_DOC; 206 return CodeFormatter.K_UNKNOWN; 207 } 208 209 219 private int inferIndentationLevel(String reference, int tabSize, int indentSize) { 220 StringBuffer expanded= expandTabs(reference, tabSize); 221 222 int referenceWidth= expanded.length(); 223 if (tabSize == 0) 224 return referenceWidth; 225 226 int level= referenceWidth / indentSize; 227 if (referenceWidth % indentSize > 0) 228 level++; 229 return level; 230 } 231 232 240 private static StringBuffer expandTabs(String string, int tabSize) { 241 StringBuffer expanded= new StringBuffer (); 242 for (int i= 0, n= string.length(), chars= 0; i < n; i++) { 243 char ch= string.charAt(i); 244 if (ch == '\t') { 245 for (; chars < tabSize; chars++) 246 expanded.append(' '); 247 chars= 0; 248 } else { 249 expanded.append(ch); 250 chars++; 251 if (chars >= tabSize) 252 chars= 0; 253 } 254 255 } 256 return expanded; 257 } 258 259 266 private static int getTabSize(Map preferences) { 267 273 String key; 274 if (JavaCore.SPACE.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) 275 key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; 276 else 277 key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; 278 279 if (preferences.containsKey(key)) 280 try { 281 return Integer.parseInt((String ) preferences.get(key)); 282 } catch (NumberFormatException e) { 283 } 285 return 4; 286 } 287 288 295 private static int getIndentSize(Map preferences) { 296 300 String key; 301 if (DefaultCodeFormatterConstants.MIXED.equals(preferences.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) 302 key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; 303 else 304 key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; 305 306 if (preferences.containsKey(key)) 307 try { 308 return Integer.parseInt((String ) preferences.get(key)); 309 } catch (NumberFormatException e) { 310 } 312 return 4; 313 } 314 315 322 private int computeHeaderEnd(IDocument document, Map preferences) { 323 if (document == null) 324 return -1; 325 326 try { 327 if (fLastMainTokenEnd >= 0 && document.hashCode() == fLastDocumentHash && fLastMainTokenEnd < document.getLength() && document.get(0, fLastMainTokenEnd).hashCode() == fLastHeaderHash) 328 return fLastDocumentsHeaderEnd; 329 } catch (BadLocationException e) { 330 } 332 333 IScanner scanner= ToolFactory.createScanner(true, false, false, (String ) preferences.get(JavaCore.COMPILER_SOURCE), (String ) preferences.get(JavaCore.COMPILER_COMPLIANCE)); 334 scanner.setSource(document.get().toCharArray()); 335 336 try { 337 int offset= -1; 338 boolean foundComment= false; 339 int terminal= scanner.getNextToken(); 340 while (terminal != ITerminalSymbols.TokenNameEOF && !(terminal == ITerminalSymbols.TokenNameclass || terminal == ITerminalSymbols.TokenNameinterface || terminal == ITerminalSymbols.TokenNameenum || (foundComment && (terminal == ITerminalSymbols.TokenNameimport || terminal == ITerminalSymbols.TokenNamepackage)))) { 341 342 if (terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC) 343 offset= scanner.getCurrentTokenStartPosition(); 344 345 foundComment= terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC || terminal == ITerminalSymbols.TokenNameCOMMENT_BLOCK; 346 347 terminal= scanner.getNextToken(); 348 } 349 350 int mainTokenEnd= scanner.getCurrentTokenEndPosition(); 351 if (terminal != ITerminalSymbols.TokenNameEOF) { 352 mainTokenEnd++; 353 if (offset == -1 || (foundComment && (terminal == ITerminalSymbols.TokenNameimport || terminal == ITerminalSymbols.TokenNamepackage))) 354 offset= scanner.getCurrentTokenStartPosition(); 355 } else 356 offset= -1; 357 358 try { 359 fLastHeaderHash= document.get(0, mainTokenEnd).hashCode(); 360 } catch (BadLocationException e) { 361 mainTokenEnd= -1; 363 } 364 365 fLastDocumentHash= document.hashCode(); 366 fLastMainTokenEnd= mainTokenEnd; 367 fLastDocumentsHeaderEnd= offset; 368 return offset; 369 370 } catch (InvalidInputException ex) { 371 return -1; 373 } 374 } 375 } 376 | Popular Tags |