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$