PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/indent/DeepIndentRule.java

#
Java | 231 lines | 160 code | 21 blank | 50 comment | 36 complexity | 2a250ef3c1501601327745168d5445b1 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * DeepIndentRule.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2006 Matthieu Casanova
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.indent;
  23. import org.gjt.sp.jedit.TextUtilities;
  24. import org.gjt.sp.jedit.buffer.JEditBuffer;
  25. import org.gjt.sp.jedit.syntax.Token;
  26. import org.gjt.sp.jedit.syntax.TokenHandler;
  27. import org.gjt.sp.jedit.syntax.TokenMarker;
  28. import java.util.List;
  29. import java.util.Stack;
  30. import javax.swing.text.Segment;
  31. /**
  32. * Deep indent rule.
  33. *
  34. * @author Matthieu Casanova
  35. * @version $Id: DeepIndentRule.java 20108 2011-10-18 12:16:38Z evanpw $
  36. */
  37. public class DeepIndentRule implements IndentRule
  38. {
  39. private final char openChar;
  40. private final char closeChar;
  41. //{{{ DeepIndentRule constructor
  42. public DeepIndentRule(char openChar, char closeChar)
  43. {
  44. this.openChar = openChar;
  45. this.closeChar = closeChar;
  46. } //}}}
  47. //{{{ apply() method
  48. public void apply(JEditBuffer buffer, int thisLineIndex,
  49. int prevLineIndex, int prevPrevLineIndex,
  50. List<IndentAction> indentActions)
  51. {
  52. if (prevLineIndex == -1)
  53. return;
  54. int lineIndex = prevLineIndex;
  55. int oldLineIndex = lineIndex;
  56. CharSequence lineText = buffer.getLineSegment(lineIndex);
  57. int searchPos = -1;
  58. while (true)
  59. {
  60. if (lineIndex != oldLineIndex)
  61. {
  62. lineText = buffer.getLineSegment(lineIndex);
  63. oldLineIndex = lineIndex;
  64. }
  65. Parens parens = new Parens(buffer, lineIndex, searchPos);
  66. // No unmatched parens on prev line.
  67. if (parens.openOffset == -1 && parens.closeOffset == -1)
  68. {
  69. // Try prev-prev line if present.
  70. if (prevPrevLineIndex != -1) {
  71. searchPos = -1;
  72. lineIndex = prevPrevLineIndex;
  73. prevPrevLineIndex = -1;
  74. continue;
  75. }
  76. return;
  77. }
  78. // There's an unmatched open parenthesis - we want to
  79. // align according to its position.
  80. if (parens.closeOffset == -1)
  81. {
  82. // recalculate column (when using tabs instead of spaces)
  83. int indent = parens.openOffset + getIndent(lineText, buffer.getTabSize()) - lineText.length();
  84. indentActions.clear();
  85. indentActions.add(new IndentAction.AlignParameter(indent));
  86. return;
  87. }
  88. // There's an unmatched closed parenthesis - find the
  89. // matching parenthesis and start looking from there again.
  90. int openParenOffset = TextUtilities.findMatchingBracket(buffer, lineIndex, parens.closeOffset);
  91. if (openParenOffset >= 0)
  92. {
  93. // Avoid falling back to the prev-prev line in this case.
  94. prevPrevLineIndex = -1;
  95. lineIndex = buffer.getLineOfOffset(openParenOffset);
  96. searchPos = openParenOffset - buffer.getLineStartOffset(lineIndex) - 1;
  97. if (searchPos < 0)
  98. break;
  99. }
  100. else
  101. break;
  102. }
  103. } //}}}
  104. //{{{ getIndent() method
  105. /**
  106. * Returns the length of the string as if it were indented with
  107. * spaces instead of tabs.
  108. */
  109. private int getIndent(CharSequence line, int tabSize)
  110. {
  111. int cnt = 0;
  112. for (int i = 0; i < line.length(); i++)
  113. {
  114. if (line.charAt(i) == '\t')
  115. {
  116. cnt += tabSize;
  117. }
  118. else
  119. {
  120. if (!Character.isWhitespace(line.charAt(i)))
  121. {
  122. cnt += (line.length() - i);
  123. break;
  124. }
  125. cnt++;
  126. }
  127. }
  128. return cnt;
  129. } //}}}
  130. //{{{ Parens class
  131. /**
  132. * A token filter that looks for the position of the open and
  133. * close characters in the line being parsed. Characters inside
  134. * literals and comments are ignored.
  135. */
  136. private class Parens implements TokenHandler
  137. {
  138. int openOffset;
  139. int closeOffset;
  140. private int searchPos;
  141. private Stack<Integer> open;
  142. private Stack<Integer> close;
  143. Parens(JEditBuffer b, int line, int pos)
  144. {
  145. this.searchPos = pos;
  146. this.open = new Stack<Integer>();
  147. this.close = new Stack<Integer>();
  148. b.markTokens(line, this);
  149. openOffset = (open.isEmpty()) ? -1 : open.pop();
  150. closeOffset = (close.isEmpty()) ? -1 : close.pop();
  151. }
  152. public void handleToken(Segment seg,
  153. byte id,
  154. int offset,
  155. int length,
  156. TokenMarker.LineContext context)
  157. {
  158. if (length <= 0 ||
  159. (searchPos != -1 && searchPos < offset))
  160. {
  161. return;
  162. }
  163. if (searchPos != -1 && offset + length > searchPos)
  164. {
  165. length = searchPos - offset + 1;
  166. }
  167. switch (id)
  168. {
  169. case Token.COMMENT1:
  170. case Token.COMMENT2:
  171. case Token.COMMENT3:
  172. case Token.COMMENT4:
  173. case Token.LITERAL1:
  174. case Token.LITERAL2:
  175. case Token.LITERAL3:
  176. case Token.LITERAL4:
  177. /* Ignore comments and literals. */
  178. break;
  179. default:
  180. for (int i = offset; i < offset + length; i++)
  181. {
  182. if (seg.array[seg.offset + i] == openChar)
  183. {
  184. if (open.isEmpty() && !close.isEmpty())
  185. close.pop();
  186. else
  187. open.push(i);
  188. }
  189. else if (seg.array[seg.offset + i] == closeChar)
  190. {
  191. if (close.isEmpty() && !open.isEmpty())
  192. open.pop();
  193. else
  194. close.push(i);
  195. }
  196. }
  197. break;
  198. }
  199. }
  200. public void setLineContext(TokenMarker.LineContext lineContext)
  201. {
  202. /* Do nothing. */
  203. }
  204. @Override
  205. public String toString()
  206. {
  207. return "Parens(" + openOffset + ',' + closeOffset + ')';
  208. }
  209. } //}}}
  210. }