/******************************************************************************* * 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 } }