PageRenderTime 253ms CodeModel.GetById 236ms app.highlight 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
  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
 23package org.gjt.sp.jedit.indent;
 24
 25import org.gjt.sp.jedit.TextUtilities;
 26import org.gjt.sp.jedit.buffer.JEditBuffer;
 27
 28import org.gjt.sp.jedit.syntax.Token;
 29import org.gjt.sp.jedit.syntax.TokenHandler;
 30import org.gjt.sp.jedit.syntax.TokenMarker;
 31
 32import java.util.List;
 33import java.util.Stack;
 34import javax.swing.text.Segment;
 35
 36/**
 37 * Deep indent rule.
 38 *
 39 * @author Matthieu Casanova
 40 * @version $Id: DeepIndentRule.java 20108 2011-10-18 12:16:38Z evanpw $
 41 */
 42public class DeepIndentRule implements IndentRule
 43{
 44	private final char openChar;
 45	private final char closeChar;
 46
 47	//{{{ DeepIndentRule constructor
 48	public DeepIndentRule(char openChar, char closeChar)
 49	{
 50		this.openChar = openChar;
 51		this.closeChar = closeChar;
 52	} //}}}
 53
 54	//{{{ apply() method
 55	public void apply(JEditBuffer buffer, int thisLineIndex,
 56			  int prevLineIndex, int prevPrevLineIndex,
 57			  List<IndentAction> indentActions)
 58	{
 59		if (prevLineIndex == -1)
 60			return;
 61
 62		int lineIndex = prevLineIndex;
 63		int oldLineIndex = lineIndex;
 64		CharSequence lineText = buffer.getLineSegment(lineIndex);
 65		int searchPos = -1;
 66		while (true)
 67		{
 68			if (lineIndex != oldLineIndex)
 69			{
 70				lineText = buffer.getLineSegment(lineIndex);
 71				oldLineIndex = lineIndex;
 72			}
 73			Parens parens = new Parens(buffer, lineIndex, searchPos);
 74
 75			// No unmatched parens on prev line.
 76			if (parens.openOffset == -1 && parens.closeOffset == -1)
 77			{
 78				// Try prev-prev line if present.
 79				if (prevPrevLineIndex != -1) {
 80					searchPos = -1;
 81					lineIndex = prevPrevLineIndex;
 82					prevPrevLineIndex = -1;
 83					continue;
 84				}
 85				return;
 86			}
 87
 88			// There's an unmatched open parenthesis - we want to
 89			// align according to its position.
 90			if (parens.closeOffset == -1)
 91			{
 92				// recalculate column (when using tabs instead of spaces)
 93				int indent = parens.openOffset + getIndent(lineText, buffer.getTabSize()) - lineText.length();
 94				indentActions.clear();
 95				indentActions.add(new IndentAction.AlignParameter(indent));
 96				return;
 97			}
 98
 99			// There's an unmatched closed parenthesis - find the
100			// matching parenthesis and start looking from there again.
101			int openParenOffset = TextUtilities.findMatchingBracket(buffer, lineIndex, parens.closeOffset);
102			if (openParenOffset >= 0)
103			{
104				// Avoid falling back to the prev-prev line in this case.
105				prevPrevLineIndex = -1;
106				lineIndex = buffer.getLineOfOffset(openParenOffset);
107				searchPos = openParenOffset - buffer.getLineStartOffset(lineIndex) - 1;
108				if (searchPos < 0)
109					break;
110			}
111			else
112				break;
113		}
114	} //}}}
115
116	//{{{ getIndent() method
117	/**
118	 * Returns the length of the string as if it were indented with
119	 * spaces instead of tabs.
120	 */
121	private int getIndent(CharSequence line, int tabSize)
122	{
123		int cnt = 0;
124		for (int i = 0;  i < line.length(); i++)
125		{
126			if (line.charAt(i) == '\t')
127			{
128				cnt += tabSize;
129			}
130			else
131			{
132				if (!Character.isWhitespace(line.charAt(i)))
133				{
134					cnt += (line.length() - i);
135					break;
136				}
137				cnt++;
138			}
139		}
140		return cnt;
141	} //}}}
142
143	//{{{ Parens class
144	/**
145	 * A token filter that looks for the position of the open and
146	 * close characters in the line being parsed. Characters inside
147	 * literals and comments are ignored.
148	 */
149	private class Parens implements TokenHandler
150	{
151		int openOffset;
152		int closeOffset;
153
154		private int searchPos;
155		private Stack<Integer> open;
156		private Stack<Integer> close;
157
158		Parens(JEditBuffer b, int line, int pos)
159		{
160			this.searchPos = pos;
161			this.open = new Stack<Integer>();
162			this.close = new Stack<Integer>();
163			b.markTokens(line, this);
164			openOffset = (open.isEmpty()) ? -1 : open.pop();
165			closeOffset = (close.isEmpty()) ? -1 : close.pop();
166		}
167
168		public void handleToken(Segment seg,
169					byte id,
170					int offset,
171					int length,
172					TokenMarker.LineContext context)
173		{
174			if (length <= 0 ||
175			    (searchPos != -1 && searchPos < offset))
176			{
177				return;
178			}
179
180			if (searchPos != -1 && offset + length > searchPos)
181			{
182				length = searchPos - offset + 1;
183			}
184
185			switch (id)
186			{
187			case Token.COMMENT1:
188			case Token.COMMENT2:
189			case Token.COMMENT3:
190			case Token.COMMENT4:
191			case Token.LITERAL1:
192			case Token.LITERAL2:
193			case Token.LITERAL3:
194			case Token.LITERAL4:
195				/* Ignore comments and literals. */
196				break;
197			default:
198				for (int i = offset; i < offset + length; i++)
199				{
200					if (seg.array[seg.offset + i] == openChar)
201					{
202						if (open.isEmpty() && !close.isEmpty())
203							close.pop();
204						else
205							open.push(i);
206					}
207					else if (seg.array[seg.offset + i] == closeChar)
208					{
209						if (close.isEmpty() && !open.isEmpty())
210							open.pop();
211						else
212							close.push(i);
213					}
214				}
215				break;
216			}
217		}
218
219		public void setLineContext(TokenMarker.LineContext lineContext)
220		{
221			/* Do nothing. */
222		}
223
224		@Override
225		public String toString()
226		{
227			return "Parens(" + openOffset + ',' + closeOffset + ')';
228		}
229	} //}}}
230}
231