/*******************************************************************************
* Copyright (c) 2007-2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.el.ui.ca;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jface.internal.text.html.BrowserInformationControl;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.StructuredModelManager;
import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceCompletionProposal;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor;
import org.eclipse.wst.xml.ui.internal.util.SharedXMLEditorPluginImageHelper;
import org.jboss.tools.common.el.core.ELReference;
import org.jboss.tools.common.el.core.ca.AbstractELCompletionEngine;
import org.jboss.tools.common.el.core.ca.ELTextProposal;
import org.jboss.tools.common.el.core.ca.MessagesELTextProposal;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.resolver.ELContext;
import org.jboss.tools.common.el.core.resolver.ELResolver;
import org.jboss.tools.common.el.core.resolver.ELResolverFactoryManager;
import org.jboss.tools.common.el.ui.ElUiPlugin;
import org.jboss.tools.common.el.ui.internal.info.ELInfoHover;
import org.jboss.tools.common.el.ui.internal.info.Messages;
import org.jboss.tools.common.text.TextProposal;
import org.jboss.tools.common.text.ext.util.Utils;
import org.jboss.tools.common.ui.CommonUIPlugin;
import org.jboss.tools.common.util.EclipseUIUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
/**
* Content assist proposal processor.
* Computes Seam EL proposals.
*
* @author Victor Rubezhny
*/
@SuppressWarnings("restriction")
public abstract class ELProposalProcessor extends AbstractContentAssistProcessor {
private static final ICompletionProposal[] NO_PROPOSALS= new ICompletionProposal[0];
private static final IContextInformation[] NO_CONTEXTS= new IContextInformation[0];
/*
* Sorts IJavaElements by IJavaElement.getElementName() case insensitive order
*/
public static final Comparator<IJavaElement> CASE_INSENSITIVE_ORDER = new Comparator<IJavaElement>() {
public int compare(IJavaElement o1, IJavaElement o2) {
return String.CASE_INSENSITIVE_ORDER.compare(o1.getElementName() , o2.getElementName());
}
};
public static final class Proposal implements ICompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2, ICompletionProposalExtension3, ICompletionProposalExtension4, ICompletionProposalExtension5, IRelevanceCompletionProposal {
private final String fString;
private final String fPrefix;
private final String fNewPrefix;
private final int fOffset;
private int fNewPosition;
private String fDisplayString;
private String fAlternateMatch;
private Object fAdditionalProposalInfo;
private IJavaElement[] fJavaElements;
private MessagesELTextProposal fPropertySource;
/**
* The control creator.
*/
private IInformationControlCreator fCreator;
private Image fImage;
public Proposal(String string, String prefix, int offset) {
this(string, prefix, offset, offset + string.length());
}
public Proposal(String string, String prefix, int offset, int newPosition) {
this(string, prefix, prefix, offset, offset + string.length(), null, null, null, null, null, null);
}
/**/ public Proposal(String string, String prefix, int offset, int newPosition, Image image, String displayString, String alternateMatch, String additionalProposalInfo, IJavaElement[] javaElements, MessagesELTextProposal propertySource) {
this(string, prefix, prefix, offset, offset + string.length(), image, displayString, alternateMatch, additionalProposalInfo, javaElements, propertySource);
}
public Proposal(String string, String prefix, String newPrefix, int offset, int newPosition) {
this(string, prefix, newPrefix, offset, newPosition, null, null, null, null, null, null);
}
/**/ public Proposal(String string, String prefix, String newPrefix, int offset, int newPosition, Image image, String displayString, String alternateMatch, String additionalProposalInfo, IJavaElement[] javaElements, MessagesELTextProposal propertySource) {
fString = string;
fPrefix = prefix;
fNewPrefix = newPrefix;
fOffset = offset;
fNewPosition = newPosition;
fImage = image;
fDisplayString = displayString;
fAlternateMatch = alternateMatch;
fAdditionalProposalInfo = additionalProposalInfo;
fJavaElements = javaElements;
if (fJavaElements != null && fJavaElements.length > 0)
fAdditionalProposalInfo = null; // Drop it due to valculate it later based on java elements
fPropertySource = propertySource;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(IDocument)
*/
public void apply(IDocument document) {
apply(null, '\0', 0, fOffset);
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(IDocument)
*/
public Point getSelection(IDocument document) {
return new Point(getCursorPosition(), 0);
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
*/
public String getAdditionalProposalInfo() {
Object info= getAdditionalProposalInfo(new NullProgressMonitor());
return info == null ? null : info.toString();
}
private static final String EMPTY_ADDITIONAL_INFO = new String();
@Override
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
if (fAdditionalProposalInfo == null) {
if (this.fJavaElements != null && this.fJavaElements.length > 0) {
fAdditionalProposalInfo = ELInfoHover.getHoverInfo(fJavaElements, monitor);
} else if (fPropertySource != null) {
fAdditionalProposalInfo = ELInfoHover.getHoverInfo(
fPropertySource.getBaseName(), fPropertySource.getPropertyName(),
fPropertySource.getAllObjects(), monitor);
}
}
if (fAdditionalProposalInfo == null)
fAdditionalProposalInfo = EMPTY_ADDITIONAL_INFO;
return fAdditionalProposalInfo;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
*/
public String getDisplayString() {
if (fDisplayString != null)
return fDisplayString;
String dispString = (fNewPrefix == null ? fPrefix : fNewPrefix) + fString;
if (dispString != null) {
if (dispString.indexOf('{') == -1
&& dispString.indexOf('}') != -1) {
dispString = dispString.substring(0, dispString.indexOf('}'));
}
if (dispString.indexOf('{') != -1
&& dispString.indexOf('}') == -1) {
dispString += "}"; //$NON-NLS-1$
}
}
return dispString;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage()
*/
public Image getImage() {
return fImage == null ?
SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_ATTRIBUTE) :
fImage;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation()
*/
public IContextInformation getContextInformation() {
return null;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#apply(IDocument, char, int)
*/
public void apply(IDocument document, char trigger, int offset) {
try {
int docCharsToReplace = (fNewPrefix == null || fPrefix == null) ? 0 :
fPrefix.length() - fNewPrefix.length();
String replacement= fString.substring(offset - fOffset);
document.replace(offset - docCharsToReplace, docCharsToReplace, replacement);
} catch (BadLocationException x) {
ElUiPlugin.getDefault().logError(x);
}
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#isValidFor(IDocument, int)
*/
public boolean isValidFor(IDocument document, int offset) {
return validate(document, offset, null);
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#getTriggerCharacters()
*/
public char[] getTriggerCharacters() {
return null;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#getContextInformationPosition()
*/
public int getContextInformationPosition() {
return 0;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(ITextViewer, char, int, int)
*/
public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
apply(viewer.getDocument(), trigger, offset);
if (fString != null && fString.endsWith("}")) { //$NON-NLS-1$
fNewPosition -= 1;
}
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(ITextViewer, boolean)
*/
public void selected(ITextViewer viewer, boolean smartToggle) {
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(ITextViewer)
*/
public void unselected(ITextViewer viewer) {
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(IDocument document, int offset, DocumentEvent event)
*/
public boolean validate(IDocument document, int offset, DocumentEvent event) {
try {
int prefixStart= fOffset - fPrefix.length();
return offset >= fOffset &&
((offset < fOffset + fString.length() && document.get(prefixStart, offset - (prefixStart)).equals((fPrefix + fString).substring(0, offset - prefixStart))) ||
(fAlternateMatch != null && offset < fOffset + fAlternateMatch.length() && document.get(prefixStart, offset - (prefixStart)).equals((fPrefix + fAlternateMatch).substring(0, offset - prefixStart))));
} catch (BadLocationException x) {
return false;
}
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getInformationControlCreator()
*/
public IInformationControlCreator getInformationControlCreator() {
final boolean[] browserInformationControlAvailable = new boolean[] {false};
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
Shell shell= JavaPlugin.getActiveWorkbenchShell();
browserInformationControlAvailable[0] = (shell != null && BrowserInformationControl.isAvailable(shell));
}
});
if (!browserInformationControlAvailable[0])
return null;
if (fCreator == null) {
ELInfoHover.PresenterControlCreator presenterControlCreator= new ELInfoHover.PresenterControlCreator(ELInfoHover.getSite());
fCreator= new ELInfoHover.HoverControlCreator(presenterControlCreator, Messages.additionalInfo_affordance);
}
return fCreator;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getPrefixCompletionText(IDocument, int)
*/
public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
return fPrefix + fString;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getPrefixCompletionStart(IDocument, int)
*/
public int getPrefixCompletionStart(IDocument document, int completionOffset) {
return fOffset - fPrefix.length();
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension4#isAutoInsertable()
*/
public boolean isAutoInsertable() {
return false;
}
/**
* Return cursor position of proposal replacement string.
*/
public int getCursorPosition() {
int cursorPosition = -1;
int openingQuoteInReplacement = fString.lastIndexOf('(');
int closingQuoteInReplacement = fString.lastIndexOf(')');
int openingQuoteInDisplay = fDisplayString.lastIndexOf('(');
int closingQuoteInDisplay = fDisplayString.lastIndexOf(')');
if (openingQuoteInReplacement != -1
&& closingQuoteInReplacement != -1
&& openingQuoteInDisplay != -1
&& closingQuoteInDisplay != -1
&& (closingQuoteInReplacement - openingQuoteInReplacement) != (closingQuoteInDisplay - openingQuoteInDisplay)) {
cursorPosition = openingQuoteInReplacement + 1;
}
return cursorPosition > -1 ? fOffset + cursorPosition : fNewPosition;
}
/**
* Returns the relevance of the proposal
*/
public int getRelevance() {
return TextProposal.R_JSP_JSF_EL_VARIABLE_ATTRIBUTE_VALUE+10;
}
public String getfAlternateMatch() {
return fAlternateMatch;
}
public void setfAlternateMatch(String fAlternateMatch) {
this.fAlternateMatch = fAlternateMatch;
}
}
/**
* Creates a new Seam EL completion proposal computer.
*/
public ELProposalProcessor() {
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
*/
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
IDocument document = viewer.getDocument();
int start = 0;
int end = document.getLength();
int[] region = getRegion(document, offset);
if(region != null) {
start = region[0];
end = region[1];
}
return computeCompletionProposals(viewer, offset, start, end);
}
private int[] getRegion(IDocument document, int offset) {
IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForRead(document);
try {
Document xmlDocument = (model instanceof IDOMModel) ? ((IDOMModel) model)
.getDocument()
: null;
if (xmlDocument == null)
return null;
Node n = Utils.findNodeForOffset(xmlDocument, offset);
if (n == null || !(n instanceof Attr || n instanceof Text))
return null;
int start = 0;
int end = document.getLength();
if (n instanceof IDOMNode) {
start = ((IDOMNode) n).getStartOffset();
end = ((IDOMNode) n).getEndOffset();
}
return new int[]{start, end};
} finally {
if(model != null) {
model.releaseFromRead();
model = null;
}
}
}
abstract protected boolean isEnabled(IFile file);
abstract protected Image getImage();
abstract protected ELContext getELContext(IFile file);
/**
*
* @param start start of relevant region in document
* @param end end of relevant region in document
*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
*/
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset, int start, int end) {
ITextEditor part = EclipseUIUtil.getActiveEditor();
if (part == null) {
return NO_PROPOSALS;
}
IEditorInput editorInput = part.getEditorInput();
if (!(editorInput instanceof IFileEditorInput)) {
return NO_PROPOSALS;
}
IFile file = ((IFileEditorInput) editorInput).getFile();
if (!isEnabled(file)) {
return NO_PROPOSALS;
}
ELContext context = getELContext(file);
if (context == null) {
return NO_PROPOSALS;
}
ELReference ref = context.getELReference(offset);
if(ref==null) {
return NO_PROPOSALS;
}
ELResolver[] resolvers = ELResolverFactoryManager.getInstance().getResolvers(file);
List<ICompletionProposal> resultList = new ArrayList<ICompletionProposal>();
String prefix= getPrefix(viewer, offset, start, end);
prefix = (prefix == null ? "" : prefix); //$NON-NLS-1$
String proposalPrefix = ""; //$NON-NLS-1$
String proposalSufix = ""; //$NON-NLS-1$
String elStartChar = "#"; //$NON-NLS-1$
String documentContent = ref.getELModel().getSource();
// Is '#{', or '${', or '}'-bracket exists? If not - add the
int elEndPosition = documentContent.indexOf("#{", offset - ref.getStartPosition()); //$NON-NLS-1$
int limit = documentContent.indexOf("${", offset - ref.getStartPosition()); //$NON-NLS-1$
if (limit != -1 && elEndPosition != -1 && limit < elEndPosition) {
elEndPosition = limit;
}
limit = documentContent.indexOf('}', offset - ref.getStartPosition());
if (limit != -1 && (elEndPosition == -1 || (elEndPosition != -1 && limit < elEndPosition))) {
elEndPosition = limit+1;
}
String restOfEL = elEndPosition == -1 ? "" : documentContent.substring(offset - ref.getStartPosition(), elEndPosition); //$NON-NLS-1$
if(restOfEL.indexOf('}') == -1) {
proposalSufix = "}"; //$NON-NLS-1$
}
for (int i = 0; i < resolvers.length; i++) {
List<TextProposal> suggestions = resolvers[i].getProposals(context,
offset);
List<TextProposal> uniqueSuggestions = AbstractELCompletionEngine
.makeProposalsUnique(suggestions);
for (TextProposal kbProposal : uniqueSuggestions) {
String string = kbProposal.getReplacementString();
Image image = kbProposal.hasImage() ? CommonUIPlugin.getImageDescriptorRegistry().get(kbProposal.getImageDescriptor()):getImage();
if (string.length() >= 0) {
string = proposalPrefix + string;
if (string.length() > 0 && ('#' == string.charAt(0) || '$' == string.charAt(0)))
string = elStartChar + string.substring(1);
String additionalProposalInfo = kbProposal.getContextInfo();
IJavaElement[] javaElements = null;
MessagesELTextProposal source = null;
if (kbProposal instanceof ELTextProposal) {
javaElements = ((ELTextProposal)kbProposal).getAllJavaElements();
} else if (kbProposal instanceof MessagesELTextProposal) {
source = (MessagesELTextProposal)kbProposal;
}
if (string.startsWith("[") && prefix != null && prefix.indexOf('.') != -1) { //$NON-NLS-1$
String newPrefix = prefix.substring(0, prefix.lastIndexOf('.'));
if (string.indexOf('\'') != -1 && restOfEL.indexOf('\'') != -1) // Exclude last quote if this char already exists
string = string.substring(0, string.lastIndexOf('\''));
if (string.indexOf(']') == -1 && restOfEL.indexOf(']') == -1) // Add closing square bracket if needed
string += ']';
string += proposalSufix;
resultList.add(new Proposal(string, prefix, newPrefix, offset, offset - (prefix.length() - newPrefix.length()) + string.length() - proposalSufix.length(), image,
kbProposal.getLabel(), kbProposal.getAlternateMatch(), additionalProposalInfo, javaElements, source));
} else {
if (string.indexOf('\'') != -1 && restOfEL.indexOf('\'') != -1) // Exclude last quote if this char already exists
string = string.substring(0, string.lastIndexOf('\''));
if ((string.indexOf('[') != -1 || (prefix.indexOf('[') != -1 && prefix.indexOf(']', prefix.lastIndexOf('[')) == -1))
&& string.indexOf(']') == -1 && restOfEL.indexOf(']') == -1) // Add closing square bracket if needed
string += ']';
string += proposalSufix;
resultList.add(new Proposal(string, prefix, offset, offset + string.length() - proposalSufix.length(), image,
kbProposal.getLabel(), kbProposal.getAlternateMatch(), additionalProposalInfo, javaElements, source));
}
}
}
}
if (resultList.isEmpty()) {
return NO_PROPOSALS;
}
ICompletionProposal[] resultArray = new ICompletionProposal[resultList
.size()];
resultArray = resultList.toArray(resultArray);
Arrays.sort(resultArray, new Comparator<ICompletionProposal>() {
public int compare(ICompletionProposal arg0,
ICompletionProposal arg1) {
return arg0.getDisplayString().compareTo(arg1.getDisplayString());
}
});
return resultArray;
}
/*
* @return non-paired quote char if exists, otherwise 0
*/
private char getPreceedingQuoteChar(int initialOffset, String restOfCurrentValue) {
int offset = initialOffset;
char inQuotesChar = 0;
while (--offset >= 0) {
if ('"' == restOfCurrentValue.charAt(offset) ||
'\'' == restOfCurrentValue.charAt(offset) &&
(inQuotesChar == 0 || inQuotesChar == restOfCurrentValue.charAt(offset))) {
if (initialOffset + offset > 0 && restOfCurrentValue.charAt(offset - 1) == '\\') {
int backslashCount = 1;
while ((offset - backslashCount) >= 0 &&
restOfCurrentValue.charAt(offset - backslashCount) == '\\') {
backslashCount++;
}
if (backslashCount % 2 == 1) {
inQuotesChar = inQuotesChar == 0 ? restOfCurrentValue.charAt(offset) : 0;
offset -= backslashCount;
}
} else {
inQuotesChar = inQuotesChar == 0 ? restOfCurrentValue.charAt(offset) : 0;
}
} else if ('{' == restOfCurrentValue.charAt(offset)) {
if (offset > 0 &&
('#' == restOfCurrentValue.charAt(offset -1) ||
'$' == restOfCurrentValue.charAt(offset -1))) {
return inQuotesChar;
}
}
}
return inQuotesChar;
}
/*
* Checks if the EL operand ending character is present
* @return
*/
private int getELEndPosition(int initialOffset, String restOfCurrentValue) {
int offset = -1;
char inQuotesChar = getPreceedingQuoteChar(initialOffset, restOfCurrentValue);
while (++offset < restOfCurrentValue.length() - initialOffset) {
if (inQuotesChar == 0) {
if ('}' == restOfCurrentValue.charAt(initialOffset + offset))
return offset;
if ('#' == restOfCurrentValue.charAt(initialOffset + offset))
return -1;
if ('<' == restOfCurrentValue.charAt(initialOffset + offset))
return -1;
if ('>' == restOfCurrentValue.charAt(initialOffset + offset))
return -1;
if ('/' == restOfCurrentValue.charAt(initialOffset + offset) &&
(initialOffset + offset + 1 < restOfCurrentValue.length() &&
'>' == restOfCurrentValue.charAt(initialOffset + offset + 1)))
return -1;
if ('"' == restOfCurrentValue.charAt(initialOffset + offset) ||
'\'' == restOfCurrentValue.charAt(initialOffset + offset)) {
inQuotesChar = restOfCurrentValue.charAt(initialOffset + offset);
}
if ('\\' == restOfCurrentValue.charAt(initialOffset + offset)) {
int backslashCount = 1;
while ((initialOffset + offset + backslashCount) < restOfCurrentValue.length() &&
restOfCurrentValue.charAt(initialOffset + offset + backslashCount) == '\\') {
backslashCount++;
}
if (initialOffset + offset + backslashCount >= restOfCurrentValue.length())
return -1;
if (backslashCount % 2 == 1 &&
('"' == restOfCurrentValue.charAt(initialOffset + offset + backslashCount) ||
'\'' == restOfCurrentValue.charAt(initialOffset + offset + backslashCount))) {
inQuotesChar = restOfCurrentValue.charAt(initialOffset + offset + backslashCount);
offset += backslashCount;
}
}
} else {
if ('"' == restOfCurrentValue.charAt(initialOffset + offset) ||
'\'' == restOfCurrentValue.charAt(initialOffset + offset)) {
inQuotesChar = 0;
}
if ('\\' == restOfCurrentValue.charAt(initialOffset + offset)) {
int backslashCount = 1;
while ((initialOffset + offset + backslashCount) < restOfCurrentValue.length() &&
restOfCurrentValue.charAt(initialOffset + offset + backslashCount) == '\\') {
backslashCount++;
}
if (initialOffset + offset + backslashCount >= restOfCurrentValue.length())
return -1;
if (backslashCount % 2 == 1 &&
('"' == restOfCurrentValue.charAt(initialOffset + offset + backslashCount) ||
'\'' == restOfCurrentValue.charAt(initialOffset + offset + backslashCount))) {
inQuotesChar = 0;
offset += backslashCount;
}
}
}
}
return -1;
}
/**
* Calculates the EX expression operand string
*
* @param viewer
* @param offset
* @param start start of relevant region in document
* @param end end of relevant region in document
* @return
* @throws BadLocationException
*/
public String getPrefix(ITextViewer viewer, int offset, int start, int end) throws StringIndexOutOfBoundsException {
IDocument doc= viewer.getDocument();
if (doc == null || offset > doc.getLength())
return null;
return getPrefix(doc, offset, start, end);
}
/**
* Calculates the EX expression operand string
*
* @param viewer
* @param offset
* @param start start of relevant region in document
* @param end end of relevant region in document
* @return
* @throws StringIndexOutOfBoundsException
*/
public String getPrefix(IDocument document, int offset, int start, int end) throws StringIndexOutOfBoundsException {
if (document == null || document.get() == null || offset > document.get().length())
return null;
ELInvocationExpression expr = AbstractELCompletionEngine.findExpressionAtOffset(document, offset, start, end);
if (expr == null)
return null;
return document.get().substring(expr.getStartPosition(), offset);
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
*/
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
// no context informations for Seam EL completions
return NO_CONTEXTS;
}
private char[] autoActivChars;
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
*/
public char[] getCompletionProposalAutoActivationCharacters() {
if(autoActivChars==null) {
IPreferenceStore store= EditorsUI.getPreferenceStore();
String superDefaultChars = store.getDefaultString(PreferenceConstants.CODEASSIST_AUTOACTIVATION_TRIGGERS_JAVA);
StringBuffer redhatDefaultChars = new StringBuffer(superDefaultChars);
if(superDefaultChars.indexOf("{")<0) { //$NON-NLS-1$
redhatDefaultChars.append('{');
}
if(superDefaultChars.indexOf(".")<0) { //$NON-NLS-1$
redhatDefaultChars.append('.');
}
if(superDefaultChars.indexOf("[")<0) { //$NON-NLS-1$
redhatDefaultChars.append('[');
}
autoActivChars = new char[redhatDefaultChars.length()];
redhatDefaultChars.getChars(0, redhatDefaultChars.length(), autoActivChars, 0);
store.setDefault(PreferenceConstants.CODEASSIST_AUTOACTIVATION_TRIGGERS_JAVA, redhatDefaultChars.toString());
store.setValue(PreferenceConstants.CODEASSIST_AUTOACTIVATION_TRIGGERS_JAVA, redhatDefaultChars.toString());
}
return autoActivChars;
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
*/
public char[] getContextInformationAutoActivationCharacters() {
return null;
}
/*
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
*/
public IContextInformationValidator getContextInformationValidator() {
return null;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalComputer#getErrorMessage()
*/
public String getErrorMessage() {
return null; // no custom error message
}
}