| /******************************************************************************* |
| * 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("<"); //$NON-NLS-1$ |
| break; |
| case '>': |
| fBuf.append(">"); //$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 |
| } |
| } |
| } |