blob: 8819d0186df8387221c5d85068d5fbad27d99ae1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 Oracle. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Oracle. - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.core.internal.jdtutility;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
/**
* This will apply TextEdit's to a doc and do some extra work to cleanup some
* of the nasty Eclipse annotation formatting (e.g. arrays of annotations).
*/
public class AnnotationEditFormatter {
protected IDocument doc;
public AnnotationEditFormatter(IDocument doc) {
this.doc = doc;
}
/**
* Apply the edits to our doc doing extra formatting as needed.
*/
public void apply(TextEdit edits) throws MalformedTreeException,
BadLocationException {
edits.apply(doc, TextEdit.UPDATE_REGIONS);
MultiTextEdit extra = new MultiTextEdit();
TextEdit[] all = edits.getChildren();
for (int i = 0; i < all.length; i++) {
if (all[i] instanceof InsertEdit) {
InsertEdit a = (InsertEdit)all[i];
if (i + 1 < all.length && all[i + 1] instanceof InsertEdit) {
InsertEdit b = (InsertEdit)all[i + 1];
if (" ".equals(b.getText()) && isAnnotation(a)) {
// Annotation being inserted before something on the same line.
// Insert a newline and indent after the annotation.
ReplaceEdit re = new ReplaceEdit(b.getOffset(), 1,
getNewlineAndIdent(b.getOffset()));
extra.addChild(re);
i++;
continue;
}
if (", ".equals(a.getText()) && isAnnotation(b)) {
// Annotation being inserted in an array initializer on the
// same line as the previous array element.
// Insert a newline and indent before the annotation.
ReplaceEdit re = new ReplaceEdit(a.getOffset() + 1, 1,
getNewlineAndIdent(a.getOffset()));
extra.addChild(re);
i++;
continue;
}
}
if (formatArrayInit(a, extra)) {
continue;
}
}
}
extra.apply(doc, 0);
}
/**
* Create a String containing a line delimeter and indenting characters
* matching the indent level of the line containing character offset.
*/
protected String getNewlineAndIdent(int offset) throws BadLocationException {
int line = doc.getLineOfOffset(offset);
offset = doc.getLineOffset(line);
StringBuffer s = new StringBuffer();
s.append(doc.getLineDelimiter(line));
for (;;) {
char c = doc.getChar(offset++);
if (c == ' ' || c == '\t') {
s.append(c);
} else {
break;
}
}
return s.toString();
}
/**
* Is e inserting an annotation?
*/
protected boolean isAnnotation(InsertEdit e) {
String s = e.getText();
return s.length() > 1 && s.charAt(0) == '@';
}
/**
* If a is inserting an annotation containing an array of annotations as
* its value then format them nicely and return true.
*/
protected boolean formatArrayInit(InsertEdit a, MultiTextEdit extra)
throws BadLocationException {
String s = a.getText();
int n = s.length();
if (n < 6 || s.charAt(0) != '@') {
return false;
}
int pos;
for (pos = 1; pos < n && s.charAt(pos++) != '('; ) {/* just move 'pos' */}
if (pos == n) {
return false;
}
for (; pos < n; ) {
char c = s.charAt(pos++);
if (c == '{') {
break;
}
if (c != ' ') {
return false;
}
}
if (pos == n) {
return false;
}
// now look for @ not inside parenthesis and put in
// line delimeter and indent string before each
int offset = a.getOffset();
String indent = null;
int parenCount = 0;
for (; pos < n; pos++) {
char c = s.charAt(pos);
switch (c) {
case '(':
++parenCount;
break;
case ')':
--parenCount;
break;
case '@':
if (parenCount == 0) {
if (indent == null) {
indent = getNewlineAndIdent(offset) + "\t";
}
InsertEdit ie = new InsertEdit(offset + pos, indent);
extra.addChild(ie);
}
}
}
return indent != null;
}
}