1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 IBM Corporation - Initial implementation
11 **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
14 import org.eclipse.jface.text.BadLocationException;
15 import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy;
16 import org.eclipse.jface.text.DocumentCommand;
17 import org.eclipse.jface.text.IDocument;
20 * Auto indent strategy sensitive to brackets.
22 public class PHPAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
24 public PHPAutoIndentStrategy() {
28 * (non-Javadoc) Method declared on IAutoIndentStrategy
30 public void customizeDocumentCommand(IDocument d, DocumentCommand c) {
31 if (c.length == 0 && c.text != null && endsWithDelimiter(d, c.text))
32 smartIndentAfterNewLine(d, c);
33 else if ("}".equals(c.text)) {
34 smartInsertAfterBracket(d, c);
39 * Returns whether or not the text ends with one of the given search
42 private boolean endsWithDelimiter(IDocument d, String txt) {
44 String[] delimiters = d.getLegalLineDelimiters();
46 for (int i = 0; i < delimiters.length; i++) {
47 if (txt.endsWith(delimiters[i]))
55 * Returns the line number of the next bracket after end.
57 * @returns the line number of the next matching bracket after end
59 * the document being parsed
61 * the line to start searching back from
63 * the end position to search back from
64 * @param closingBracketIncrease -
65 * the number of brackets to skip
67 protected int findMatchingOpenBracket(IDocument document, int line,
68 int end, int closingBracketIncrease) throws BadLocationException {
70 int start = document.getLineOffset(line);
71 int brackcount = getBracketCount(document, start, end, false)
72 - closingBracketIncrease;
74 // sum up the brackets counts of each line (closing brackets count
76 // opening positive) until we find a line the brings the count to zero
77 while (brackcount < 0) {
82 start = document.getLineOffset(line);
83 end = start + document.getLineLength(line) - 1;
84 brackcount += getBracketCount(document, start, end, false);
90 * Returns the bracket value of a section of text. Closing brackets have a
91 * value of -1 and open brackets have a value of 1.
93 * @returns the line number of the next matching bracket after end
95 * the document being parsed
97 * the start position for the search
99 * the end position for the search
100 * @param ignoreCloseBrackets -
101 * whether or not to ignore closing brackets in the count
103 private int getBracketCount(IDocument document, int start, int end,
104 boolean ignoreCloseBrackets) throws BadLocationException {
107 int bracketcount = 0;
108 while (begin < end) {
109 char curr = document.getChar(begin);
114 char next = document.getChar(begin);
116 // a comment starts, advance to the comment end
117 begin = getCommentEnd(document, begin + 1, end);
118 } else if (next == '/') {
119 // '//'-comment: nothing to do anymore on this line
126 char next = document.getChar(begin);
128 // we have been in a comment: forget what we read before
136 ignoreCloseBrackets = false;
139 if (!ignoreCloseBrackets) {
145 begin = getStringEnd(document, begin, end, curr);
154 * Returns the end position a comment starting at pos.
156 * @returns the end position a comment starting at pos
158 * the document being parsed
160 * the start position for the search
162 * the end position for the search
164 private int getCommentEnd(IDocument document, int position, int end)
165 throws BadLocationException {
166 int currentPosition = position;
167 while (currentPosition < end) {
168 char curr = document.getChar(currentPosition);
171 if (currentPosition < end
172 && document.getChar(currentPosition) == '/') {
173 return currentPosition + 1;
181 * Returns the String at line with the leading whitespace removed.
183 * @returns the String at line with the leading whitespace removed.
185 * the document being parsed
187 * the line being searched
189 protected String getIndentOfLine(IDocument document, int line)
190 throws BadLocationException {
192 int start = document.getLineOffset(line);
193 int end = start + document.getLineLength(line) - 1;
194 int whiteend = findEndOfWhiteSpace(document, start, end);
195 return document.get(start, whiteend - start);
197 return ""; //$NON-NLS-1$
202 * Returns the position of the character in the document after position.
204 * @returns the next location of character.
206 * the document being parsed
208 * the position to start searching from
210 * the end of the document
212 * the character you are trying to match
214 private int getStringEnd(IDocument document, int position, int end,
215 char character) throws BadLocationException {
216 int currentPosition = position;
217 while (currentPosition < end) {
218 char currentCharacter = document.getChar(currentPosition);
220 if (currentCharacter == '\\') {
221 // ignore escaped characters
223 } else if (currentCharacter == character) {
224 return currentPosition;
231 * Set the indent of a new line based on the command provided in the
235 * the document being parsed
237 * the command being performed
239 protected void smartIndentAfterNewLine(IDocument document,
240 DocumentCommand command) {
242 int docLength = document.getLength();
243 if (command.offset == -1 || docLength == 0)
247 int p = (command.offset == docLength ? command.offset - 1
249 int line = document.getLineOfOffset(p);
251 StringBuffer buf = new StringBuffer(command.text);
252 if (command.offset < docLength
253 && document.getChar(command.offset) == '}') {
254 int indLine = findMatchingOpenBracket(document, line,
259 buf.append(getIndentOfLine(document, indLine));
261 int start = document.getLineOffset(line);
262 int whiteend = findEndOfWhiteSpace(document, start,
265 // if (command.offset > 0 && command.offset < docLength &&
266 // document.getChar(command.offset-1) == '{') {
267 // offset = command.offset;
269 buf.append(document.get(start, whiteend - start));
270 if (getBracketCount(document, start, command.offset, true) > 0) {
273 // if (offset >= 0) {
277 command.text = buf.toString();
279 } catch (BadLocationException excp) {
280 System.out.println(PHPEditorMessages
281 .getString("AutoIndent.error.bad_location_1")); //$NON-NLS-1$
286 * Set the indent of a bracket based on the command provided in the supplied
290 * the document being parsed
292 * the command being performed
294 protected void smartInsertAfterBracket(IDocument document,
295 DocumentCommand command) {
296 if (command.offset == -1 || document.getLength() == 0)
300 int p = (command.offset == document.getLength() ? command.offset - 1
302 int line = document.getLineOfOffset(p);
303 int start = document.getLineOffset(line);
304 int whiteend = findEndOfWhiteSpace(document, start, command.offset);
306 // shift only when line does not contain any text up to the closing
308 if (whiteend == command.offset) {
309 // evaluate the line with the opening bracket that matches out
311 int indLine = findMatchingOpenBracket(document, line,
313 if (indLine != -1 && indLine != line) {
314 // take the indent of the found line
315 StringBuffer replaceText = new StringBuffer(
316 getIndentOfLine(document, indLine));
317 // add the rest of the current line including the just added
319 replaceText.append(document.get(whiteend, command.offset
321 replaceText.append(command.text);
322 // modify document command
323 command.length = command.offset - start;
324 command.offset = start;
325 command.text = replaceText.toString();
328 } catch (BadLocationException excp) {
329 System.out.println(PHPEditorMessages
330 .getString("AutoIndent.error.bad_location_2")); //$NON-NLS-1$