/bundles/plugins-trunk/AStylePlugin/astyle/ASBeautifier.java

# · Java · 1680 lines · 1306 code · 121 blank · 253 comment · 118 complexity · b6de26bac8489e9bbf6a60c2633bd36c MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. * :tabSize=8:indentSize=4:noTabs=true:maxLineLen=0:
  3. *
  4. * Copyright (c) 1998,1999,2000,2001 Tal Davidson. All rights reserved.
  5. *
  6. * ASBeautifier.java
  7. * by Tal Davidson (davidsont@bigfoot.com)
  8. * This file is a part of "Artistic Style" - an indentater and reformatter
  9. * of C++, C, and Java source files.
  10. *
  11. * Ported from C++ to Java by Dirk Moebius (dmoebius@gmx.net).
  12. *
  13. * The "Artistic Style" project, including all files needed to compile it,
  14. * is free software; you can redistribute it and/or use it and/or modify it
  15. * under the terms of EITHER the "Artistic License" OR
  16. * the GNU Library General Public License as published by the Free Software
  17. * Foundation; either version 2 of the License, or (at your option) any later
  18. * version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. *
  24. * You should have received a copy of EITHER the "Artistic License" or
  25. * the GNU Library General Public License along with this program.
  26. */
  27. package astyle;
  28. import java.util.*;
  29. import java.io.*;
  30. import astyle.util.*;
  31. import org.gjt.sp.util.Log;
  32. /**
  33. * A C/C++/Java source code indenter.
  34. */
  35. public class ASBeautifier implements ASResource {
  36. public ASBeautifier() {
  37. initStatic();
  38. waitingBeautifierStack = null;
  39. activeBeautifierStack = null;
  40. waitingBeautifierStackLengthStack = null;
  41. activeBeautifierStackLengthStack = null;
  42. headerStack = null;
  43. tempStacks = null;
  44. blockParenDepthStack = null;
  45. blockStatementStack = null;
  46. parenStatementStack = null;
  47. bracketBlockStateStack = null;
  48. inStatementIndentStack = null;
  49. inStatementIndentStackSizeStack = null;
  50. parenIndentStack = null;
  51. sourceIterator = null;
  52. isMinimalConditinalIndentSet = false;
  53. shouldForceTabIndentation = false;
  54. setSpaceIndentation(4);
  55. setMaxInStatementIndentLength(40);
  56. setClassIndent(false);
  57. setSwitchIndent(false);
  58. setCaseIndent(false);
  59. setBlockIndent(false);
  60. setBracketIndent(false);
  61. setNamespaceIndent(false);
  62. setLabelIndent(false);
  63. setEmptyLineFill(false);
  64. setCStyle(true);
  65. setPreprocessorIndent(false);
  66. }
  67. /** copy constructor */
  68. public ASBeautifier(ASBeautifier other) {
  69. this();
  70. headerStack = other.headerStack.getClone();
  71. tempStacks = new StackStack();
  72. for (int i = 0; i < other.tempStacks.size(); i++) {
  73. StringStack s = (StringStack) other.tempStacks.at(i);
  74. tempStacks.push_back(s.getClone());
  75. }
  76. blockParenDepthStack = other.blockParenDepthStack.getClone();
  77. blockStatementStack = other.blockStatementStack.getClone();
  78. parenStatementStack = other.parenStatementStack.getClone();
  79. bracketBlockStateStack = other.bracketBlockStateStack.getClone();
  80. inStatementIndentStack = other.inStatementIndentStack.getClone();
  81. inStatementIndentStackSizeStack = other.inStatementIndentStackSizeStack.getClone();
  82. parenIndentStack = other.parenIndentStack.getClone();
  83. sourceIterator = other.sourceIterator;
  84. indentString = other.indentString;
  85. currentHeader = other.currentHeader;
  86. previousLastLineHeader = other.previousLastLineHeader;
  87. immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp;
  88. isInQuote = other.isInQuote;
  89. isInComment = other.isInComment;
  90. isInCase = other.isInCase;
  91. isInQuestion = other.isInQuestion;
  92. isInStatement =other. isInStatement;
  93. isInHeader = other.isInHeader;
  94. isCStyle = other.isCStyle;
  95. isInFor = other.isInFor; /// danson
  96. isInOperator = other.isInOperator;
  97. isInTemplate = other.isInTemplate;
  98. classIndent = other.classIndent;
  99. isInClassHeader = other.isInClassHeader;
  100. isInClassHeaderTab = other.isInClassHeaderTab;
  101. switchIndent = other.switchIndent;
  102. caseIndent = other.caseIndent;
  103. namespaceIndent = other.namespaceIndent;
  104. bracketIndent = other.bracketIndent;
  105. blockIndent = other.blockIndent;
  106. labelIndent = other.labelIndent;
  107. preprocessorIndent = other.preprocessorIndent;
  108. parenDepth = other.parenDepth;
  109. indentLength = other.indentLength;
  110. blockTabCount = other.blockTabCount;
  111. leadingWhiteSpaces = other.leadingWhiteSpaces;
  112. maxInStatementIndent = other.maxInStatementIndent;
  113. templateDepth = other.templateDepth;
  114. quoteChar = other.quoteChar;
  115. prevNonSpaceCh = other.prevNonSpaceCh;
  116. currentNonSpaceCh = other.currentNonSpaceCh;
  117. currentNonLegalCh = other.currentNonLegalCh;
  118. prevNonLegalCh = other.prevNonLegalCh;
  119. isInConditional = other.isInConditional;
  120. minConditionalIndent = other.minConditionalIndent;
  121. prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
  122. prevFinalLineTabCount = other.prevFinalLineTabCount;
  123. emptyLineFill = other.emptyLineFill;
  124. probationHeader = other.probationHeader;
  125. isInDefine = other.isInDefine;
  126. isInDefineDefinition = other.isInDefineDefinition;
  127. backslashEndsPrevLine = other.backslashEndsPrevLine;
  128. defineTabCount = other.defineTabCount;
  129. }
  130. /**
  131. * initialize the ASBeautifier.
  132. * This method should be called every time a ASBeautifier object is to
  133. * start beautifying a new source file.
  134. * <code>init()</code> receives an ASSourceIterator object that will be
  135. * used to iterate through the source code.
  136. *
  137. * @param iter a reference to the ASSourceIterator object
  138. */
  139. public void init(ASSourceIterator iter) {
  140. sourceIterator = iter;
  141. waitingBeautifierStack = new ASBeautifierStack();
  142. activeBeautifierStack = new ASBeautifierStack();
  143. waitingBeautifierStackLengthStack = new IntegerStack();
  144. activeBeautifierStackLengthStack = new IntegerStack();
  145. headerStack = new StringStack();
  146. tempStacks = new StackStack();
  147. tempStacks.push_back(new StringStack());
  148. blockParenDepthStack = new IntegerStack();
  149. blockStatementStack = new BooleanStack();
  150. parenStatementStack = new BooleanStack();
  151. bracketBlockStateStack = new BooleanStack();
  152. bracketBlockStateStack.push_back(true);
  153. inStatementIndentStack = new IntegerStack();
  154. inStatementIndentStackSizeStack = new IntegerStack();
  155. inStatementIndentStackSizeStack.push_back(0);
  156. parenIndentStack = new IntegerStack();
  157. immediatelyPreviousAssignmentOp = null;
  158. previousLastLineHeader = null;
  159. isInQuote = false;
  160. isInComment = false;
  161. isInStatement = false;
  162. isInCase = false;
  163. isInQuestion = false;
  164. isInClassHeader = false;
  165. isInClassHeaderTab = false;
  166. isInHeader = false;
  167. isInOperator = false;
  168. isInFor = false;
  169. isInTemplate = false;
  170. isInConditional = false;
  171. templateDepth = 0;
  172. parenDepth=0;
  173. blockTabCount = 0;
  174. leadingWhiteSpaces = 0;
  175. prevNonSpaceCh = '{';
  176. currentNonSpaceCh = '{';
  177. prevNonLegalCh = '{';
  178. currentNonLegalCh = '{';
  179. prevFinalLineSpaceTabCount = 0;
  180. prevFinalLineTabCount = 0;
  181. probationHeader = null;
  182. backslashEndsPrevLine = false;
  183. isInDefine = false;
  184. isInDefineDefinition = false;
  185. defineTabCount = 0;
  186. }
  187. /**
  188. * get indent mode.
  189. * @return true, if ASBeautifier indents using tab.
  190. */
  191. public final boolean getUseTabs() {
  192. return indentString.equals("\t");
  193. }
  194. /**
  195. * set indent mode.
  196. * @param useTabs true if ASBeautifier should indent using tabs,
  197. * otherwise indent using spaces.
  198. */
  199. public final void setUseTabs(boolean useTabs) {
  200. if (useTabs)
  201. setTabIndentation(indentLength);
  202. else
  203. setSpaceIndentation(indentLength);
  204. }
  205. /**
  206. * get tab indentation.
  207. * @return number of spaces to assume for one tab.
  208. */
  209. public final int getTabIndentation() {
  210. return indentLength;
  211. }
  212. /**
  213. * indent using one tab per indentation.
  214. * @param length assume each tab is this spaces long.
  215. */
  216. public final void setTabIndentation(int length) {
  217. indentString = "\t";
  218. indentLength = length;
  219. if (!isMinimalConditinalIndentSet)
  220. minConditionalIndent = indentLength * 2;
  221. }
  222. /**
  223. * get value of 'forceTabs' property.
  224. * @return the value of the <code>forceTabs</code> property.
  225. */
  226. public final boolean getForceTabs() {
  227. return shouldForceTabIndentation;
  228. }
  229. /**
  230. * enforce usage of tabs.
  231. * @param forceTabs if true, the beautifier uses tabs in areas where
  232. * it otherwise would use spaces.
  233. */
  234. public final void setForceTabs(boolean forceTabs) {
  235. shouldForceTabIndentation = forceTabs;
  236. }
  237. /**
  238. * get space indentation.
  239. * @return number of spaces per indent.
  240. */
  241. public final int getSpaceIndentation() {
  242. return indentLength;
  243. }
  244. /**
  245. * indent using a number of spaces per indentation.
  246. * @param length number of spaces per indent. The default is 4.
  247. */
  248. public final void setSpaceIndentation(int length) {
  249. StringBuffer indentBuf = new StringBuffer();
  250. for (int i = 0; i < length; i++)
  251. indentBuf.append(' ');
  252. indentString = indentBuf.toString();
  253. indentLength = length;
  254. if (!isMinimalConditinalIndentSet)
  255. minConditionalIndent = indentLength * 2;
  256. }
  257. /**
  258. * get maximum indentation between two lines in a multi-line statement.
  259. * @return maximum indentation length.
  260. */
  261. public final int getMaxInStatementIndentLength() {
  262. return maxInStatementIndent;
  263. }
  264. /**
  265. * set the maximum indentation between two lines in a multi-line statement.
  266. * @param max maximum indentation length.
  267. */
  268. public final void setMaxInStatementIndentLength(int max) {
  269. maxInStatementIndent = max;
  270. }
  271. /**
  272. * get the minimum indentation between two lines in a multi-line condition.
  273. * @return minimal indentation length. The default is twice the indent level.
  274. * @see #setSpaceIndentation(int)
  275. */
  276. public final int getMinConditionalIndentLength() {
  277. if (!isMinimalConditinalIndentSet)
  278. setMinConditionalIndentLength(indentLength * 2);
  279. return minConditionalIndent;
  280. }
  281. /**
  282. * set the minimum indentation between two lines in a multi-line condition.
  283. * @param min minimal indentation length.
  284. */
  285. public final void setMinConditionalIndentLength(int min) {
  286. minConditionalIndent = min;
  287. isMinimalConditinalIndentSet = true;
  288. }
  289. /**
  290. * get the state of the class indentation option. If true, C++ class
  291. * definitions will be indented one additional indent.
  292. * @return state of option.
  293. */
  294. public final boolean getClassIndent() {
  295. return classIndent;
  296. }
  297. /**
  298. * set the state of the class indentation option. If true, C++ class
  299. * definitions will be indented one additional indent.
  300. * @param state state of option.
  301. */
  302. public final void setClassIndent(boolean state) {
  303. classIndent = state;
  304. }
  305. /**
  306. * get the state of the switch indentation option. If true, blocks of
  307. * 'switch' statements will be indented one additional indent.
  308. * @return state of option.
  309. */
  310. public final boolean getSwitchIndent() {
  311. return switchIndent;
  312. }
  313. /**
  314. * set the state of the switch indentation option. If true, blocks of
  315. * 'switch' statements will be indented one additional indent.
  316. * @param state state of option.
  317. */
  318. public final void setSwitchIndent(boolean state) {
  319. switchIndent = state;
  320. }
  321. /**
  322. * get the state of the case indentation option. If true, lines of 'case'
  323. * statements will be indented one additional indent.
  324. * @return state of option.
  325. */
  326. public final boolean getCaseIndent() {
  327. return caseIndent;
  328. }
  329. /**
  330. * set the state of the case indentation option. If true, lines of 'case'
  331. * statements will be indented one additional indent.
  332. * @param state state of option.
  333. */
  334. public final void setCaseIndent(boolean state) {
  335. caseIndent = state;
  336. }
  337. /**
  338. * get the state of the bracket indentation option. If true, brackets will
  339. * be indented one additional indent.
  340. * @return state of option.
  341. */
  342. public final boolean getBracketIndent() {
  343. return bracketIndent;
  344. }
  345. /**
  346. * set the state of the bracket indentation option. If true, brackets will
  347. * be indented one additional indent.
  348. * @param state state of option.
  349. */
  350. public final void setBracketIndent(boolean state) {
  351. if (state)
  352. setBlockIndent(false); // so that we don't have both bracket and block indent
  353. bracketIndent = state;
  354. }
  355. /**
  356. * get the state of the block indentation option. If true, entire blocks
  357. * will be indented one additional indent, similar to the GNU indent style.
  358. * @param state state of option.
  359. */
  360. public final boolean getBlockIndent() {
  361. return blockIndent;
  362. }
  363. /**
  364. * set the state of the block indentation option. If true, entire blocks
  365. * will be indented one additional indent, similar to the GNU indent style.
  366. * @param state state of option.
  367. */
  368. public final void setBlockIndent(boolean state) {
  369. if (state)
  370. setBracketIndent(false); // so that we don't have both bracket and block indent
  371. blockIndent = state;
  372. }
  373. /**
  374. * get the state of the namespace indentation option.
  375. * If true, blocks of 'namespace' statements will be indented one
  376. * additional indent. Otherwise, NO indentation will be added.
  377. * @return state of option.
  378. */
  379. public final boolean getNamespaceIndent() {
  380. return namespaceIndent;
  381. }
  382. /**
  383. * set the state of the namespace indentation option.
  384. * If true, blocks of 'namespace' statements will be indented one
  385. * additional indent. Otherwise, NO indentation will be added.
  386. * @param state state of option.
  387. */
  388. public final void setNamespaceIndent(boolean state) {
  389. namespaceIndent = state;
  390. }
  391. /**
  392. * get the state of the label indentation option.
  393. * If true, labels will be indented one indent LESS than the
  394. * current indentation level.
  395. * If false, labels will be flushed to the left with NO
  396. * indent at all.
  397. * @return state of option.
  398. */
  399. public final boolean getLabelIndent() {
  400. return labelIndent;
  401. }
  402. /**
  403. * set the state of the label indentation option.
  404. * If true, labels will be indented one indent LESS than the
  405. * current indentation level.
  406. * If false, labels will be flushed to the left with NO
  407. * indent at all.
  408. * @param state state of option.
  409. */
  410. public final void setLabelIndent(boolean state) {
  411. labelIndent = state;
  412. }
  413. /**
  414. * return true, if C formatting style is on.
  415. * @return true, if C formatting style is on, otherwise false.
  416. */
  417. public final boolean isCStyle() {
  418. return isCStyle;
  419. }
  420. /**
  421. * set C formatting style. Set this to true, if you want to beautify a
  422. * C/C++ file. If true, the beautifier performs additional indenting
  423. * on templates and precompiler instructions, among other things.
  424. * Corresponds to the options "--mode=c" and "--mode=java".
  425. * @param state if true, C formatting style is on, otherwise off.
  426. */
  427. public final void setCStyle(boolean state) {
  428. isCStyle = state;
  429. }
  430. /**
  431. * get the state of the empty line fill option.
  432. * If true, empty lines will be filled with the whitespace.
  433. * of their previous lines.
  434. * If false, these lines will remain empty.
  435. * @return state of option.
  436. */
  437. public final boolean getEmptyLineFill() {
  438. return emptyLineFill;
  439. }
  440. /**
  441. * set the state of the empty line fill option.
  442. * If true, empty lines will be filled with the whitespace.
  443. * of their previous lines.
  444. * If false, these lines will remain empty.
  445. * @param state state of option.
  446. */
  447. public final void setEmptyLineFill(boolean state) {
  448. emptyLineFill = state;
  449. }
  450. /**
  451. * get the state of the preprocessor indentation option.
  452. * If true, multiline #define statements will be indented.
  453. * @return state of option.
  454. */
  455. public final boolean getPreprocessorIndent() {
  456. return preprocessorIndent;
  457. }
  458. /**
  459. * set the state of the preprocessor indentation option.
  460. * If true, multiline #define statements will be indented.
  461. * @param state state of option.
  462. */
  463. public final void setPreprocessorIndent(boolean state) {
  464. preprocessorIndent = state;
  465. }
  466. /**
  467. * check if there are any indented lines ready to be read by nextLine()
  468. * @return are there any indented lines ready?
  469. */
  470. public boolean hasMoreLines() {
  471. return sourceIterator.hasMoreLines();
  472. }
  473. /**
  474. * get the next indented line.
  475. * @return indented line.
  476. */
  477. public String nextLine() {
  478. return beautify(sourceIterator.nextLine());
  479. }
  480. /**
  481. * beautify a line of source code.
  482. * every line of source code in a source code file should be sent
  483. * one after the other to the beautify method.
  484. * @return the indented line.
  485. * @param originalLine the original unindented line.
  486. */
  487. protected String beautify(String originalLine) {
  488. String line;
  489. boolean isInLineComment = false;
  490. boolean isInClass = false;
  491. boolean isInSwitch = false;
  492. boolean isImmediatelyAfterConst = false;
  493. boolean isSpecialChar = false;
  494. char ch = ' ';
  495. char prevCh;
  496. StringBuffer outBuffer = new StringBuffer(); // the newly idented line is buffered here
  497. int tabCount = 0;
  498. String lastLineHeader = null;
  499. boolean closingBracketReached = false;
  500. int spaceTabCount = 0;
  501. char tempCh;
  502. int headerStackSize = headerStack.size();
  503. //boolean isLineInStatement = isInStatement;
  504. boolean shouldIndentBrackettedLine = true;
  505. int lineOpeningBlocksNum = 0;
  506. int lineClosingBlocksNum = 0;
  507. boolean previousLineProbation = (probationHeader != null);
  508. int i;
  509. currentHeader = null;
  510. // handle and remove white spaces around the line:
  511. // If not in comment, first find out size of white space before line,
  512. // so that possible comments starting in the line continue in
  513. // relation to the preliminary white-space.
  514. if (!isInComment) {
  515. leadingWhiteSpaces = 0;
  516. while (leadingWhiteSpaces < originalLine.length() && originalLine.charAt(leadingWhiteSpaces) <= 0x20)
  517. leadingWhiteSpaces++;
  518. line = originalLine.trim();
  519. } else {
  520. int trimSize;
  521. for (trimSize = 0;
  522. trimSize < originalLine.length() && trimSize < leadingWhiteSpaces && originalLine.charAt(trimSize) <= 0x20;
  523. trimSize++)
  524. ;
  525. line = originalLine.substring(trimSize);
  526. }
  527. if (line.length() == 0)
  528. if (emptyLineFill)
  529. return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
  530. else
  531. return line;
  532. // handle preprocessor commands
  533. if (isCStyle && !isInComment && (line.charAt(0) == '#' || backslashEndsPrevLine)) {
  534. if (line.charAt(0) == '#') {
  535. String preproc = line.substring(1).trim();
  536. // When finding a multi-lined #define statement, the original beautifier
  537. // 1. sets its isInDefineDefinition flag
  538. // 2. clones a new beautifier that will be used for the actual indentation
  539. // of the #define. This clone is put into the activeBeautifierStack in order
  540. // to be called for the actual indentation.
  541. // The original beautifier will have isInDefineDefinition = true, isInDefine = false.
  542. // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true.
  543. if (preprocessorIndent && preproc.equals("define") && line.endsWith("\\")) {
  544. if (!isInDefineDefinition) {
  545. // this is the original beautifier
  546. isInDefineDefinition = true;
  547. // push a new beautifier into the active stack
  548. // this breautifier will be used for the indentation of this define
  549. ASBeautifier defineBeautifier = new ASBeautifier(this);
  550. //defineBeautifier.init();
  551. //defineBeautifier.isInDefineDefinition = true;
  552. //defineBeautifier.beautify("");
  553. activeBeautifierStack.push_back(defineBeautifier);
  554. } else {
  555. // this is the cloned beautifier that is in charge of indenting the #define.
  556. isInDefine = true;
  557. }
  558. }
  559. else if (preproc.equals("if")) {
  560. // push a new beautifier into the stack
  561. waitingBeautifierStackLengthStack.push_back(waitingBeautifierStack.size());
  562. activeBeautifierStackLengthStack.push_back(activeBeautifierStack.size());
  563. waitingBeautifierStack.push_back(new ASBeautifier(this));
  564. }
  565. else if (preproc.equals("else")) {
  566. if (!waitingBeautifierStack.empty()) {
  567. // MOVE current waiting beautifier to active stack.
  568. activeBeautifierStack.push_back(waitingBeautifierStack.back());
  569. waitingBeautifierStack.pop_back();
  570. }
  571. }
  572. else if (preproc.equals("elif")) {
  573. if (!waitingBeautifierStack.empty()) {
  574. // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
  575. activeBeautifierStack.push_back(new ASBeautifier(waitingBeautifierStack.back()));
  576. }
  577. }
  578. else if (preproc.equals("endif")) {
  579. int stackLength;
  580. ASBeautifier beautifier;
  581. if (!waitingBeautifierStackLengthStack.empty()) {
  582. stackLength = waitingBeautifierStackLengthStack.back();
  583. waitingBeautifierStackLengthStack.pop_back();
  584. while (waitingBeautifierStack.size() > stackLength) {
  585. beautifier = waitingBeautifierStack.back();
  586. waitingBeautifierStack.pop_back();
  587. beautifier = null;
  588. }
  589. }
  590. if (!activeBeautifierStackLengthStack.empty()) {
  591. stackLength = activeBeautifierStackLengthStack.back();
  592. activeBeautifierStackLengthStack.pop_back();
  593. while (activeBeautifierStack.size() > stackLength) {
  594. beautifier = activeBeautifierStack.back();
  595. activeBeautifierStack.pop_back();
  596. beautifier = null;
  597. }
  598. }
  599. }
  600. } // if (line.charAt(0) == '#')
  601. // check if the last char is a backslash
  602. if (line.length() > 0)
  603. backslashEndsPrevLine = line.endsWith("\\");
  604. else
  605. backslashEndsPrevLine = false;
  606. // check if this line ends a multi-line #define.
  607. // if so, use the #define's cloned beautifier for the line's indentation
  608. // and then remove it from the active beautifier stack and delete it.
  609. if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine) {
  610. String beautifiedLine;
  611. ASBeautifier defineBeautifier;
  612. isInDefineDefinition = false;
  613. defineBeautifier = activeBeautifierStack.back();
  614. activeBeautifierStack.pop_back();
  615. beautifiedLine = defineBeautifier.beautify(line);
  616. defineBeautifier = null;
  617. return beautifiedLine;
  618. }
  619. // unless this is a multi-line #define, return this precompiler line as is.
  620. if (!isInDefine && !isInDefineDefinition)
  621. return originalLine;
  622. } // if preprocessor command
  623. // if there exists any worker beautifier in the activeBeautifierStack,
  624. // then use it instead of me to indent the current line.
  625. if (!isInDefine && activeBeautifierStack != null && !activeBeautifierStack.empty())
  626. return activeBeautifierStack.back().beautify(line);
  627. // calculate preliminary indentation based on data from past lines
  628. if (!inStatementIndentStack.empty())
  629. spaceTabCount = inStatementIndentStack.back();
  630. for (i = 0; i < headerStackSize; i++) {
  631. isInClass = false;
  632. if (blockIndent || (!(i > 0 && headerStack.at(i-1) != AS_OPEN_BRACKET
  633. && headerStack.at(i) == AS_OPEN_BRACKET)))
  634. ++tabCount;
  635. if (isCStyle && !namespaceIndent && i >= 1
  636. && headerStack.at(i-1) == AS_NAMESPACE
  637. && headerStack.at(i) == AS_OPEN_BRACKET)
  638. --tabCount;
  639. if (isCStyle && i >= 1
  640. && headerStack.at(i-1) == AS_CLASS
  641. && headerStack.at(i) == AS_OPEN_BRACKET)
  642. {
  643. if (classIndent)
  644. ++tabCount;
  645. isInClass = true;
  646. }
  647. else if (switchIndent && i > 1
  648. && headerStack.at(i-1) == AS_SWITCH
  649. && headerStack.at(i) == AS_OPEN_BRACKET)
  650. {
  651. // is the switchIndent option is on, indent switch statements an additional indent.
  652. ++tabCount;
  653. isInSwitch = true;
  654. }
  655. } // for
  656. if (isCStyle && isInClass && classIndent && headerStackSize >= 2
  657. && headerStack.at(headerStackSize-2) == AS_CLASS
  658. && headerStack.at(headerStackSize-1) == AS_OPEN_BRACKET
  659. && line.charAt(0) == '}')
  660. --tabCount;
  661. else if (isInSwitch && switchIndent && headerStackSize >= 2
  662. && headerStack.at(headerStackSize-2) == AS_SWITCH
  663. && headerStack.at(headerStackSize-1) == AS_OPEN_BRACKET
  664. && line.charAt(0) == '}')
  665. --tabCount;
  666. if (isInClassHeader) {
  667. isInClassHeaderTab = true;
  668. tabCount += 2;
  669. }
  670. if (isInConditional)
  671. --tabCount;
  672. // parse characters in the current line.
  673. for (i = 0; i < line.length(); i++) {
  674. tempCh = line.charAt(i);
  675. prevCh = ch;
  676. ch = tempCh;
  677. outBuffer.append(ch);
  678. if (isWhiteSpace(ch))
  679. continue;
  680. // handle special characters (i.e. backslash and characters such as \n, \t, ...)
  681. if (isSpecialChar) {
  682. isSpecialChar = false;
  683. continue;
  684. }
  685. if (!(isInComment || isInLineComment) && line.regionMatches(i, "\\\\", 0, 2)) {
  686. outBuffer.append('\\');
  687. i++;
  688. continue;
  689. }
  690. if (!(isInComment || isInLineComment) && ch=='\\') {
  691. isSpecialChar = true;
  692. continue;
  693. }
  694. // handle quotes (such as 'x' and "Hello Dolly")
  695. if (!(isInComment || isInLineComment) && (ch=='"' || ch=='\'')) {
  696. if (!isInQuote) {
  697. quoteChar = ch;
  698. isInQuote = true;
  699. } else if (quoteChar == ch) {
  700. isInQuote = false;
  701. isInStatement = true;
  702. continue;
  703. }
  704. }
  705. if (isInQuote)
  706. continue;
  707. // handle comments
  708. if (!(isInComment || isInLineComment) && line.regionMatches(i, AS_OPEN_LINE_COMMENT, 0, 2)) {
  709. isInLineComment = true;
  710. outBuffer.append('/');
  711. i++;
  712. continue;
  713. }
  714. else if (!(isInComment || isInLineComment) && line.regionMatches(i, AS_OPEN_COMMENT, 0, 2)) {
  715. isInComment = true;
  716. outBuffer.append('*');
  717. i++;
  718. continue;
  719. }
  720. else if ((isInComment || isInLineComment) && line.regionMatches(i, AS_CLOSE_COMMENT, 0, 2)) {
  721. isInComment = false;
  722. outBuffer.append('/');
  723. i++;
  724. continue;
  725. }
  726. if (isInComment || isInLineComment) {
  727. continue;
  728. }
  729. // if we have reached this far then we are NOT in a comment or string of special character...
  730. if (probationHeader != null) {
  731. if (((probationHeader == AS_STATIC || probationHeader == AS_CONST) && ch == '{')
  732. || (probationHeader == AS_SYNCHRONIZED && ch == '('))
  733. {
  734. // insert the probation header as a new header
  735. isInHeader = true;
  736. headerStack.push_back(probationHeader);
  737. // handle the specific probation header
  738. isInConditional = (probationHeader == AS_SYNCHRONIZED);
  739. if (probationHeader == AS_CONST)
  740. isImmediatelyAfterConst = true;
  741. // isInConst = true;
  742. // TODO:
  743. // There is actually no more need for the global isInConst variable.
  744. // The only reason for checking const is to see if there is a const
  745. // immediately before an open-bracket.
  746. // Since CONST is now put into probation and is checked during itspost-char,
  747. // isImmediatelyAfterConst can be set by its own...
  748. isInStatement = false;
  749. // if the probation comes from the previous line, then indent by 1 tab count.
  750. if (previousLineProbation && ch == '{')
  751. tabCount++;
  752. previousLineProbation = false;
  753. }
  754. // dismiss the probation header
  755. probationHeader = null;
  756. }
  757. prevNonSpaceCh = currentNonSpaceCh;
  758. currentNonSpaceCh = ch;
  759. if (!isLegalNameChar(ch) && ch != ',' && ch != ';') {
  760. prevNonLegalCh = currentNonLegalCh;
  761. currentNonLegalCh = ch;
  762. }
  763. //if (isInConst)
  764. //{
  765. // isInConst = false;
  766. // isImmediatelyAfterConst = true;
  767. //}
  768. if (isInHeader) {
  769. isInHeader = false;
  770. currentHeader = headerStack.back();
  771. }
  772. else
  773. currentHeader = null;
  774. // handle templates
  775. if (isCStyle && isInTemplate
  776. && (ch == '<' || ch == '>')
  777. && findHeader(line, i, nonAssignmentOperators) == null)
  778. {
  779. if (ch == '<')
  780. ++templateDepth;
  781. else if (ch == '>') {
  782. if (--templateDepth <= 0) {
  783. if (isInTemplate)
  784. ch = ';';
  785. else
  786. ch = 't';
  787. isInTemplate = false;
  788. templateDepth = 0;
  789. }
  790. }
  791. }
  792. // handle parenthesies
  793. if (ch == '(' || ch == '[' || ch == ')' || ch == ']') {
  794. if (ch == '(' || ch == '[') {
  795. if (parenDepth == 0) {
  796. parenStatementStack.push_back(isInStatement);
  797. isInStatement = true;
  798. }
  799. parenDepth++;
  800. inStatementIndentStackSizeStack.push_back(inStatementIndentStack.size());
  801. if (currentHeader != null)
  802. registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent /*indentLength*2 */, true);
  803. else
  804. registerInStatementIndent(line, i, spaceTabCount, 0, true);
  805. }
  806. else if (ch == ')' || ch == ']') {
  807. parenDepth--;
  808. if (parenDepth == 0) {
  809. isInStatement = parenStatementStack.back();
  810. parenStatementStack.pop_back();
  811. ch = ' ';
  812. isInConditional = false;
  813. }
  814. if (!inStatementIndentStackSizeStack.empty()) {
  815. int previousIndentStackSize = inStatementIndentStackSizeStack.back();
  816. inStatementIndentStackSizeStack.pop_back();
  817. while (previousIndentStackSize < inStatementIndentStack.size())
  818. inStatementIndentStack.pop_back();
  819. if (!parenIndentStack.empty()) {
  820. int poppedIndent = parenIndentStack.back();
  821. parenIndentStack.pop_back();
  822. if (i == 0)
  823. spaceTabCount = poppedIndent;
  824. }
  825. }
  826. }
  827. continue;
  828. } // if handle parenthesis
  829. // handle block start
  830. if (ch == '{') {
  831. boolean isBlockOpener = false;
  832. // first, check if '{' is a block-opener or an static-array opener
  833. isBlockOpener = ((prevNonSpaceCh == '{' && bracketBlockStateStack.back())
  834. || prevNonSpaceCh == '}'
  835. || prevNonSpaceCh == ')'
  836. || prevNonSpaceCh == ';'
  837. || isInClassHeader
  838. || isBlockOpener
  839. || isImmediatelyAfterConst
  840. || (isInDefine &&
  841. (prevNonSpaceCh == '('
  842. || prevNonSpaceCh == '_'
  843. || Character.isLetterOrDigit(prevNonSpaceCh))));
  844. isInClassHeader = false;
  845. if (!isBlockOpener && currentHeader != null)
  846. if (nonParenHeaders.contains(currentHeader))
  847. isBlockOpener = true;
  848. bracketBlockStateStack.push_back(isBlockOpener);
  849. if (!isBlockOpener) {
  850. inStatementIndentStackSizeStack.push_back(inStatementIndentStack.size());
  851. registerInStatementIndent(line, i, spaceTabCount, 0, true);
  852. parenDepth++;
  853. if (i == 0)
  854. shouldIndentBrackettedLine = false;
  855. continue;
  856. }
  857. // this bracket is a block opener..
  858. ++lineOpeningBlocksNum;
  859. if (isInClassHeader)
  860. isInClassHeader = false;
  861. if (isInClassHeaderTab) {
  862. isInClassHeaderTab = false;
  863. tabCount -= 2;
  864. }
  865. /// danson
  866. if (isInFor) {
  867. isInFor = false;
  868. }
  869. blockParenDepthStack.push_back(parenDepth);
  870. blockStatementStack.push_back(isInStatement);
  871. inStatementIndentStackSizeStack.push_back(inStatementIndentStack.size());
  872. blockTabCount += isInStatement ? 1 : 0;
  873. parenDepth = 0;
  874. isInStatement = false;
  875. tempStacks.push_back(new StringStack());
  876. headerStack.push_back(AS_OPEN_BRACKET);
  877. lastLineHeader = AS_OPEN_BRACKET; // <------
  878. continue;
  879. }
  880. // check if a header has been reached
  881. if (prevCh == ' ') {
  882. boolean isIndentableHeader = true;
  883. String newHeader = findHeader(line, i, headers);
  884. if (newHeader != null) {
  885. // if we reached here, then this is a header...
  886. isInHeader = true;
  887. StringStack lastTempStack;
  888. if (tempStacks.empty())
  889. lastTempStack = null;
  890. else
  891. lastTempStack = (StringStack) tempStacks.back();
  892. // if a new block is opened, push a new stack into tempStacks to hold the
  893. // future list of headers in the new block.
  894. // take care of the special case: 'else if (...)'
  895. if (newHeader == AS_IF && lastLineHeader == AS_ELSE) {
  896. //spaceTabCount += indentLength; // to counter the opposite addition that occurs when the 'if' is registered below...
  897. headerStack.pop_back();
  898. }
  899. // take care of 'else'
  900. else if (newHeader == AS_ELSE) {
  901. if (lastTempStack != null) {
  902. int indexOfIf = lastTempStack.indexOf(AS_IF); // <---
  903. if (indexOfIf != -1) {
  904. // recreate the header list in headerStack up to the previous 'if'
  905. // from the temporary snapshot stored in lastTempStack.
  906. int restackSize = lastTempStack.size() - indexOfIf - 1;
  907. for (int r = 0; r < restackSize; r++) {
  908. headerStack.push_back(lastTempStack.back());
  909. lastTempStack.pop_back();
  910. }
  911. if (!closingBracketReached)
  912. tabCount += restackSize;
  913. }
  914. // If the above if is not true, i.e. no 'if' before the 'else',
  915. // then nothing beautiful will come out of this...
  916. // I should think about inserting an Exception here to notify the caller of this...
  917. }
  918. }
  919. // check if 'while' closes a previous 'do'
  920. else if (newHeader == AS_WHILE) {
  921. if (lastTempStack != null) {
  922. int indexOfDo = lastTempStack.indexOf(AS_DO); // <---
  923. if (indexOfDo != -1) {
  924. // recreate the header list in headerStack up to the previous 'do'
  925. // from the temporary snapshot stored in lastTempStack.
  926. int restackSize = lastTempStack.size() - indexOfDo - 1;
  927. for (int r = 0; r < restackSize; r++) {
  928. headerStack.push_back(lastTempStack.back());
  929. lastTempStack.pop_back();
  930. }
  931. if (!closingBracketReached)
  932. tabCount += restackSize;
  933. }
  934. }
  935. }
  936. /// danson, added check for 'for' for Java 1.5's "for(... : ...)" construct
  937. else if (newHeader == AS_FOR) {
  938. isInFor = true;
  939. }
  940. // check if 'catch' closes a previous 'try' or 'catch'
  941. else if (newHeader == AS_CATCH || newHeader == AS_FINALLY) {
  942. if (lastTempStack != null) {
  943. int indexOfTry = lastTempStack.indexOf(AS_TRY);
  944. if (indexOfTry == -1)
  945. indexOfTry = lastTempStack.indexOf(AS_CATCH);
  946. if (indexOfTry != -1) {
  947. // recreate the header list in headerStack up to the previous 'try'
  948. // from the temporary snapshot stored in lastTempStack.
  949. int restackSize = lastTempStack.size() - indexOfTry - 1;
  950. for (int r = 0; r < restackSize; r++) {
  951. headerStack.push_back(lastTempStack.back());
  952. lastTempStack.pop_back();
  953. }
  954. if (!closingBracketReached)
  955. tabCount += restackSize;
  956. }
  957. }
  958. }
  959. else if (newHeader == AS_CASE) {
  960. isInCase = true;
  961. if (!caseIndent)
  962. --tabCount;
  963. }
  964. else if (newHeader == AS_DEFAULT) {
  965. isInCase = true;
  966. if (!caseIndent)
  967. --tabCount;
  968. }
  969. else if (newHeader == AS_PUBLIC || newHeader == AS_PROTECTED || newHeader == AS_PRIVATE) {
  970. if (isCStyle && !isInClassHeader)
  971. --tabCount;
  972. isIndentableHeader = false;
  973. }
  974. //else if ((newHeader == AS_STATIC || newHeader == AS_SYNCHRONIZED) &&
  975. // !headerStack.empty() &&
  976. // (headerStack.back() == AS_STATIC || headerStack.back() == AS_SYNCHRONIZED))
  977. //{
  978. // isIndentableHeader = false;
  979. //}
  980. else if (newHeader == AS_STATIC
  981. || newHeader == AS_SYNCHRONIZED
  982. || (newHeader == AS_CONST && isCStyle))
  983. {
  984. if (!headerStack.empty()
  985. && (headerStack.back() == AS_STATIC
  986. || headerStack.back() == AS_SYNCHRONIZED
  987. || headerStack.back() == AS_CONST))
  988. {
  989. isIndentableHeader = false;
  990. } else {
  991. isIndentableHeader = false;
  992. probationHeader = newHeader;
  993. }
  994. }
  995. else if (newHeader == AS_CONST) {
  996. // this will be entered only if NOT in C style
  997. // since otherwise the CONST would be found to be a probation header...
  998. isIndentableHeader = false;
  999. }
  1000. /*
  1001. else if (newHeader == AS_OPERATOR) {
  1002. if (isCStyle) {
  1003. isInOperator = true;
  1004. }
  1005. isIndentableHeader = false;
  1006. }
  1007. */
  1008. else if (newHeader == AS_TEMPLATE) {
  1009. if (isCStyle)
  1010. isInTemplate = true;
  1011. isIndentableHeader = false;
  1012. }
  1013. if (isIndentableHeader) {
  1014. //spaceTabCount -= indentLength;
  1015. headerStack.push_back(newHeader);
  1016. isInStatement = false;
  1017. if (nonParenHeaders.indexOf(newHeader) == -1)
  1018. isInConditional = true;
  1019. lastLineHeader = newHeader;
  1020. }
  1021. else
  1022. isInHeader = false;
  1023. //lastLineHeader = newHeader;
  1024. outBuffer.append(newHeader.substring(1));
  1025. i += newHeader.length() - 1;
  1026. continue;
  1027. } // if (newHeader != null)
  1028. } // if (prevCh == ' ')
  1029. // handle operators
  1030. if (isCStyle &&
  1031. !Character.isLetter(prevCh) &&
  1032. line.regionMatches(i, AS_OPERATOR, 0, 8) &&
  1033. !Character.isLetterOrDigit(line.charAt(i+8)))
  1034. {
  1035. isInOperator = true;
  1036. outBuffer.append(AS_OPERATOR.substring(1));
  1037. i += 7;
  1038. continue;
  1039. }
  1040. if (ch == '?')
  1041. isInQuestion = true;
  1042. // special handling of 'case' statements
  1043. if (ch == ':') {
  1044. if (line.length() > i+1 && line.charAt(i+1) == ':') {
  1045. // this is '::'
  1046. ++i;
  1047. outBuffer.append(':');
  1048. ch = ' ';
  1049. continue;
  1050. }
  1051. else if (isCStyle && isInClass && prevNonSpaceCh != ')') {
  1052. --tabCount;
  1053. // found a 'private:' or 'public:' inside a class definition,
  1054. // so do nothing special
  1055. }
  1056. else if (isCStyle && isInClassHeader) {
  1057. // found a 'class A : public B' definition
  1058. // so do nothing special
  1059. }
  1060. else if (isInQuestion) {
  1061. isInQuestion = false;
  1062. }
  1063. else if (isInFor) { /// danson
  1064. continue;
  1065. }
  1066. else if (isCStyle && prevNonSpaceCh == ')') {
  1067. isInClassHeader = true;
  1068. if (i==0)
  1069. tabCount += 2;
  1070. }
  1071. else {
  1072. currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
  1073. if (isInCase) {
  1074. isInCase = false;
  1075. ch = ';'; // from here on, treat char as ';'
  1076. } else {
  1077. // is in a label (e.g. 'label1:')
  1078. if (labelIndent)
  1079. --tabCount; // unindent label by one indent
  1080. else
  1081. tabCount = 0; // completely flush indent to left
  1082. }
  1083. }
  1084. }
  1085. if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack.empty())
  1086. while (inStatementIndentStackSizeStack.back() + (parenDepth > 0 ? 1 : 0) < inStatementIndentStack.size())
  1087. inStatementIndentStack.pop_back();
  1088. // handle ends of statements
  1089. if ((ch == ';' && parenDepth == 0) || ch == '}') {
  1090. if (ch == '}') {
  1091. // first check if this '}' closes a previous block, or a static array...
  1092. if (!bracketBlockStateStack.empty()) {
  1093. boolean bracketBlockState = bracketBlockStateStack.back();
  1094. bracketBlockStateStack.pop_back();
  1095. if (!bracketBlockState) {
  1096. if (!inStatementIndentStackSizeStack.empty()) {
  1097. // this bracket is a static array
  1098. int previousIndentStackSize = inStatementIndentStackSizeStack.back();
  1099. inStatementIndentStackSizeStack.pop_back();
  1100. while (previousIndentStackSize < inStatementIndentStack.size()) {
  1101. inStatementIndentStack.pop_back();
  1102. }
  1103. parenDepth--;
  1104. if (i == 0)
  1105. shouldIndentBrackettedLine = false;
  1106. if (!parenIndentStack.empty()) {
  1107. int poppedIndent = parenIndentStack.back();
  1108. parenIndentStack.pop_back();
  1109. if (i == 0)
  1110. spaceTabCount = poppedIndent;
  1111. }
  1112. }
  1113. continue;
  1114. }
  1115. }
  1116. // this bracket is block closer...
  1117. ++lineClosingBlocksNum;
  1118. if(!inStatementIndentStackSizeStack.empty())
  1119. inStatementIndentStackSizeStack.pop_back();
  1120. if (!blockParenDepthStack.empty()) {
  1121. parenDepth = blockParenDepthStack.back();
  1122. blockParenDepthStack.pop_back();