blob: 3be2ab6d03c4f2fded5bfcc371c2cd948ffb161b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.correction.proposals;
import org.eclipse.text.edits.CopyTargetEdit;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MoveSourceEdit;
import org.eclipse.text.edits.MoveTargetEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditVisitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jdt.internal.core.manipulation.util.Strings;
/**
* Class to annotate edits made by a quick fix/assist to be shown via the quick fix pop-up preview.
* E.g. the added changes are shown in bold.
*
* @since 3.8
*/
public class EditAnnotator extends TextEditVisitor {
private int fWrittenToPos= 0;
private final StringBuffer fBuf;
private final IDocument fPreviewDocument;
public EditAnnotator(StringBuffer buffer, IDocument previewDoc) {
fBuf= buffer;
fPreviewDocument= previewDoc;
}
public void unchangedUntil(int pos) {
if (pos > fWrittenToPos) {
appendContent(fPreviewDocument, fWrittenToPos, pos, true);
fWrittenToPos= pos;
}
}
@Override
public boolean visit(MoveTargetEdit edit) {
return true; //rangeAdded(edit);
}
@Override
public boolean visit(CopyTargetEdit edit) {
return true; //return rangeAdded(edit);
}
@Override
public boolean visit(InsertEdit edit) {
return rangeAdded(edit);
}
@Override
public boolean visit(ReplaceEdit edit) {
if (edit.getLength() > 0)
return rangeAdded(edit);
return rangeRemoved(edit);
}
@Override
public boolean visit(MoveSourceEdit edit) {
return rangeRemoved(edit);
}
@Override
public boolean visit(DeleteEdit edit) {
return rangeRemoved(edit);
}
protected boolean rangeRemoved(TextEdit edit) {
unchangedUntil(edit.getOffset());
return false;
}
private boolean rangeAdded(TextEdit edit) {
return annotateEdit(edit, "<b>", "</b>"); //$NON-NLS-1$ //$NON-NLS-2$
}
protected boolean annotateEdit(TextEdit edit, String startTag, String endTag) {
unchangedUntil(edit.getOffset());
fBuf.append(startTag);
appendContent(fPreviewDocument, edit.getOffset(), edit.getExclusiveEnd(), false);
fBuf.append(endTag);
fWrittenToPos= edit.getExclusiveEnd();
return false;
}
private void appendContent(IDocument text, int startOffset, int endOffset, boolean surroundLinesOnly) {
final int surroundLines= 1;
try {
int startLine= text.getLineOfOffset(startOffset);
int endLine= text.getLineOfOffset(endOffset);
boolean dotsAdded= false;
if (surroundLinesOnly && startOffset == 0) { // no surround lines for the top no-change range
startLine= Math.max(endLine - surroundLines, 0);
fBuf.append("...<br>"); //$NON-NLS-1$
dotsAdded= true;
}
for (int i= startLine; i <= endLine; i++) {
if (surroundLinesOnly) {
if ((i - startLine > surroundLines) && (endLine - i > surroundLines)) {
if (!dotsAdded) {
fBuf.append("...<br>"); //$NON-NLS-1$
dotsAdded= true;
} else if (endOffset == text.getLength()) {
return; // no surround lines for the bottom no-change range
}
continue;
}
}
IRegion lineInfo= text.getLineInformation(i);
int start= lineInfo.getOffset();
int end= start + lineInfo.getLength();
int from= Math.max(start, startOffset);
int to= Math.min(end, endOffset);
String content= text.get(from, to - from);
if (surroundLinesOnly && (from == start) && Strings.containsOnlyWhitespaces(content)) {
continue; // ignore empty lines except when range started in the middle of a line
}
for (int k= 0; k < content.length(); k++) {
char ch= content.charAt(k);
switch (ch) {
case '<':
fBuf.append("&lt;"); //$NON-NLS-1$
break;
case '>':
fBuf.append("&gt;"); //$NON-NLS-1$
break;
default:
fBuf.append(ch);
break;
}
}
if (to == end && to != endOffset) { // new line when at the end of the line, and not end of range
fBuf.append("<br>"); //$NON-NLS-1$
}
}
} catch (BadLocationException e) {
// ignore
}
}
}