1 11 package org.eclipse.jdt.internal.corext.template.java; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 18 19 import org.eclipse.text.edits.MalformedTreeException; 20 import org.eclipse.text.edits.MultiTextEdit; 21 import org.eclipse.text.edits.RangeMarker; 22 import org.eclipse.text.edits.ReplaceEdit; 23 import org.eclipse.text.edits.TextEdit; 24 25 import org.eclipse.core.runtime.Assert; 26 27 import org.eclipse.jface.text.BadLocationException; 28 import org.eclipse.jface.text.BadPositionCategoryException; 29 import org.eclipse.jface.text.Document; 30 import org.eclipse.jface.text.IDocument; 31 import org.eclipse.jface.text.IRegion; 32 import org.eclipse.jface.text.Position; 33 import org.eclipse.jface.text.TypedPosition; 34 import org.eclipse.jface.text.rules.FastPartitioner; 35 import org.eclipse.jface.text.source.LineRange; 36 import org.eclipse.jface.text.templates.DocumentTemplateContext; 37 import org.eclipse.jface.text.templates.TemplateBuffer; 38 import org.eclipse.jface.text.templates.TemplateContext; 39 import org.eclipse.jface.text.templates.TemplateVariable; 40 41 import org.eclipse.jdt.core.IJavaProject; 42 import org.eclipse.jdt.core.JavaCore; 43 import org.eclipse.jdt.core.formatter.CodeFormatter; 44 45 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil; 46 47 import org.eclipse.jdt.ui.text.IJavaPartitions; 48 49 import org.eclipse.jdt.internal.ui.javaeditor.IndentUtil; 50 import org.eclipse.jdt.internal.ui.text.FastJavaPartitionScanner; 51 52 55 public class JavaFormatter { 56 57 private static final String COMMENT_START= "/*-"; private static final String COMMENT_END= "*/"; 60 61 private final String fLineDelimiter; 62 63 private final int fInitialIndentLevel; 64 65 66 private boolean fUseCodeFormatter; 67 private final IJavaProject fProject; 68 69 73 private static final class VariableTracker { 74 private static final String CATEGORY= "__template_variables"; private Document fDocument; 76 private final TemplateBuffer fBuffer; 77 private List fPositions; 78 79 86 public VariableTracker(TemplateBuffer buffer) throws MalformedTreeException, BadLocationException { 87 Assert.isLegal(buffer != null); 88 fBuffer= buffer; 89 fDocument= new Document(fBuffer.getString()); 90 installJavaStuff(fDocument); 91 fDocument.addPositionCategory(CATEGORY); 92 fDocument.addPositionUpdater(new ExclusivePositionUpdater(CATEGORY)); 93 fPositions= createRangeMarkers(fBuffer.getVariables(), fDocument); 94 } 95 96 101 private static void installJavaStuff(Document document) { 102 String [] types= new String [] { 103 IJavaPartitions.JAVA_DOC, 104 IJavaPartitions.JAVA_MULTI_LINE_COMMENT, 105 IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, 106 IJavaPartitions.JAVA_STRING, 107 IJavaPartitions.JAVA_CHARACTER, 108 IDocument.DEFAULT_CONTENT_TYPE 109 }; 110 FastPartitioner partitioner= new FastPartitioner(new FastJavaPartitionScanner(), types); 111 partitioner.connect(document); 112 document.setDocumentPartitioner(IJavaPartitions.JAVA_PARTITIONING, partitioner); 113 } 114 115 121 public IDocument getDocument() { 122 checkState(); 123 return fDocument; 124 } 125 126 private void checkState() { 127 if (fDocument == null) 128 throw new IllegalStateException (); 129 } 130 131 138 public TemplateBuffer updateBuffer() throws MalformedTreeException, BadLocationException { 139 checkState(); 140 TemplateVariable[] variables= fBuffer.getVariables(); 141 try { 142 removeRangeMarkers(fPositions, fDocument, variables); 143 } catch (BadPositionCategoryException x) { 144 Assert.isTrue(false); 145 } 146 fBuffer.setContent(fDocument.get(), variables); 147 fDocument= null; 148 149 return fBuffer; 150 } 151 152 private List createRangeMarkers(TemplateVariable[] variables, IDocument document) throws MalformedTreeException, BadLocationException { 153 Map markerToOriginal= new HashMap (); 154 155 MultiTextEdit root= new MultiTextEdit(0, document.getLength()); 156 List edits= new ArrayList (); 157 boolean hasModifications= false; 158 for (int i= 0; i != variables.length; i++) { 159 final TemplateVariable variable= variables[i]; 160 int[] offsets= variable.getOffsets(); 161 162 String value= variable.getDefaultValue(); 163 if (isWhitespaceVariable(value)) { 164 String placeholder= COMMENT_START + value + COMMENT_END; 166 for (int j= 0; j != offsets.length; j++) { 167 ReplaceEdit replace= new ReplaceEdit(offsets[j], value.length(), placeholder); 168 root.addChild(replace); 169 hasModifications= true; 170 markerToOriginal.put(replace, value); 171 edits.add(replace); 172 } 173 } else { 174 for (int j= 0; j != offsets.length; j++) { 175 RangeMarker marker= new RangeMarker(offsets[j], value.length()); 176 root.addChild(marker); 177 edits.add(marker); 178 } 179 } 180 } 181 182 if (hasModifications) { 183 root.apply(document, TextEdit.UPDATE_REGIONS); 185 } 186 187 List positions= new ArrayList (); 188 for (Iterator it= edits.iterator(); it.hasNext();) { 189 TextEdit edit= (TextEdit) it.next(); 190 try { 191 final TypedPosition pos= new TypedPosition(edit.getOffset(), edit.getLength(), (String ) markerToOriginal.get(edit)); 193 document.addPosition(CATEGORY, pos); 194 positions.add(pos); 195 } catch (BadPositionCategoryException x) { 196 Assert.isTrue(false); 197 } 198 } 199 200 return positions; 201 } 202 203 private boolean isWhitespaceVariable(String value) { 204 int length= value.length(); 205 return length == 0 || Character.isWhitespace(value.charAt(0)) || Character.isWhitespace(value.charAt(length - 1)); 206 } 207 208 private void removeRangeMarkers(List positions, IDocument document, TemplateVariable[] variables) throws MalformedTreeException, BadLocationException, BadPositionCategoryException { 209 210 for (Iterator it= positions.iterator(); it.hasNext();) { 212 TypedPosition position= (TypedPosition) it.next(); 213 document.removePosition(CATEGORY, position); 215 final String original= position.getType(); 216 if (original != null) { 217 document.replace(position.getOffset(), position.getLength(), original); 218 position.setLength(original.length()); 219 } 220 document.addPosition(position); 221 } 222 223 Iterator it= positions.iterator(); 224 for (int i= 0; i != variables.length; i++) { 225 TemplateVariable variable= variables[i]; 226 227 int[] offsets= new int[variable.getOffsets().length]; 228 for (int j= 0; j != offsets.length; j++) 229 offsets[j]= ((Position) it.next()).getOffset(); 230 231 variable.setOffsets(offsets); 232 } 233 234 } 235 } 236 237 245 public JavaFormatter(String lineDelimiter, int initialIndentLevel, boolean useCodeFormatter, IJavaProject project) { 246 fLineDelimiter= lineDelimiter; 247 fUseCodeFormatter= useCodeFormatter; 248 fInitialIndentLevel= initialIndentLevel; 249 fProject= project; 250 } 251 252 258 public void format(TemplateBuffer buffer, TemplateContext context) throws BadLocationException { 259 try { 260 VariableTracker tracker= new VariableTracker(buffer); 261 IDocument document= tracker.getDocument(); 262 263 internalFormat(document, context); 264 convertLineDelimiters(document); 265 if (!isReplacedAreaEmpty(context)) 266 trimStart(document); 267 268 tracker.updateBuffer(); 269 } catch (MalformedTreeException e) { 270 throw new BadLocationException(); 271 } 272 } 273 274 279 private void internalFormat(IDocument document, TemplateContext context) throws BadLocationException { 280 if (fUseCodeFormatter) { 281 try { 283 format(document, (CompilationUnitContext) context); 284 return; 285 } catch (BadLocationException e) { 286 } catch (MalformedTreeException e) { 288 } 290 } 291 indent(document); 292 } 293 294 private void convertLineDelimiters(IDocument document) throws BadLocationException { 295 int lines= document.getNumberOfLines(); 296 for (int line= 0; line < lines; line++) { 297 IRegion region= document.getLineInformation(line); 298 String lineDelimiter= document.getLineDelimiter(line); 299 if (lineDelimiter != null) 300 document.replace(region.getOffset() + region.getLength(), lineDelimiter.length(), fLineDelimiter); 301 } 302 } 303 304 private void trimStart(IDocument document) throws BadLocationException { 305 int i= 0; 306 while ((i != document.getLength()) && Character.isWhitespace(document.getChar(i))) 307 i++; 308 309 document.replace(0, i, ""); } 311 312 private boolean isReplacedAreaEmpty(TemplateContext context) { 313 if (context instanceof DocumentTemplateContext) { 316 DocumentTemplateContext dtc= (DocumentTemplateContext) context; 317 if (dtc.getStart() == dtc.getCompletionOffset()) 318 try { 319 if (dtc.getDocument().get(dtc.getStart(), dtc.getEnd() - dtc.getStart()).trim().length() == 0) 320 return true; 321 } catch (BadLocationException x) { 322 return true; 325 } 326 } 327 return false; 328 } 329 330 private void format(IDocument doc, CompilationUnitContext context) throws BadLocationException { 331 Map options; 332 IJavaProject project= context.getJavaProject(); 333 if (project != null) 334 options= project.getOptions(true); 335 else 336 options= JavaCore.getOptions(); 337 338 String contents= doc.get(); 339 int[] kinds= { CodeFormatter.K_EXPRESSION, CodeFormatter.K_STATEMENTS, CodeFormatter.K_UNKNOWN}; 340 TextEdit edit= null; 341 for (int i= 0; i < kinds.length && edit == null; i++) { 342 edit= CodeFormatterUtil.format2(kinds[i], contents, fInitialIndentLevel, fLineDelimiter, options); 343 } 344 345 if (edit == null) 346 throw new BadLocationException(); 348 edit.apply(doc, TextEdit.UPDATE_REGIONS); 349 } 350 351 private void indent(IDocument document) throws BadLocationException, MalformedTreeException { 352 int offset= document.getLineOffset(0); 354 document.replace(offset, 0, CodeFormatterUtil.createIndentString(fInitialIndentLevel, fProject)); 355 356 int lineCount= document.getNumberOfLines(); 358 IndentUtil.indentLines(document, new LineRange(1, lineCount - 1), fProject, null); 359 } 360 } 361 | Popular Tags |