blob: ab1823ba4716b98607faf58c6db65b98594217cf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.fix;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditGroup;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.ltk.core.refactoring.CategorizedTextEditGroup;
import org.eclipse.ltk.core.refactoring.GroupCategory;
import org.eclipse.ltk.core.refactoring.GroupCategorySet;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.util.TextEditUtil;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.IndentAction;
import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
public class CodeFormatFix implements ICleanUpFix {
public static ICleanUpFix createCleanUp(ICompilationUnit cu, IRegion[] regions, boolean format, boolean removeTrailingWhitespacesAll, boolean removeTrailingWhitespacesIgnorEmpty, boolean correctIndentation) throws CoreException {
if (!format && !removeTrailingWhitespacesAll && !removeTrailingWhitespacesIgnorEmpty && !correctIndentation)
return null;
ArrayList<CategorizedTextEditGroup> groups= new ArrayList<CategorizedTextEditGroup>();
MultiTextEdit formatEdit= new MultiTextEdit();
if (format) {
Map<String, String> formatterSettings= new HashMap<String, String>(cu.getJavaProject().getOptions(true));
String content= cu.getBuffer().getContents();
Document document= new Document(content);
String lineDelemiter= TextUtilities.getDefaultLineDelimiter(document);
TextEdit edit;
if (regions == null) {
edit= CodeFormatterUtil.reformat(CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, content, 0, lineDelemiter, formatterSettings);
} else {
if (regions.length == 0)
return null;
edit= CodeFormatterUtil.reformat(CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, content, regions, 0, lineDelemiter, formatterSettings);
}
if (edit != null && (!(edit instanceof MultiTextEdit) || edit.hasChildren())) {
formatEdit.addChild(edit);
if (!TextEditUtil.isPacked(formatEdit)) {
formatEdit= TextEditUtil.flatten(formatEdit);
}
String label= MultiFixMessages.CodeFormatFix_description;
CategorizedTextEditGroup group= new CategorizedTextEditGroup(label, new GroupCategorySet(new GroupCategory(label, label, label)));
group.addTextEdit(edit);
groups.add(group);
}
}
MultiTextEdit otherEdit= new MultiTextEdit();
if ((removeTrailingWhitespacesAll || removeTrailingWhitespacesIgnorEmpty || correctIndentation) && (!format || regions != null)) {
try {
if (correctIndentation && removeTrailingWhitespacesAll) {
removeTrailingWhitespacesAll= false;
removeTrailingWhitespacesIgnorEmpty= true;
}
Document document= new Document(cu.getBuffer().getContents());
if (removeTrailingWhitespacesAll || removeTrailingWhitespacesIgnorEmpty) {
String label= MultiFixMessages.CodeFormatFix_RemoveTrailingWhitespace_changeDescription;
CategorizedTextEditGroup group= new CategorizedTextEditGroup(label, new GroupCategorySet(new GroupCategory(label, label, label)));
int lineCount= document.getNumberOfLines();
for (int i= 0; i < lineCount; i++) {
IRegion region= document.getLineInformation(i);
if (region.getLength() == 0)
continue;
int lineStart= region.getOffset();
int lineExclusiveEnd= lineStart + region.getLength();
int j= getIndexOfRightMostNoneWhitspaceCharacter(lineStart, lineExclusiveEnd - 1, document);
if (removeTrailingWhitespacesAll) {
j++;
if (j < lineExclusiveEnd) {
DeleteEdit edit= new DeleteEdit(j, lineExclusiveEnd - j);
if (!TextEditUtil.overlaps(formatEdit, edit)) {
otherEdit.addChild(edit);
group.addTextEdit(edit);
}
}
} else if (removeTrailingWhitespacesIgnorEmpty) {
if (j >= lineStart) {
if (document.getChar(j) == '*' && getIndexOfRightMostNoneWhitspaceCharacter(lineStart, j - 1, document) < lineStart) {
j++;
}
j++;
if (j < lineExclusiveEnd) {
DeleteEdit edit= new DeleteEdit(j, lineExclusiveEnd - j);
if (!TextEditUtil.overlaps(formatEdit, edit)) {
otherEdit.addChild(edit);
group.addTextEdit(edit);
}
}
}
}
}
if (otherEdit.hasChildren()) {
groups.add(group);
}
}
if (correctIndentation) {
JavaPlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING);
TextEdit edit= IndentAction.indent(document, cu.getJavaProject());
if (edit != null) {
String label= MultiFixMessages.CodeFormatFix_correctIndentation_changeGroupLabel;
CategorizedTextEditGroup group= new CategorizedTextEditGroup(label, new GroupCategorySet(new GroupCategory(label, label, label)));
if (edit instanceof MultiTextEdit) {
TextEdit[] children= ((MultiTextEdit)edit).getChildren();
for (int i= 0; i < children.length; i++) {
TextEdit child= children[i];
edit.removeChild(child);
if (!TextEditUtil.overlaps(formatEdit, child)) {
otherEdit.addChild(child);
group.addTextEdit(child);
}
}
} else {
if (!TextEditUtil.overlaps(formatEdit, edit)) {
otherEdit.addChild(edit);
group.addTextEdit(edit);
}
}
groups.add(group);
}
}
} catch (BadLocationException x) {
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), 0, "", x)); //$NON-NLS-1$
}
}
TextEdit resultEdit= TextEditUtil.merge(formatEdit, otherEdit);
if (!resultEdit.hasChildren())
return null;
CompilationUnitChange change= new CompilationUnitChange("", cu); //$NON-NLS-1$
change.setEdit(resultEdit);
for (int i= 0, size= groups.size(); i < size; i++) {
TextEditGroup group= groups.get(i);
change.addTextEditGroup(group);
}
return new CodeFormatFix(change);
}
/**
* Returns the index in document of a none whitespace character between start (inclusive) and
* end (inclusive) such that if more then one such character the index returned is the largest
* possible (closest to end). Returns start - 1 if no such character.
*
* @param start the start
* @param end the end
* @param document the document
* @return the position or start - 1
* @exception BadLocationException if the offset is invalid in this document
*/
private static int getIndexOfRightMostNoneWhitspaceCharacter(int start, int end, IDocument document) throws BadLocationException {
int position= end;
while (position >= start && Character.isWhitespace(document.getChar(position)))
position--;
return position;
}
private final CompilationUnitChange fChange;
public CodeFormatFix(CompilationUnitChange change) {
fChange= change;
}
/**
* {@inheritDoc}
*/
public CompilationUnitChange createChange(IProgressMonitor progressMonitor) throws CoreException {
return fChange;
}
}