| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation 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 API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.examples.javaeditor.java; |
| |
| |
| import org.eclipse.jface.text.*; |
| |
| /** |
| * Auto indent strategy sensitive to brackets. |
| */ |
| public class JavaAutoIndentStrategy extends DefaultAutoIndentStrategy { |
| |
| public JavaAutoIndentStrategy() { |
| } |
| |
| /* (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)) { //$NON-NLS-1$ |
| 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); |
| buf.append(document.get(start, whiteend - start)); |
| if (getBracketCount(document, start, command.offset, true) > 0) { |
| buf.append('\t'); |
| } |
| } |
| command.text= buf.toString(); |
| |
| } catch (BadLocationException excp) { |
| System.out.println(JavaEditorMessages.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(JavaEditorMessages.getString("AutoIndent.error.bad_location_2")); //$NON-NLS-1$ |
| } |
| } |
| } |