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.DefaultAutoIndentStrategy;
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 DefaultAutoIndentStrategy {
24 public PHPAutoIndentStrategy() {
28 * 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 strings.
41 private boolean endsWithDelimiter(IDocument d, String txt) {
43 String[] delimiters= d.getLegalLineDelimiters();
45 for (int i= 0; i < delimiters.length; i++) {
46 if (txt.endsWith(delimiters[i]))
54 * Returns the line number of the next bracket after end.
55 * @returns the line number of the next matching bracket after end
56 * @param document - the document being parsed
57 * @param line - the line to start searching back from
58 * @param end - the end position to search back from
59 * @param closingBracketIncrease - the number of brackets to skip
61 protected int findMatchingOpenBracket(IDocument document, int line, int end, int closingBracketIncrease) throws BadLocationException {
63 int start= document.getLineOffset(line);
64 int brackcount= getBracketCount(document, start, end, false) - closingBracketIncrease;
66 // sum up the brackets counts of each line (closing brackets count negative,
67 // opening positive) until we find a line the brings the count to zero
68 while (brackcount < 0) {
73 start= document.getLineOffset(line);
74 end= start + document.getLineLength(line) - 1;
75 brackcount += getBracketCount(document, start, end, false);
81 * Returns the bracket value of a section of text. Closing brackets have a value of -1 and
82 * open brackets have a value of 1.
83 * @returns the line number of the next matching bracket after end
84 * @param document - the document being parsed
85 * @param start - the start position for the search
86 * @param end - the end position for the search
87 * @param ignoreCloseBrackets - whether or not to ignore closing brackets in the count
89 private int getBracketCount(IDocument document, int start, int end, boolean ignoreCloseBrackets) throws BadLocationException {
94 char curr= document.getChar(begin);
99 char next= document.getChar(begin);
101 // a comment starts, advance to the comment end
102 begin= getCommentEnd(document, begin + 1, end);
103 } else if (next == '/') {
104 // '//'-comment: nothing to do anymore on this line
111 char next= document.getChar(begin);
113 // we have been in a comment: forget what we read before
121 ignoreCloseBrackets= false;
124 if (!ignoreCloseBrackets) {
130 begin= getStringEnd(document, begin, end, curr);
139 * Returns the end position a comment starting at pos.
140 * @returns the end position a comment starting at pos
141 * @param document - the document being parsed
142 * @param position - the start position for the search
143 * @param end - the end position for the search
145 private int getCommentEnd(IDocument document, int position, int end) throws BadLocationException {
146 int currentPosition = position;
147 while (currentPosition < end) {
148 char curr= document.getChar(currentPosition);
151 if (currentPosition < end && document.getChar(currentPosition) == '/') {
152 return currentPosition + 1;
160 * Returns the String at line with the leading whitespace removed.
161 * @returns the String at line with the leading whitespace removed.
162 * @param document - the document being parsed
163 * @param line - the line being searched
165 protected String getIndentOfLine(IDocument document, int line) throws BadLocationException {
167 int start= document.getLineOffset(line);
168 int end= start + document.getLineLength(line) - 1;
169 int whiteend= findEndOfWhiteSpace(document, start, end);
170 return document.get(start, whiteend - start);
172 return ""; //$NON-NLS-1$
177 * Returns the position of the character in the document after position.
178 * @returns the next location of character.
179 * @param document - the document being parsed
180 * @param position - the position to start searching from
181 * @param end - the end of the document
182 * @param character - the character you are trying to match
184 private int getStringEnd(IDocument document, int position, int end, char character) throws BadLocationException {
185 int currentPosition = position;
186 while (currentPosition < end) {
187 char currentCharacter= document.getChar(currentPosition);
189 if (currentCharacter == '\\') {
190 // ignore escaped characters
192 } else if (currentCharacter == character) {
193 return currentPosition;
200 * Set the indent of a new line based on the command provided in the supplied document.
201 * @param document - the document being parsed
202 * @param command - the command being performed
204 protected void smartIndentAfterNewLine(IDocument document, DocumentCommand command) {
206 int docLength= document.getLength();
207 if (command.offset == -1 || docLength == 0)
211 int p= (command.offset == docLength ? command.offset - 1 : command.offset);
212 int line= document.getLineOfOffset(p);
214 StringBuffer buf= new StringBuffer(command.text);
215 if (command.offset < docLength && document.getChar(command.offset) == '}') {
216 int indLine= findMatchingOpenBracket(document, line, command.offset, 0);
220 buf.append(getIndentOfLine(document, indLine));
222 int start= document.getLineOffset(line);
223 int whiteend= findEndOfWhiteSpace(document, start, command.offset);
225 // if (command.offset > 0 && command.offset < docLength && document.getChar(command.offset-1) == '{') {
226 // offset = command.offset;
228 buf.append(document.get(start, whiteend - start));
229 if (getBracketCount(document, start, command.offset, true) > 0) {
232 // if (offset >= 0) {
236 command.text= buf.toString();
238 } catch (BadLocationException excp) {
239 System.out.println(PHPEditorMessages.getString("AutoIndent.error.bad_location_1")); //$NON-NLS-1$
244 * Set the indent of a bracket based on the command provided in the supplied document.
245 * @param document - the document being parsed
246 * @param command - the command being performed
248 protected void smartInsertAfterBracket(IDocument document, DocumentCommand command) {
249 if (command.offset == -1 || document.getLength() == 0)
253 int p= (command.offset == document.getLength() ? command.offset - 1 : command.offset);
254 int line= document.getLineOfOffset(p);
255 int start= document.getLineOffset(line);
256 int whiteend= findEndOfWhiteSpace(document, start, command.offset);
258 // shift only when line does not contain any text up to the closing bracket
259 if (whiteend == command.offset) {
260 // evaluate the line with the opening bracket that matches out closing bracket
261 int indLine= findMatchingOpenBracket(document, line, command.offset, 1);
262 if (indLine != -1 && indLine != line) {
263 // take the indent of the found line
264 StringBuffer replaceText= new StringBuffer(getIndentOfLine(document, indLine));
265 // add the rest of the current line including the just added close bracket
266 replaceText.append(document.get(whiteend, command.offset - whiteend));
267 replaceText.append(command.text);
268 // modify document command
269 command.length= command.offset - start;
270 command.offset= start;
271 command.text= replaceText.toString();
274 } catch (BadLocationException excp) {
275 System.out.println(PHPEditorMessages.getString("AutoIndent.error.bad_location_2")); //$NON-NLS-1$