/*=============================================================================#
# Copyright (c) 2009-2016 Stephan Wahlbrink (WalWare.de) 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.docmlet.tex.internal.ui.editors;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension6;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import de.walware.ecommons.ltk.ui.sourceediting.assist.AssistInvocationContext;
import de.walware.ecommons.ltk.ui.sourceediting.assist.CompletionProposalWithOverwrite;
import de.walware.docmlet.tex.core.model.TexNameAccess;
import de.walware.docmlet.tex.core.source.LtxHeuristicTokenScanner;
import de.walware.docmlet.tex.ui.TexUI;
public class TexLabelCompletionProposal extends CompletionProposalWithOverwrite
implements ICompletionProposalExtension6 {
static final class ApplyData {
private final AssistInvocationContext fContext;
private final SourceViewer fViewer;
private final IDocument fDocument;
private LtxHeuristicTokenScanner fScanner;
ApplyData(final AssistInvocationContext context) {
fContext = context;
fViewer = context.getSourceViewer();
fDocument = fViewer.getDocument();
}
public SourceViewer getViewer() {
return fViewer;
}
public IDocument getDocument() {
return fDocument;
}
public LtxHeuristicTokenScanner getScanner() {
if (fScanner == null) {
fScanner= LtxHeuristicTokenScanner.create(fContext.getEditor().getDocumentContentInfo());
}
return fScanner;
}
}
protected final TexNameAccess fAccess;
protected StyledString fDisplayString;
private final int fRelevance;
/** The cursor position after this proposal has been applied. */
private int fCursorPosition = -1;
private ApplyData fApplyData;
protected TexLabelCompletionProposal(final AssistInvocationContext context, final int startOffset,
final TexNameAccess access, final int relevance) {
super(context, startOffset);
fAccess = access;
fRelevance = relevance;
}
@Override
protected String getPluginId() {
return TexUI.PLUGIN_ID;
}
@Override
public int getRelevance() {
return fRelevance;
}
@Override
public String getSortingString() {
return fAccess.getSegmentName();
}
@Override
public String getDisplayString() {
return getStyledDisplayString().getString();
}
@Override
public Image getImage() {
return null;
// return TexImages.getImageRegistry().get(key);
}
@Override
public StyledString getStyledDisplayString() {
if (fDisplayString == null) {
final StyledString s = new StyledString(fAccess.getDisplayName());
fDisplayString = s;
}
return fDisplayString;
}
protected final ApplyData getApplyData() {
if (fApplyData == null) {
fApplyData = new ApplyData(getInvocationContext());
}
return fApplyData;
}
@Override
protected int computeReplacementLength(final int replacementOffset, final Point selection, final int caretOffset, final boolean overwrite) throws BadLocationException {
int end = Math.max(caretOffset, selection.x + selection.y);
if (overwrite) {
final ApplyData data = getApplyData();
final IDocument document = data.getDocument();
end--;
SEARCH_END: while (++end < document.getLength()) {
final char c = document.getChar(end);
if (c <= 0x20 || c == '\\' || c == '{' || c == '}' || c == '%'
|| Character.isWhitespace(c)) {
break SEARCH_END;
}
continue SEARCH_END;
}
}
return (end - replacementOffset);
}
@Override
public boolean validate(final IDocument document, final int offset, final DocumentEvent event) {
try {
final int start = getReplacementOffset();
final String prefix = document.get(start, offset - start);
return prefix.regionMatches(true, 0, fAccess.getDisplayName(), 0, prefix.length());
}
catch (final BadLocationException e) {
return false;
}
}
@Override
public String getAdditionalProposalInfo() {
return null;
}
@Override
public boolean isAutoInsertable() {
return true;
}
@Override
protected void doApply(final char trigger, final int stateMask, final int caretOffset,
final int replacementOffset, final int replacementLength) throws BadLocationException {
final ApplyData data = getApplyData();
final IDocument document = data.getDocument();
final StringBuilder replacement = new StringBuilder(fAccess.getDisplayName());
final int cursor = replacement.length();
document.replace(replacementOffset, replacementLength, replacement.toString());
setCursorPosition(replacementOffset + cursor);
}
protected void setCursorPosition(final int offset) {
fCursorPosition = offset;
}
@Override
public Point getSelection(final IDocument document) {
if (fCursorPosition >= 0) {
return new Point(fCursorPosition, 0);
}
return null;
}
@Override
public IContextInformation getContextInformation() {
return null;
}
}