Source code: com/port80/eclipse/util/JavaCodeFormatter.java
1 /**
2 * Modifed from org.eclipse.jdt.internal.formatter.CodeFormatter.
3 * . But don't add space after '#'.
4 * . Has a custom default format options.
5 * . Clear line buffer before format so that formatter can be reused to format another string.
6 */
7 package com.port80.eclipse.util;
8
9 import java.io.BufferedReader;
10 import java.io.IOException;
11 import java.io.StringReader;
12 import java.util.HashMap;
13 import java.util.Hashtable;
14 import java.util.Locale;
15 import java.util.Map;
16
17 import org.eclipse.jdt.core.ICodeFormatter;
18 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
19 import org.eclipse.jdt.core.compiler.InvalidInputException;
20 import org.eclipse.jdt.internal.compiler.ConfigurableOption;
21 import org.eclipse.jdt.internal.formatter.impl.FormatterOptions;
22 import org.eclipse.jdt.internal.formatter.impl.SplitLine;
23
24 /** <h2>How to format a piece of code ?</h2>
25 * <ul><li>Create an instance of <code>CodeFormatter</code>
26 * <li>Use the method <code>void format(aString)</code>
27 * on this instance to format <code>aString</code>.
28 * It will return the formatted string.</ul>
29 */
30 public class JavaCodeFormatter implements IJavaCodeSymbol, ICodeFormatter, ICodeFragmentFormatter {
31
32 ////////////////////////////////////////////////////////////////////////
33
34 private static final int DEFAULT_LINEWIDTH = 80;
35 private static final int DEFAULT_TABWIDTH = 8;
36 private static final Map DEFAULT_OPTIONS = new HashMap();
37 static {
38 DEFAULT_OPTIONS.put(FormatterOptions.OPTION_InsertNewLineInEmptyBlock, FormatterOptions.DO_NOT_INSERT);
39 DEFAULT_OPTIONS.put(FormatterOptions.OPTION_CompactAssignment, FormatterOptions.NORMAL);
40 DEFAULT_OPTIONS.put(FormatterOptions.OPTION_TabulationSize, String.valueOf(DEFAULT_TABWIDTH));
41 DEFAULT_OPTIONS.put(
42 FormatterOptions.OPTION_SplitLineExceedingLength,
43 String.valueOf(DEFAULT_LINEWIDTH));
44 }
45
46 ////////////////////////////////////////////////////////////////////////
47
48 public JavaCodeFormatter() {
49 this(DEFAULT_OPTIONS);
50 }
51
52 public JavaCodeFormatter(int linewidth, int tabwidth) {
53 this(DEFAULT_OPTIONS);
54 init(linewidth, tabwidth);
55 }
56
57 public JavaCodeFormatter(int linewidth, int tabwidth, boolean with_preprocessor) {
58 this(DEFAULT_OPTIONS);
59 init(linewidth, tabwidth);
60 withPreprocessor = with_preprocessor;
61 }
62
63 public void init(int linewidth, int tabwidth) {
64 Map opts = new HashMap(DEFAULT_OPTIONS);
65 opts.put(FormatterOptions.OPTION_SplitLineExceedingLength, String.valueOf(linewidth));
66 opts.put(FormatterOptions.OPTION_TabulationSize, String.valueOf(tabwidth));
67 this.options = new FormatterOptions(opts);
68 }
69
70 public int getIndentLevel() {
71 return indentationLevel;
72 }
73
74 ////////////////////////////////////////////////////////////////////////
75
76 public FormatterOptions options;
77
78 /**
79 * Represents a block in the <code>constructions</code> stack.
80 */
81 public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE;
82
83 /**
84 * Represents a block following a control statement in the <code>constructions</code> stack.
85 */
86 public static final int NONINDENT_BLOCK = -100;
87
88 /**
89 * Contains the formatted output.
90 */
91 StringBuffer formattedSource;
92
93 /**
94 * Contains the current line.<br>
95 * Will be dumped at the next "newline"
96 */
97 StringBuffer currentLineBuffer;
98
99 /**
100 * Used during the formatting to get each token.
101 */
102 JavaCodeScanner scanner;
103
104 /**
105 * Contains the tokens responsible for the current indentation level
106 * and the blocks not closed yet.
107 */
108 private int[] constructions;
109
110 /**
111 * Index in the <code>constructions</code> array.
112 */
113 private int constructionsCount;
114
115 /**
116 * Level of indentation of the current token (number of tab char put in front of it).
117 */
118 private int indentationLevel;
119
120 /**
121 * Regular level of indentation of all the lines
122 */
123 private int initialIndentationLevel;
124
125 /**
126 * Used to split a line.
127 */
128 JavaCodeScanner splitScanner;
129
130 /**
131 * To remember the offset between the beginning of the line and the
132 * beginning of the comment.
133 */
134 int currentCommentOffset;
135 int currentLineIndentationLevel;
136 int maxLineSize = 30;
137 private boolean containsOpenCloseBraces;
138 private int indentationLevelForOpenCloseBraces;
139
140 /**
141 * Collections of positions to map
142 */
143 private int[] positionsToMap;
144
145 /**
146 * Collections of mapped positions
147 */
148 private int[] mappedPositions;
149
150 private int indexToMap;
151
152 private int indexInMap;
153
154 private int globalDelta;
155
156 private int lineDelta;
157
158 private int splitDelta;
159
160 private int beginningOfLineIndex;
161
162 private int multipleLineCommentCounter;
163
164 private boolean withPreprocessor;
165 private boolean isPreprocessor;
166
167 /**
168 * Creates a new instance of Code Formatter using the given settings.
169 *
170 * @deprecated backport 1.0 internal functionality
171 */
172 public JavaCodeFormatter(ConfigurableOption[] settings) {
173 this(convertConfigurableOptions(settings));
174 }
175
176 // /**
177 // * Creates a new instance of Code Formatter using the FormattingOptions object
178 // * given as argument
179 // * @deprecated Use JavaCodeFormatter(ConfigurableOption[]) instead
180 // */
181 // public JavaCodeFormatter() {
182 // this((Map) null);
183 // }
184
185 /**
186 * Creates a new instance of Code Formatter using the given settings.
187 */
188 public JavaCodeFormatter(Map settings) {
189 this(settings, false);
190 }
191
192 public JavaCodeFormatter(Map settings, boolean with_preprocessor) {
193 withPreprocessor = with_preprocessor;
194 // initialize internal state
195 constructionsCount = 0;
196 constructions = new int[10];
197 currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
198 currentCommentOffset = -1;
199
200 // initialize primary and secondary scanners
201 scanner = new JavaCodeScanner(true, true); // regular scanner for forming lines
202 scanner.recordLineSeparator = true;
203 // to remind of the position of the beginning of the line.
204 splitScanner = new JavaCodeScanner(true, true);
205 // secondary scanner to split long lines formed by primary scanning
206
207 // initialize current line buffer
208 currentLineBuffer = new StringBuffer();
209 this.options = new FormatterOptions(settings);
210 }
211
212 /**
213 * Returns true if a lineSeparator has to be inserted before <code>operator</code>
214 * false otherwise.
215 */
216 private static boolean breakLineBeforeOperator(int operator) {
217 switch (operator) {
218 case TokenNameCOMMA :
219 case TokenNameSEMICOLON :
220 case TokenNameEQUAL :
221 return false;
222 default :
223 return true;
224 }
225 }
226
227 /**
228 * @deprecated backport 1.0 internal functionality
229 */
230 private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
231 Hashtable options = new Hashtable(10);
232
233 for (int i = 0; i < settings.length; i++) {
234 if (settings[i].getComponentName().equals(JavaCodeFormatter.class.getName())) {
235 String optionName = settings[i].getOptionName();
236 int valueIndex = settings[i].getCurrentValueIndex();
237
238 if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
239 options.put("org.eclipse.jdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
240
241 } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
242 options.put("org.eclipse.jdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
243
244 } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
245 options.put("org.eclipse.jdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
246
247 } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
248 options.put("org.eclipse.jdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
249
250 } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
251 options.put("org.eclipse.jdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
252
253 } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
254 options.put("org.eclipse.jdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
255
256 } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
257 options.put("org.eclipse.jdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
258
259 } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
260 options.put("org.eclipse.jdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
261
262 } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
263 options.put("org.eclipse.jdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
264 }
265 }
266 }
267
268 return options;
269 }
270
271 /**
272 * Returns the end of the source code.
273 */
274 private final String copyRemainingSource() {
275 char str[] = scanner.source;
276 int startPosition = scanner.startPosition;
277 int length = str.length - startPosition;
278 StringBuffer bufr = new StringBuffer(length);
279 if (startPosition < str.length) {
280 bufr.append(str, startPosition, length);
281 }
282 return (bufr.toString());
283 }
284
285 /**
286 * Inserts <code>tabCount</code> tab character or their equivalent number of spaces.
287 */
288 private void dumpTab(int tabCount) {
289 if (options.indentWithTab) {
290 for (int j = 0; j < tabCount; j++) {
291 formattedSource.append('\t');
292 increaseSplitDelta(1);
293 }
294 } else {
295 for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
296 formattedSource.append(' ');
297 increaseSplitDelta(1);
298 }
299 }
300 }
301
302 /**
303 * Dumps <code>currentLineBuffer</code> into the formatted string.
304 */
305 private void flushBuffer() {
306 String currentString = currentLineBuffer.toString();
307 splitDelta = 0;
308 beginningOfLineIndex = formattedSource.length();
309 if (containsOpenCloseBraces) {
310 containsOpenCloseBraces = false;
311 outputLine(currentString, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
312 indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
313 } else {
314 outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0);
315 }
316 int scannerSourceLength = scanner.source.length;
317 if (scannerSourceLength > 2) {
318 if (scanner.source[scannerSourceLength - 1] == '\n'
319 && scanner.source[scannerSourceLength - 2] == '\r') {
320 formattedSource.append(options.lineSeparatorSequence);
321 increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
322 } else if (scanner.source[scannerSourceLength - 1] == '\n') {
323 formattedSource.append(options.lineSeparatorSequence);
324 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
325 } else if (scanner.source[scannerSourceLength - 1] == '\r') {
326 formattedSource.append(options.lineSeparatorSequence);
327 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
328 }
329 }
330 updateMappedPositions(scanner.startPosition);
331 }
332
333 /**
334 * Formats the input string.
335 */
336 private void format() {
337 int token = 0;
338 int previousToken = 0;
339 int previousCompilableToken = 0;
340 int indentationOffset = 0;
341 int newLinesInWhitespace = 0;
342
343 // number of new lines in the previous whitespace token
344 // (used to leave blank lines before comments)
345 int pendingNewLines = 0;
346 boolean expectingOpenBrace = false;
347 boolean clearNonBlockIndents = false;
348 // true if all indentations till the 1st { (usefull after } or ;)
349 boolean pendingSpace = true;
350 boolean pendingNewlineAfterParen = false;
351 // true when a cr is to be put after a ) (in conditional statements)
352 boolean inAssignment = false;
353 boolean inArrayAssignment = false;
354 boolean inThrowsClause = false;
355 boolean inClassOrInterfaceHeader = false;
356
357 // openBracketCount is used to count the number of open brackets not closed yet.
358 int openBracketCount = 0;
359 int unarySignModifier = 0;
360
361 // openParenthesis[0] is used to count the parenthesis not belonging to a condition
362 // (eg foo();). parenthesis in for (...) are count elsewhere in the array.
363 int openParenthesisCount = 1;
364 int[] openParenthesis = new int[10];
365
366 // tokenBeforeColon is used to know what token goes along with the current :
367 // it can be case or ?
368 int tokenBeforeColonCount = 0;
369 int[] tokenBeforeColon = new int[10];
370
371 constructionsCount = 0; // initializes the constructions count.
372
373 // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
374 int nlicsToken = 0;
375
376 // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else
377 boolean specialElse = false;
378
379 // OPTION (IndentationLevel): initial indentation level may be non-zero.
380 currentLineIndentationLevel += constructionsCount;
381 containsOpenCloseBraces = false;
382 indentationLevelForOpenCloseBraces = 0;
383
384 // An InvalidInputException exception might cause the termination of this loop.
385 try {
386 while (true) {
387 // Get the next token. Catch invalid input and output it
388 // with minimal formatting, also catch end of input and
389 // exit the loop.
390 try {
391 token = scanner.getNextToken();
392 } catch (InvalidInputException e) {
393 if (!handleInvalidToken(e)) {
394 throw e;
395 }
396 token = 0;
397 }
398 if (token == JavaCodeScanner.TokenNameEOF)
399 break;
400
401 /* ## MODIFYING the indentation level before generating new lines
402 and indentation in the output string
403 */
404
405 // Removes all the indentations made by statements not followed by a block
406 // except if the current token is ELSE, CATCH or if we are in a switch/case
407 if (clearNonBlockIndents && (token != JavaCodeScanner.TokenNameWHITESPACE)) {
408 switch (token) {
409 case TokenNameelse :
410 if (constructionsCount > 0
411 && constructions[constructionsCount - 1]
412 == TokenNameelse) {
413 pendingNewLines = 1;
414 specialElse = true;
415 }
416 indentationLevel += popInclusiveUntil(TokenNameif);
417 break;
418 case TokenNamecatch :
419 indentationLevel += popInclusiveUntil(TokenNamecatch);
420 break;
421 case TokenNamefinally :
422 indentationLevel += popInclusiveUntil(TokenNamecatch);
423 break;
424 case TokenNamewhile :
425 if (nlicsToken == TokenNamedo) {
426 indentationLevel += pop(TokenNamedo);
427 break;
428 }
429 default :
430 indentationLevel += popExclusiveUntilBlockOrCase();
431 // clear until a CASE, DEFAULT or BLOCK is encountered.
432 // Thus, the indentationLevel is correctly cleared either
433 // in a switch/case statement or in any other situation.
434 }
435 clearNonBlockIndents = false;
436 }
437 //HACK to preserve linebreaks before preprocessor lines #define, ... etc.
438 if (withPreprocessor && token == TokenNameHASH) {
439 if (newLinesInWhitespace > 0) {
440 pendingNewLines = newLinesInWhitespace;
441 newLinesInWhitespace = 0;
442 specialElse = true;
443 isPreprocessor = true;
444 }
445 if (previousToken == JavaCodeScanner.TokenNameEOF)
446 isPreprocessor = true;
447 }
448 // returns to the indentation level created by the SWITCH keyword
449 // if the current token is a CASE or a DEFAULT
450 if (token == TokenNamecase || token == TokenNamedefault) {
451 indentationLevel += pop(TokenNamecase);
452 }
453 if (token == JavaCodeScanner.TokenNamethrows) {
454 inThrowsClause = true;
455 }
456 if ((token == JavaCodeScanner.TokenNameclass
457 || token == JavaCodeScanner.TokenNameinterface)
458 && previousToken != JavaCodeScanner.TokenNameDOT) {
459 inClassOrInterfaceHeader = true;
460 }
461
462 /* ## APPEND newlines and indentations to the output string
463 */
464 // Do not add a new line between ELSE and IF, if the option elseIfOnSameLine is true.
465 // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
466 if (pendingNewlineAfterParen
467 && previousCompilableToken == TokenNameelse
468 && token == TokenNameif
469 && options.compactElseIfMode) {
470 pendingNewlineAfterParen = false;
471 pendingNewLines = 0;
472 indentationLevel += pop(TokenNameelse);
473 // because else if is now one single statement,
474 // the indentation level after it is increased by one and not by 2
475 // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2).
476 }
477 // Add a newline & indent to the formatted source string if
478 // a for/if-else/while statement was scanned and there is no block
479 // following it.
480 pendingNewlineAfterParen =
481 pendingNewlineAfterParen
482 || (previousCompilableToken == TokenNameRPAREN
483 && token == TokenNameLBRACE);
484 if (pendingNewlineAfterParen && token != JavaCodeScanner.TokenNameWHITESPACE) {
485 pendingNewlineAfterParen = false;
486
487 // Do to add a newline & indent sequence if the current token is an
488 // open brace or a period or if the current token is a semi-colon and the
489 // previous token is a close paren.
490 // add a new line if a parenthesis belonging to a for() statement
491 // has been closed and the current token is not an opening brace
492 if (token != TokenNameLBRACE
493 && !isComment(token) // to avoid adding new line between else and a comment
494 && token != TokenNameDOT
495 && !(previousCompilableToken == TokenNameRPAREN
496 && token == TokenNameSEMICOLON)) {
497 newLine(1);
498 currentLineIndentationLevel = indentationLevel;
499 pendingNewLines = 0;
500 pendingSpace = false;
501 } else {
502 if (token == TokenNameLBRACE
503 && options.newLineBeforeOpeningBraceMode) {
504 newLine(1);
505 if (constructionsCount > 0
506 && constructions[constructionsCount - 1] != BLOCK
507 && constructions[constructionsCount - 1]
508 != NONINDENT_BLOCK) {
509 currentLineIndentationLevel = indentationLevel - 1;
510 } else {
511 currentLineIndentationLevel = indentationLevel;
512 }
513 pendingNewLines = 0;
514 pendingSpace = false;
515 }
516 }
517 }
518 if (token == TokenNameLBRACE
519 && options.newLineBeforeOpeningBraceMode
520 && constructionsCount > 0
521 && constructions[constructionsCount - 1] == TokenNamedo) {
522 newLine(1);
523 currentLineIndentationLevel = indentationLevel - 1;
524 pendingNewLines = 0;
525 pendingSpace = false;
526 }
527 // see PR 1G5G8EC
528 if (token == TokenNameLBRACE && inThrowsClause) {
529 inThrowsClause = false;
530 if (options.newLineBeforeOpeningBraceMode) {
531 newLine(1);
532 currentLineIndentationLevel = indentationLevel;
533 pendingNewLines = 0;
534 pendingSpace = false;
535 }
536 }
537 // see PR 1G5G82G
538 if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
539 inClassOrInterfaceHeader = false;
540 if (options.newLineBeforeOpeningBraceMode) {
541 newLine(1);
542 currentLineIndentationLevel = indentationLevel;
543 pendingNewLines = 0;
544 pendingSpace = false;
545 }
546 }
547 // Add pending new lines to the formatted source string.
548 // Note: pending new lines are not added if the current token
549 // is a single line comment or whitespace.
550 // if the comment is between parenthesis, there is no blank line preservation
551 // (if it's a one-line comment, a blank line is added after it).
552 if (((pendingNewLines > 0 && (!isComment(token)))
553 || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
554 || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE))
555 && token != JavaCodeScanner.TokenNameWHITESPACE) {
556
557 // Do not add newline & indent between an adjoining close brace and
558 // close paren. Anonymous inner classes may use this form.
559 boolean closeBraceAndCloseParen =
560 previousToken == TokenNameRBRACE && token == TokenNameRPAREN;
561
562 // OPTION (NewLineInCompoundStatement): do not add newline & indent
563 // between close brace and else, (do) while, catch, and finally if
564 // newlineInCompoundStatement is true.
565 boolean nlicsOption =
566 previousToken == TokenNameRBRACE
567 && !options.newlineInControlStatementMode
568 && (token == TokenNameelse
569 || (token == TokenNamewhile && nlicsToken == TokenNamedo)
570 || token == TokenNamecatch
571 || token == TokenNamefinally);
572
573 // Do not add a newline & indent between a close brace and semi-colon.
574 boolean semiColonAndCloseBrace =
575 previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON;
576
577 // Do not add a new line & indent between a multiline comment and a opening brace
578 boolean commentAndOpenBrace =
579 previousToken == JavaCodeScanner.TokenNameCOMMENT_BLOCK
580 && token == TokenNameLBRACE;
581
582 // Do not add a newline & indent between a close brace and a colon (in array assignments, for example).
583 boolean commaAndCloseBrace =
584 previousToken == TokenNameRBRACE && token == TokenNameCOMMA;
585
586 // Add a newline and indent, if appropriate.
587 if (specialElse
588 || (!commentAndOpenBrace
589 && !closeBraceAndCloseParen
590 && !nlicsOption
591 && !semiColonAndCloseBrace
592 && !commaAndCloseBrace)) {
593
594 // if clearAllBlankLinesMode=false, leaves the blank lines
595 // inserted by the user
596 // if clearAllBlankLinesMode=true, removes all of then
597 // and insert only blank lines required by the formatting.
598 if (!options.clearAllBlankLinesMode) {
599 // (isComment(token))
600 pendingNewLines =
601 (pendingNewLines < newLinesInWhitespace)
602 ? newLinesInWhitespace
603 : pendingNewLines;
604 pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines;
605 }
606 if (previousCompilableToken == TokenNameLBRACE
607 && token == TokenNameRBRACE) {
608 containsOpenCloseBraces = true;
609 indentationLevelForOpenCloseBraces =
610 currentLineIndentationLevel;
611 if (isComment(previousToken)) {
612 newLine(pendingNewLines);
613 } else {
614 /* if (!(constructionsCount > 1
615 && constructions[constructionsCount-1] == NONINDENT_BLOCK
616 && (constructions[constructionsCount-2] == TokenNamefor
617 || constructions[constructionsCount-2] == TokenNamewhile))) {*/
618 if (options.newLineInEmptyBlockMode) {
619 if (inArrayAssignment) {
620 newLine(1);
621 // array assigment with an empty block
622 } else {
623 newLine(pendingNewLines);
624 }
625 }
626 // }
627 }
628 } else {
629 // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment before the ';'
630 if (!((previousToken == JavaCodeScanner.TokenNameCOMMENT_BLOCK
631 || previousToken
632 == JavaCodeScanner.TokenNameCOMMENT_JAVADOC)
633 && token == TokenNameSEMICOLON)) {
634 newLine(pendingNewLines);
635 }
636 }
637 if (((previousCompilableToken == TokenNameSEMICOLON)
638 || (previousCompilableToken == TokenNameLBRACE)
639 || (previousCompilableToken == TokenNameRBRACE)
640 || (isComment(previousToken)))
641 && (token == TokenNameRBRACE)) {
642 indentationOffset = -1;
643 indentationLevel += popExclusiveUntilBlock();
644 }
645 if (previousToken == JavaCodeScanner.TokenNameCOMMENT_LINE
646 && inAssignment) {
647 // PR 1FI5IPO
648 currentLineIndentationLevel++;
649 } else {
650 currentLineIndentationLevel =
651 indentationLevel + indentationOffset;
652 }
653 pendingSpace = false;
654 indentationOffset = 0;
655 }
656 pendingNewLines = 0;
657 newLinesInWhitespace = 0;
658 specialElse = false;
659
660 if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
661 nlicsToken = 0;
662 }
663 }
664 switch (token) {
665 case TokenNameelse :
666 case TokenNamefinally :
667 expectingOpenBrace = true;
668 pendingNewlineAfterParen = true;
669 indentationLevel += pushControlStatement(token);
670 break;
671 case TokenNamecase :
672 case TokenNamedefault :
673 if (tokenBeforeColonCount == tokenBeforeColon.length) {
674 System.arraycopy(
675 tokenBeforeColon,
676 0,
677 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
678 0,
679 tokenBeforeColonCount);
680 }
681 tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
682 indentationLevel += pushControlStatement(TokenNamecase);
683 break;
684 case TokenNameQUESTION :
685 if (tokenBeforeColonCount == tokenBeforeColon.length) {
686 System.arraycopy(
687 tokenBeforeColon,
688 0,
689 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
690 0,
691 tokenBeforeColonCount);
692 }
693 tokenBeforeColon[tokenBeforeColonCount++] = token;
694 break;
695 case TokenNameswitch :
696 case TokenNamefor :
697 case TokenNameif :
698 case TokenNamewhile :
699 if (openParenthesisCount == openParenthesis.length) {
700 System.arraycopy(
701 openParenthesis,
702 0,
703 (openParenthesis = new int[openParenthesisCount * 2]),
704 0,
705 openParenthesisCount);
706 }
707 openParenthesis[openParenthesisCount++] = 0;
708 expectingOpenBrace = true;
709
710 indentationLevel += pushControlStatement(token);
711 break;
712 case TokenNametry :
713 pendingNewlineAfterParen = true;
714 case TokenNamecatch :
715 // several CATCH statements can be contiguous.
716 // a CATCH is encountered pop until first CATCH (if a CATCH follows a TRY it works the same way,
717 // as CATCH and TRY are the same token in the stack).
718 expectingOpenBrace = true;
719 indentationLevel += pushControlStatement(TokenNamecatch);
720 break;
721
722 case TokenNamedo :
723 expectingOpenBrace = true;
724 indentationLevel += pushControlStatement(token);
725 nlicsToken = token;
726 break;
727 case TokenNamenew :
728 break;
729 case TokenNameLPAREN :
730 if (previousToken == TokenNamesynchronized) {
731 indentationLevel += pushControlStatement(previousToken);
732 } else {
733 // Put a space between the previous and current token if the
734 // previous token was not a keyword, open paren, logical
735 // compliment (eg: !), semi-colon, open brace, close brace,
736 // super, or this.
737 if (previousCompilableToken != TokenNameLBRACKET
738 && previousToken != TokenNameIdentifier
739 && previousToken != 0
740 && previousToken != TokenNameNOT
741 && previousToken != TokenNameLPAREN
742 && previousToken != TokenNameTWIDDLE
743 && previousToken != TokenNameSEMICOLON
744 && previousToken != TokenNameLBRACE
745 && previousToken != TokenNameRBRACE
746 && previousToken != TokenNameHASH
747 && previousToken != TokenNameEACH
748 && previousToken != TokenNamesuper
749 && previousToken != TokenNamethis) {
750 space();
751 }
752 // If in a for/if/while statement, increase the parenthesis count
753 // for the current openParenthesisCount
754 // else increase the count for stand alone parenthesis.
755 if (openParenthesisCount > 0)
756 openParenthesis[openParenthesisCount - 1]++;
757 else
758 openParenthesis[0]++;
759
760 pendingSpace = false;
761 }
762 break;
763 case TokenNameRPAREN :
764
765 // Decrease the parenthesis count
766 // if there is no more unclosed parenthesis,
767 // a new line and indent may be append (depending on the next token).
768 if ((openParenthesisCount > 1)
769 && (openParenthesis[openParenthesisCount - 1] > 0)) {
770 openParenthesis[openParenthesisCount - 1]--;
771 if (openParenthesis[openParenthesisCount - 1] <= 0) {
772 pendingNewlineAfterParen = true;
773 inAssignment = false;
774 openParenthesisCount--;
775 }
776 } else {
777 openParenthesis[0]--;
778 }
779 pendingSpace = false;
780 break;
781 case TokenNameLBRACE :
782 if ((previousCompilableToken == TokenNameRBRACKET)
783 || (previousCompilableToken == TokenNameEQUAL)) {
784 // if (previousCompilableToken == TokenNameRBRACKET) {
785 inArrayAssignment = true;
786 inAssignment = false;
787 }
788 if (inArrayAssignment) {
789 indentationLevel += pushBlock();
790 } else {
791 // Add new line and increase indentation level after open brace.
792 pendingNewLines = 1;
793 indentationLevel += pushBlock();
794 }
795 break;
796 case TokenNameRBRACE :
797 if (previousCompilableToken == TokenNameRPAREN) {
798 pendingSpace = false;
799 }
800 if (inArrayAssignment) {
801 inArrayAssignment = false;
802 pendingNewLines = 1;
803 indentationLevel += popInclusiveUntilBlock();
804 } else {
805 pendingNewLines = 1;
806 indentationLevel += popInclusiveUntilBlock();
807
808 if (previousCompilableToken == TokenNameRPAREN) {
809 // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
810 currentLineBuffer.append(options.lineSeparatorSequence);
811 increaseLineDelta(options.lineSeparatorSequence.length);
812 }
813 if (constructionsCount > 0) {
814 switch (constructions[constructionsCount - 1]) {
815 case TokenNamefor :
816 //indentationLevel += popExclusiveUntilBlock();
817 //break;
818 case TokenNameswitch :
819 case TokenNameif :
820 case TokenNameelse :
821 case TokenNametry :
822 case TokenNamecatch :
823 case TokenNamefinally :
824 case TokenNamewhile :
825 case TokenNamedo :
826 case TokenNamesynchronized :
827 clearNonBlockIndents = true;
828 default :
829 break;
830 }
831 }
832 }
833 break;
834 case TokenNameLBRACKET :
835 openBracketCount++;
836 pendingSpace = false;
837 break;
838 case TokenNameRBRACKET :
839 openBracketCount -= (openBracketCount > 0) ? 1 : 0;
840 // if there is no left bracket to close, the right bracket is ignored.
841 pendingSpace = false;
842 break;
843 case TokenNameCOMMA :
844 case TokenNameDOT :
845 pendingSpace = false;
846 break;
847 case TokenNameSEMICOLON :
848
849 // Do not generate line terminators in the definition of
850 // the for statement.
851 // if not in this case, jump a line and reduce indentation after the brace
852 // if the block it closes belongs to a conditional statement (if, while, do...).
853 if (openParenthesisCount <= 1) {
854 pendingNewLines = 1;
855 if (expectingOpenBrace) {
856 clearNonBlockIndents = true;
857 expectingOpenBrace = false;
858 }
859 }
860 inAssignment = false;
861 pendingSpace = false;
862 break;
863 case TokenNamePLUS_PLUS :
864 case TokenNameMINUS_MINUS :
865
866 // Do not put a space between a post-increment/decrement
867 // and the identifier being modified.
868 if (previousToken == TokenNameIdentifier
869 || previousToken == TokenNameRBRACKET) {
870 pendingSpace = false;
871 }
872 break;
873 case TokenNamePLUS : // previously ADDITION
874 case TokenNameMINUS :
875
876 // Handle the unary operators plus and minus via a flag
877 if (!isLiteralToken(previousToken)
878 && previousToken != TokenNameIdentifier
879 && previousToken != TokenNameRPAREN
880 && previousToken != TokenNameRBRACKET) {
881 unarySignModifier = 1;
882 }
883 break;
884 case TokenNameCOLON :
885 // In a switch/case statement, add a newline & indent
886 // when a colon is encountered.
887 if (tokenBeforeColonCount > 0) {
888 if (tokenBeforeColon[tokenBeforeColonCount - 1]
889 == TokenNamecase) {
890 pendingNewLines = 1;
891 }
892 tokenBeforeColonCount--;
893 }
894 break;
895 case TokenNameEQUAL :
896 inAssignment = true;
897 break;
898 case JavaCodeScanner.TokenNameCOMMENT_LINE :
899 pendingNewLines = 1;
900 if (inAssignment) {
901 currentLineIndentationLevel++;
902 }
903 break; // a line is always inserted after a one-line comment
904 case JavaCodeScanner.TokenNameCOMMENT_JAVADOC :
905 case JavaCodeScanner.TokenNameCOMMENT_BLOCK :
906 currentCommentOffset = getCurrentCommentOffset();
907 pendingNewLines = 1;
908 break;
909 case JavaCodeScanner.TokenNameWHITESPACE :
910
911 // Count the number of line terminators in the whitespace so
912 // line spacing can be preserved near comments.
913 char[] source = scanner.source;
914 newLinesInWhitespace = 0;
915 for (int i = scanner.startPosition, max = scanner.currentPosition;
916 i < max;
917 i++) {
918 if (source[i] == '\r') {
919 if (i < max - 1) {
920 if (source[++i] == '\n') {
921 newLinesInWhitespace++;
922 } else {
923 newLinesInWhitespace++;
924 }
925 } else {
926 newLinesInWhitespace++;
927 }
928 } else if (source[i] == '\n') {
929 newLinesInWhitespace++;
930 }
931 }
932 increaseLineDelta(scanner.startPosition - scanner.currentPosition);
933 break;
934 default :
935 if ((token == TokenNameIdentifier)
936 || isLiteralToken(token)
937 || token == TokenNamesuper
938 || token == TokenNameLPAREN
939 || token == TokenNamethis) {
940
941 // Do not put a space between a unary operator
942 // (eg: ++, --, +, -) and the identifier being modified.
943 if (previousToken == TokenNamePLUS_PLUS
944 || previousToken == TokenNameMINUS_MINUS
945 || previousToken == TokenNameHASH
946 || previousToken == TokenNameEACH
947 || (previousToken == TokenNamePLUS
948 && unarySignModifier > 0)
949 || (previousToken == TokenNameMINUS
950 && unarySignModifier > 0)) {
951 pendingSpace = false;
952 }
953 unarySignModifier = 0;
954 }
955 break;
956 }
957 // Do not output whitespace tokens.
958 if (token != JavaCodeScanner.TokenNameWHITESPACE) {
959
960 /* Add pending space to the formatted source string.
961 Do not output a space under the following circumstances:
962 1) this is the first pass
963 2) previous token is an open paren
964 3) previous token is a period
965 4) previous token is the logical compliment (eg: !)
966 5) previous token is the bitwise compliment (eg: ~)
967 6) previous token is the open bracket (eg: [)
968 7) in an assignment statement, if the previous token is an
969 open brace or the current token is a close brace
970 8) previous token is a single line comment
971 */
972 boolean openAndCloseBrace =
973 previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE;
974
975 if (pendingSpace
976 && insertSpaceAfter(previousToken)
977 && !(inAssignment
978 && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
979 && previousToken != JavaCodeScanner.TokenNameCOMMENT_LINE) {
980 if ((!(options.compactAssignmentMode && token == TokenNameEQUAL))
981 && !openAndCloseBrace)
982 space();
983 }
984 // Add the next token to the formatted source string.
985 outputCurrentToken(token);
986 if (token == JavaCodeScanner.TokenNameCOMMENT_LINE
987 && openParenthesisCount > 1) {
988 pendingNewLines = 0;
989 currentLineBuffer.append(options.lineSeparatorSequence);
990 increaseLineDelta(options.lineSeparatorSequence.length);
991 }
992 pendingSpace = true;
993 }
994 // Whitespace tokens do not need to be remembered.
995 if (token != JavaCodeScanner.TokenNameWHITESPACE) {
996 previousToken = token;
997 if (token != JavaCodeScanner.TokenNameCOMMENT_BLOCK
998 && token != JavaCodeScanner.TokenNameCOMMENT_LINE
999 && token != JavaCodeScanner.TokenNameCOMMENT_JAVADOC) {
1000 previousCompilableToken = token;
1001 }
1002 } else if (withPreprocessor && newLinesInWhitespace > 0 && isPreprocessor) {
1003 //HACK to preserve line break after a line with '#'.
1004 isPreprocessor = false;
1005 pendingSpace = false;
1006 pendingNewLines = 0;
1007 int level=currentLineIndentationLevel;
1008 newLine(newLinesInWhitespace);
1009 currentLineIndentationLevel=level;
1010 newLinesInWhitespace = 0;
1011 previousToken = JavaCodeScanner.TokenNameEOF;
1012 }
1013 }
1014 output(copyRemainingSource());
1015 flushBuffer(); // dump the last token of the source in the formatted output.
1016 } catch (InvalidInputException e) {
1017 output(copyRemainingSource());
1018 flushBuffer(); // dump the last token of the source in the formatted output.
1019 }
1020 }
1021
1022 /**
1023 * Formats the char array <code>sourceString</code>,
1024 * and returns a string containing the formatted version.
1025 * @return the formatted ouput.
1026 */
1027 public String formatSourceString(String sourceString) {
1028 char[] sourceChars = sourceString.toCharArray();
1029 currentLineBuffer.setLength(0);
1030 formattedSource = new StringBuffer(sourceChars.length);
1031 scanner.setSource(sourceChars);
1032 format();
1033 if (formattedSource.length() > 0 && formattedSource.charAt(0) == '}')
1034 return formattedSource.substring(1);
1035 return formattedSource.toString();
1036 }
1037
1038 /**
1039 * Formats the char array <code>sourceString</code>,
1040 * and returns a string containing the formatted version.
1041 * @param string the string to format
1042 * @param indentationLevel the initial indentation level
1043 * @return the formatted ouput.
1044 */
1045 public String format(String string, int indentationLevel) {
1046 return format(string, indentationLevel, (int[]) null);
1047 }
1048
1049 /**
1050 * Formats the char array <code>sourceString</code>,
1051 * and returns a string containing the formatted version.
1052 * The positions array is modified to contain the mapped positions.
1053 * @param string the string to format
1054 * @param indentationLevel the initial indentation level
1055 * @param positions the array of positions to map
1056 * @return the formatted ouput.
1057 */
1058 public String format(String string, int indentationLevel, int[] positions) {
1059 return this.format(string, indentationLevel, positions, null);
1060 }
1061
1062 public String format(String string, int indentationLevel, int[] positions, String lineSeparator) {
1063 if (lineSeparator != null) {
1064 this.options.setLineSeparator(lineSeparator);
1065 }
1066 if (positions != null) {
1067 this.setPositionsToMap(positions);
1068 this.setInitialIndentationLevel(indentationLevel);
1069 String formattedString = this.formatSourceString(string);
1070 int[] mappedPositions = this.getMappedPositions();
1071 System.arraycopy(mappedPositions, 0, positions, 0, positions.length);
1072 return formattedString;
1073 } else {
1074 this.setInitialIndentationLevel(indentationLevel);
1075 return this.formatSourceString(string);
1076 }
1077 }
1078 /**
1079 * Formats the char array <code>sourceString</code>,
1080 * and returns a string containing the formatted version. The initial indentation level is 0.
1081 * @param string the string to format
1082 * @return the formatted ouput.
1083 */
1084 public String format(String string) {
1085 return this.format(string, 0, (int[]) null);
1086 }
1087
1088 /**
1089 * Formats a given source string, starting indenting it at a particular
1090 * depth and using the given options
1091 *
1092 * @deprecated backport 1.0 internal functionality
1093 */
1094 public static String format(String sourceString, int initialIndentationLevel, ConfigurableOption[] options) {
1095 JavaCodeFormatter formatter = new JavaCodeFormatter(options);
1096 formatter.setInitialIndentationLevel(initialIndentationLevel);
1097 return formatter.formatSourceString(sourceString);
1098 }
1099
1100 /**
1101 * Returns the number of characters and tab char between the beginning of the line
1102 * and the beginning of the comment.
1103 */
1104 private int getCurrentCommentOffset() {
1105 int linePtr = scanner.linePtr;
1106 // if there is no beginning of line, return 0.
1107 if (linePtr < 0)
1108 return 0;
1109 int offset = 0;
1110 int beginningOfLine = scanner.lineEnds[linePtr];
1111 int currentStartPosition = scanner.startPosition;
1112 char[] source = scanner.source;
1113
1114 // find the position of the beginning of the line containing the comment
1115 while (beginningOfLine > currentStartPosition) {
1116 if (linePtr > 0) {
1117 beginningOfLine = scanner.lineEnds[--linePtr];
1118 } else {
1119 beginningOfLine = 0;
1120 break;
1121 }
1122 }
1123 for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
1124 char currentCharacter = source[i];
1125 switch (currentCharacter) {
1126 case '\t' :
1127 offset += options.tabSize;
1128 break;
1129 case ' ' :
1130 offset++;
1131 break;
1132 case '\r' :
1133 case '\n' :
1134 break;
1135 default :
1136 return offset;
1137 }
1138 }
1139 return offset;
1140 }
1141
1142 /**
1143 * Returns an array of descriptions for the configurable options.
1144 * The descriptions may be changed and passed back to a different
1145 * compiler.
1146 *
1147 * @deprecated backport 1.0 internal functionality
1148 */
1149 public static ConfigurableOption[] getDefaultOptions(Locale locale) {
1150 String componentName = JavaCodeFormatter.class.getName();
1151 FormatterOptions options = new FormatterOptions();
1152 return new ConfigurableOption[] { new ConfigurableOption(componentName, "newline.openingBrace", locale, options.newLineBeforeOpeningBraceMode ? 0 : 1), //$NON-NLS-1$
1153 new ConfigurableOption(componentName, "newline.controlStatement", locale, options.newlineInControlStatementMode ? 0 : 1), //$NON-NLS-1$
1154 new ConfigurableOption(componentName, "newline.clearAll", locale, options.clearAllBlankLinesMode ? 0 : 1), //$NON-NLS-1$
1155 new ConfigurableOption(componentName, "newline.elseIf", locale, options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
1156 new ConfigurableOption(componentName, "newline.emptyBlock", locale, options.newLineInEmptyBlockMode ? 0 : 1), //$NON-NLS-1$
1157 new ConfigurableOption(componentName, "line.split", locale, options.maxLineLength), //$NON-NLS-1$
1158 new ConfigurableOption(componentName, "style.compactAssignment", locale, options.compactAssignmentMode ? 0 : 1), //$NON-NLS-1$
1159 new ConfigurableOption(componentName, "tabulation.char", locale, options.indentWithTab ? 0 : 1), //$NON-NLS-1$
1160 new ConfigurableOption(componentName, "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
1161 };
1162 }
1163
1164 /**
1165 * Returns the array of mapped positions.
1166 * Returns null is no positions have been set.
1167 * @return int[]
1168 * @deprecated There is no need to retrieve the mapped positions anymore.
1169 */
1170 public int[] getMappedPositions() {
1171 return mappedPositions;
1172 }
1173
1174 /**
1175 * Returns the priority of the token given as argument<br>
1176 * The most prioritary the token is, the smallest the return value is.
1177 * @return the priority of <code>token</code>
1178 * @param token the token of which the priority is requested
1179 */
1180 private static int getTokenPriority(int token) {
1181 switch (token) {
1182 case TokenNameextends :
1183 case TokenNameimplements :
1184 case TokenNamethrows :
1185 return 10;
1186 case TokenNameSEMICOLON : // ;
1187 return 20;
1188 case TokenNameCOMMA : // ,
1189 return 25;
1190 case TokenNameEQUAL : // =
1191 return 30;
1192 case TokenNameAND_AND : // &&
1193 case TokenNameOR_OR : // ||
1194 return 40;
1195 case TokenNameQUESTION : // ?
1196 case TokenNameCOLON : // :
1197 return 50; // it's better cutting on ?: than on ;
1198 case TokenNameEQUAL_EQUAL : // ==
1199 case TokenNameNOT_EQUAL : // !=
1200 return 60;
1201 case TokenNameLESS : // <
1202 case TokenNameLESS_EQUAL : // <=
1203 case TokenNameGREATER : // >
1204 case TokenNameGREATER_EQUAL : // >=
1205 case TokenNameinstanceof : // instanceof
1206 return 70;
1207 case TokenNamePLUS : // +
1208 case TokenNameMINUS : // -
1209 return 80;
1210 case TokenNameMULTIPLY : // *
1211 case TokenNameDIVIDE : // /
1212 case TokenNameREMAINDER : // %
1213 return 90;
1214 case TokenNameLEFT_SHIFT : // <<
1215 case TokenNameRIGHT_SHIFT : // >>
1216 case TokenNameUNSIGNED_RIGHT_SHIFT : // >>>
1217 return 100;
1218 case TokenNameAND : // &
1219 case TokenNameOR : // |
1220 case TokenNameXOR : // ^
1221 return 110;
1222 case TokenNameMULTIPLY_EQUAL : // *=
1223 case TokenNameDIVIDE_EQUAL : // /=
1224 case TokenNameREMAINDER_EQUAL : // %=
1225 case TokenNamePLUS_EQUAL : // +=
1226 case TokenNameMINUS_EQUAL : // -=
1227 case TokenNameLEFT_SHIFT_EQUAL : // <<=
1228 case TokenNameRIGHT_SHIFT_EQUAL : // >>=
1229 case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
1230 case TokenNameAND_EQUAL : // &=
1231 case TokenNameXOR_EQUAL : // ^=
1232 case TokenNameOR_EQUAL : // |=
1233 return 120;
1234 case TokenNameDOT : // .
1235 return 130;
1236 default :
1237 return Integer.MAX_VALUE;
1238 }
1239 }
1240
1241 /**
1242 * Handles the exception raised when an invalid token is encountered.
1243 * Returns true if the exception has been handled, false otherwise.
1244 */
1245 private boolean handleInvalidToken(Exception e) {
1246 if (e.getMessage().equals(JavaCodeScanner.INVALID_CHARACTER_CONSTANT)
1247 || e.getMessage().equals(JavaCodeScanner.INVALID_CHAR_IN_STRING)
1248 || e.getMessage().equals(JavaCodeScanner.INVALID_ESCAPE)) {
1249 return true;
1250 }
1251 return false;
1252 }
1253
1254 private final void increaseGlobalDelta(int offset) {
1255 globalDelta += offset;
1256 }
1257
1258 private final void increaseLineDelta(int offset) {
1259 lineDelta += offset;
1260 }
1261
1262 private final void increaseSplitDelta(int offset) {
1263 splitDelta += offset;
1264 }
1265
1266 /**
1267 * Returns true if a space has to be inserted after <code>operator</code>
1268 * false otherwise.
1269 */
1270 private boolean insertSpaceAfter(int token) {
1271 switch (token) {
1272 case TokenNameLPAREN :
1273 case TokenNameNOT :
1274 case TokenNameTWIDDLE :
1275 case TokenNameDOT :
1276 case 0 : // no token
1277 case TokenNameLBRACKET :
1278 case JavaCodeScanner.TokenNameCOMMENT_LINE :
1279 case JavaCodeScanner.TokenNameHASH :
1280 case JavaCodeScanner.TokenNameEACH :
1281 return false;
1282 default :
1283 return true;
1284 }
1285 }
1286
1287 /**
1288 * Returns true if a space has to be inserted before <code>operator</code>
1289 * false otherwise.<br>
1290 * Cannot be static as it uses the code formatter options
1291 * (to know if the compact assignment mode is on).
1292 */
1293 private boolean insertSpaceBefore(int token) {
1294 switch (token) {
1295 case TokenNameEQUAL :
1296 return (!options.compactAssignmentMode);
1297 default :
1298 return false;
1299 }
1300 }
1301
1302 private static boolean isComment(int token) {
1303 boolean result =
1304 token == JavaCodeScanner.TokenNameCOMMENT_BLOCK
1305 || token == JavaCodeScanner.TokenNameCOMMENT_LINE
1306 || token == JavaCodeScanner.TokenNameCOMMENT_JAVADOC;
1307 return result;
1308 }
1309
1310 private static boolean isLiteralToken(int token) {
1311 boolean result =
1312 token == TokenNameIntegerLiteral
1313 || token == TokenNameLongLiteral
1314 || token == TokenNameFloatingPointLiteral
1315 || token == TokenNameDoubleLiteral
1316 || token == TokenNameCharacterLiteral
1317 || token == TokenNameStringLiteral;
1318 return result;
1319 }
1320
1321 /**
1322 * If the length of <code>oneLineBuffer</code> exceeds <code>maxLineLength</code>,
1323 * it is split and the result is dumped in <code>formattedSource</code>
1324 * @param newLineCount the number of new lines to append
1325 */
1326 private void newLine(int newLineCount) {
1327
1328 // format current line
1329 splitDelta = 0;
1330 beginningOfLineIndex = formattedSource.length();
1331 String currentLine = currentLineBuffer.toString();
1332 if (containsOpenCloseBraces) {
1333 containsOpenCloseBraces = false;
1334 outputLine(currentLine, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
1335 indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
1336 } else {
1337 outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0);
1338 }
1339 // dump line break(s)
1340 for (int i = 0; i < newLineCount; i++) {
1341 formattedSource.append(options.lineSeparatorSequence);
1342 increaseSplitDelta(options.lineSeparatorSequence.length);
1343 }
1344 // reset formatter for next line
1345 int currentLength = currentLine.length();
1346 currentLineBuffer =
1347 new StringBuffer(currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize);
1348
1349 increaseGlobalDelta(splitDelta);
1350 increaseGlobalDelta(lineDelta);
1351 lineDelta = 0;
1352 currentLineIndentationLevel = initialIndentationLevel;
1353 }
1354
1355 private String operatorString(int operator) {
1356 switch (operator) {
1357 case TokenNameextends :
1358 return "extends"; //$NON-NLS-1$
1359
1360 case TokenNameimplements :
1361 return "implements"; //$NON-NLS-1$
1362
1363 case TokenNamethrows :
1364 return "throws"; //$NON-NLS-1$
1365
1366 case TokenNameSEMICOLON : // ;
1367 return ";"; //$NON-NLS-1$
1368
1369 case TokenNameCOMMA : // ,
1370 return ","; //$NON-NLS-1$
1371
1372 case TokenNameEQUAL : // =
1373 return "="; //$NON-NLS-1$
1374