package org.erlide.ui.editors.erl.completion;
import java.util.List;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.link.ILinkedModeListener;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedModeUI;
import org.eclipse.jface.text.link.LinkedPosition;
import org.eclipse.jface.text.link.LinkedPositionGroup;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
import org.erlide.engine.services.codeassist.Location;
import org.erlide.util.ErlLogger;
public class ErlCompletionProposal implements ICompletionProposal {
protected static final class ExitPolicy implements LinkedModeUI.IExitPolicy {
final char fExitCharacter;
public ExitPolicy(final char exitCharacter, final IDocument document) {
fExitCharacter = exitCharacter;
}
/*
* @see
* org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy
* #doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager,
* org.eclipse.swt.events.VerifyEvent, int, int)
*/
@Override
public LinkedModeUI.ExitFlags doExit(final LinkedModeModel environment,
final VerifyEvent event, final int offset, final int length) {
if (event.character == fExitCharacter) {
if (environment.anyPositionContains(offset)) {
return new LinkedModeUI.ExitFlags(ILinkedModeListener.UPDATE_CARET,
false);
}
return new LinkedModeUI.ExitFlags(ILinkedModeListener.UPDATE_CARET, true);
}
switch (event.character) {
case ';':
return new LinkedModeUI.ExitFlags(ILinkedModeListener.NONE, true);
case SWT.CR:
return null;
default:
return null;
}
}
}
/** List of offsets (x) and lengths (y) for linked mode replacements */
private final List<Location> offsetsAndLengths;
/** The string to be displayed in the completion proposal popup. */
private final String displayString;
/** The replacement string. */
private final String replacementString;
/** The replacement offset. */
private final int replacementOffset;
/** The replacement length. */
private final int replacementLength;
/** The cursor position after this proposal has been applied. */
private final int cursorPosition;
/** The image to be displayed in the completion proposal popup. */
private final Image image;
/** The context information of this proposal. */
private final IContextInformation contextInformation;
/** The additional info of this proposal. */
private final String additionalProposalInfo;
/** A sourceViewer (from the erlang editor) */
private final ISourceViewer sourceViewer;
/**
* @param offsetsAndLengths
* @param displayString
* @param replacementString
* @param replacementOffset
* @param replacementLength
* @param cursorPosition
* @param image
* @param contextInformation
* @param additionalProposalInfo
* @param sourceViewer
*/
public ErlCompletionProposal(final List<Location> offsetsAndLengths,
final String displayString, final String replacementString,
final int replacementOffset, final int replacementLength,
final int cursorPosition, final Image image,
final IContextInformation contextInformation,
final String additionalProposalInfo, final ISourceViewer sourceViewer) {
this.offsetsAndLengths = offsetsAndLengths;
this.displayString = displayString;
this.replacementString = replacementString;
this.replacementOffset = replacementOffset;
this.replacementLength = replacementLength;
this.cursorPosition = cursorPosition;
this.image = image;
this.contextInformation = contextInformation;
this.additionalProposalInfo = additionalProposalInfo;
this.sourceViewer = sourceViewer;
}
/*
* @see ICompletionProposal#apply(IDocument)
*/
@Override
public void apply(final IDocument document) {
try {
document.replace(replacementOffset, replacementLength, replacementString);
setUpLinkedMode(document, ')', offsetsAndLengths);
} catch (final BadLocationException x) {
// ignore
}
}
/*
* @see ICompletionProposal#getAdditionalProposalInfo()
*/
@Override
public String getAdditionalProposalInfo() {
return additionalProposalInfo;
}
/*
* @see ICompletionProposal#getContextInformation()
*/
@Override
public IContextInformation getContextInformation() {
return contextInformation;
}
/*
* @see ICompletionProposal#getDisplayString()
*/
@Override
public String getDisplayString() {
if (displayString != null) {
return displayString;
}
return replacementString;
}
/*
* @see ICompletionProposal#getImage()
*/
@Override
public Image getImage() {
return image;
}
/*
* @see ICompletionProposal#getSelection(IDocument)
*/
@Override
public Point getSelection(final IDocument document) {
if (offsetsAndLengths.isEmpty()) {
return new Point(replacementOffset + cursorPosition, 0);
}
final Location location = offsetsAndLengths.get(0);
return new Point(location.getOffset(), location.getLength());
}
/**
* Sets up a simple linked mode at {@link #getCursorPosition()} and an exit
* policy that will exit the mode when <code>closingCharacter</code> is
* typed and an exit position at <code>getCursorPosition() + 1</code>.
*
* @param document
* the document
* @param closingCharacter
* the exit character
* @param offsetsAndLengths
* list of offsets and lengths for linked groups
*/
protected void setUpLinkedMode(final IDocument document, final char closingCharacter,
final List<Location> offsetsAndLengths) {
if (sourceViewer != null && !offsetsAndLengths.isEmpty()) {
try {
final LinkedModeModel model = new LinkedModeModel();
int last = 0, i = 0;
for (final Location offsetAndLength : offsetsAndLengths) {
final LinkedPositionGroup group = new LinkedPositionGroup();
group.addPosition(
new LinkedPosition(document, offsetAndLength.getOffset(),
offsetAndLength.getLength(), ++i));
model.addGroup(group);
final int l = offsetAndLength.getOffset()
+ offsetAndLength.getLength();
if (l > last) {
last = l;
}
}
model.forceInstall();
final LinkedModeUI ui = new EditorLinkedModeUI(model, sourceViewer);
// ui.setSimpleMode(true);
ui.setExitPolicy(new ExitPolicy(closingCharacter, document));
ui.setExitPosition(sourceViewer, last + 1, 0,
LinkedPositionGroup.NO_STOP);
ui.setCyclingMode(LinkedModeUI.CYCLE_ALWAYS);
ui.enter();
} catch (final BadLocationException x) {
ErlLogger.error(x);
}
}
}
}