X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java new file mode 100644 index 0000000..9c961ac --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPAutoIndentStrategy.java @@ -0,0 +1,333 @@ +/********************************************************************** + Copyright (c) 2000, 2002 IBM Corp. and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Common Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/cpl-v10.html + + Contributors: + IBM Corporation - Initial implementation + www.phpeclipse.de + **********************************************************************/ +package net.sourceforge.phpeclipse.phpeditor.php; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DefaultIndentLineAutoEditStrategy; +import org.eclipse.jface.text.DocumentCommand; +import org.eclipse.jface.text.IDocument; + +/** + * Auto indent strategy sensitive to brackets. + */ +public class PHPAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy { + + public PHPAutoIndentStrategy() { + } + + /* + * (non-Javadoc) Method declared on IAutoIndentStrategy + */ + public void customizeDocumentCommand(IDocument d, DocumentCommand c) { + if (c.length == 0 && c.text != null && endsWithDelimiter(d, c.text)) + smartIndentAfterNewLine(d, c); + else if ("}".equals(c.text)) { + smartInsertAfterBracket(d, c); + } + } + + /** + * Returns whether or not the text ends with one of the given search + * strings. + */ + private boolean endsWithDelimiter(IDocument d, String txt) { + + String[] delimiters = d.getLegalLineDelimiters(); + + for (int i = 0; i < delimiters.length; i++) { + if (txt.endsWith(delimiters[i])) + return true; + } + + return false; + } + + /** + * Returns the line number of the next bracket after end. + * + * @returns the line number of the next matching bracket after end + * @param document - + * the document being parsed + * @param line - + * the line to start searching back from + * @param end - + * the end position to search back from + * @param closingBracketIncrease - + * the number of brackets to skip + */ + protected int findMatchingOpenBracket(IDocument document, int line, + int end, int closingBracketIncrease) throws BadLocationException { + + int start = document.getLineOffset(line); + int brackcount = getBracketCount(document, start, end, false) + - closingBracketIncrease; + + // sum up the brackets counts of each line (closing brackets count + // negative, + // opening positive) until we find a line the brings the count to zero + while (brackcount < 0) { + line--; + if (line < 0) { + return -1; + } + start = document.getLineOffset(line); + end = start + document.getLineLength(line) - 1; + brackcount += getBracketCount(document, start, end, false); + } + return line; + } + + /** + * Returns the bracket value of a section of text. Closing brackets have a + * value of -1 and open brackets have a value of 1. + * + * @returns the line number of the next matching bracket after end + * @param document - + * the document being parsed + * @param start - + * the start position for the search + * @param end - + * the end position for the search + * @param ignoreCloseBrackets - + * whether or not to ignore closing brackets in the count + */ + private int getBracketCount(IDocument document, int start, int end, + boolean ignoreCloseBrackets) throws BadLocationException { + + int begin = start; + int bracketcount = 0; + while (begin < end) { + char curr = document.getChar(begin); + begin++; + switch (curr) { + case '/': + if (begin < end) { + char next = document.getChar(begin); + if (next == '*') { + // a comment starts, advance to the comment end + begin = getCommentEnd(document, begin + 1, end); + } else if (next == '/') { + // '//'-comment: nothing to do anymore on this line + begin = end; + } + } + break; + case '*': + if (begin < end) { + char next = document.getChar(begin); + if (next == '/') { + // we have been in a comment: forget what we read before + bracketcount = 0; + begin++; + } + } + break; + case '{': + bracketcount++; + ignoreCloseBrackets = false; + break; + case '}': + if (!ignoreCloseBrackets) { + bracketcount--; + } + break; + case '"': + case '\'': + begin = getStringEnd(document, begin, end, curr); + break; + default: + } + } + return bracketcount; + } + + /** + * Returns the end position a comment starting at pos. + * + * @returns the end position a comment starting at pos + * @param document - + * the document being parsed + * @param position - + * the start position for the search + * @param end - + * the end position for the search + */ + private int getCommentEnd(IDocument document, int position, int end) + throws BadLocationException { + int currentPosition = position; + while (currentPosition < end) { + char curr = document.getChar(currentPosition); + currentPosition++; + if (curr == '*') { + if (currentPosition < end + && document.getChar(currentPosition) == '/') { + return currentPosition + 1; + } + } + } + return end; + } + + /** + * Returns the String at line with the leading whitespace removed. + * + * @returns the String at line with the leading whitespace removed. + * @param document - + * the document being parsed + * @param line - + * the line being searched + */ + protected String getIndentOfLine(IDocument document, int line) + throws BadLocationException { + if (line > -1) { + int start = document.getLineOffset(line); + int end = start + document.getLineLength(line) - 1; + int whiteend = findEndOfWhiteSpace(document, start, end); + return document.get(start, whiteend - start); + } else { + return ""; //$NON-NLS-1$ + } + } + + /** + * Returns the position of the character in the document after position. + * + * @returns the next location of character. + * @param document - + * the document being parsed + * @param position - + * the position to start searching from + * @param end - + * the end of the document + * @param character - + * the character you are trying to match + */ + private int getStringEnd(IDocument document, int position, int end, + char character) throws BadLocationException { + int currentPosition = position; + while (currentPosition < end) { + char currentCharacter = document.getChar(currentPosition); + currentPosition++; + if (currentCharacter == '\\') { + // ignore escaped characters + currentPosition++; + } else if (currentCharacter == character) { + return currentPosition; + } + } + return end; + } + + /** + * Set the indent of a new line based on the command provided in the + * supplied document. + * + * @param document - + * the document being parsed + * @param command - + * the command being performed + */ + protected void smartIndentAfterNewLine(IDocument document, + DocumentCommand command) { + + int docLength = document.getLength(); + if (command.offset == -1 || docLength == 0) + return; + + try { + int p = (command.offset == docLength ? command.offset - 1 + : command.offset); + int line = document.getLineOfOffset(p); + + StringBuffer buf = new StringBuffer(command.text); + if (command.offset < docLength + && document.getChar(command.offset) == '}') { + int indLine = findMatchingOpenBracket(document, line, + command.offset, 0); + if (indLine == -1) { + indLine = line; + } + buf.append(getIndentOfLine(document, indLine)); + } else { + int start = document.getLineOffset(line); + int whiteend = findEndOfWhiteSpace(document, start, + command.offset); + //int offset = -1; + // if (command.offset > 0 && command.offset < docLength && + // document.getChar(command.offset-1) == '{') { + // offset = command.offset; + // } + buf.append(document.get(start, whiteend - start)); + if (getBracketCount(document, start, command.offset, true) > 0) { + buf.append('\t'); + } + // if (offset >= 0) { + // buf.append('}'); + // } + } + command.text = buf.toString(); + + } catch (BadLocationException excp) { + System.out.println(PHPEditorMessages + .getString("AutoIndent.error.bad_location_1")); //$NON-NLS-1$ + } + } + + /** + * Set the indent of a bracket based on the command provided in the supplied + * document. + * + * @param document - + * the document being parsed + * @param command - + * the command being performed + */ + protected void smartInsertAfterBracket(IDocument document, + DocumentCommand command) { + if (command.offset == -1 || document.getLength() == 0) + return; + + try { + int p = (command.offset == document.getLength() ? command.offset - 1 + : command.offset); + int line = document.getLineOfOffset(p); + int start = document.getLineOffset(line); + int whiteend = findEndOfWhiteSpace(document, start, command.offset); + + // shift only when line does not contain any text up to the closing + // bracket + if (whiteend == command.offset) { + // evaluate the line with the opening bracket that matches out + // closing bracket + int indLine = findMatchingOpenBracket(document, line, + command.offset, 1); + if (indLine != -1 && indLine != line) { + // take the indent of the found line + StringBuffer replaceText = new StringBuffer( + getIndentOfLine(document, indLine)); + // add the rest of the current line including the just added + // close bracket + replaceText.append(document.get(whiteend, command.offset + - whiteend)); + replaceText.append(command.text); + // modify document command + command.length = command.offset - start; + command.offset = start; + command.text = replaceText.toString(); + } + } + } catch (BadLocationException excp) { + System.out.println(PHPEditorMessages + .getString("AutoIndent.error.bad_location_2")); //$NON-NLS-1$ + } + } +}