| package org.eclipse.jst.jsp.ui.internal.contentassist; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| import org.eclipse.jdt.core.CompletionProposal; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.ui.text.java.CompletionProposalCollector; |
| import org.eclipse.jdt.ui.text.java.CompletionProposalComparator; |
| import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jst.jsp.core.internal.java.JSP2ServletNameUtil; |
| import org.eclipse.jst.jsp.core.internal.java.JSPTranslation; |
| import org.eclipse.swt.graphics.Image; |
| |
| /** |
| * Passed into ICodeComplete#codeComplete(int offset, CompletionRequestor requestor). |
| * Adapts IJavaCompletionProposals to JSPCompletion proposals. |
| * This includes: |
| * - translating offsets |
| * - "fixing" up display strings |
| * - filtering some unwanted proposals |
| * |
| * @plannedfor 1.0 |
| */ |
| public class JSPProposalCollector extends CompletionProposalCollector { |
| |
| private String fJspName; |
| private String fMangledName; |
| private JSPTranslation fTranslation; |
| private Comparator fComparator; |
| |
| public JSPProposalCollector(ICompilationUnit cu, JSPTranslation translation) { |
| super(cu); |
| if(cu != null) { |
| // set some names for fixing up mangled name in proposals |
| // set mangled (servlet) name |
| String cuName = cu.getPath().lastSegment(); |
| setMangledName(cuName.substring(0, cuName.lastIndexOf('.'))); |
| // set name of jsp file |
| String unmangled = JSP2ServletNameUtil.unmangle(cuName); |
| setJspName(unmangled.substring(unmangled.lastIndexOf('/') + 1)); |
| } |
| |
| if(translation == null) |
| throw new IllegalArgumentException("JSPTranslation cannot be null"); //$NON-NLS-1$ |
| |
| fTranslation = translation; |
| } |
| |
| /** |
| * Ensures that we only return JSPCompletionProposals. |
| * @return an array of JSPCompletionProposals |
| */ |
| public JSPCompletionProposal[] getJSPCompletionProposals() { |
| List results = new ArrayList(); |
| IJavaCompletionProposal[] javaProposals = getJavaCompletionProposals(); |
| // need to filter out non JSPCompletionProposals |
| // because their offsets haven't been translated |
| for (int i = 0; i < javaProposals.length; i++) { |
| if(javaProposals[i] instanceof JSPCompletionProposal) |
| results.add(javaProposals[i]); |
| } |
| Collections.sort(results, getComparator()); |
| return (JSPCompletionProposal[])results.toArray(new JSPCompletionProposal[results.size()]); |
| } |
| |
| private Comparator getComparator() { |
| if(fComparator == null) |
| fComparator = new CompletionProposalComparator(); |
| return fComparator; |
| } |
| |
| /** |
| * Overridden to: |
| * - translate Java -> JSP offsets |
| * - fix cursor-position-after |
| * - fix mangled servlet name in display string |
| * - remove unwanted proposals (servlet constructor) |
| */ |
| protected IJavaCompletionProposal createJavaCompletionProposal(CompletionProposal proposal) { |
| |
| JSPCompletionProposal jspProposal = null; |
| |
| // from proposal |
| String completion = String.valueOf(proposal.getCompletion()); |
| String mangledName = getMangledName(); |
| |
| // ignore constructor proposals |
| // (they will include mangled servlet name) |
| if(mangledName != null && completion.indexOf(mangledName) == -1) { |
| |
| // java offset |
| int offset = proposal.getReplaceStart(); |
| // replacement length |
| int length = proposal.getReplaceEnd() - offset; |
| // translate offset from Java > JSP |
| offset = fTranslation.getJspOffset(offset); |
| // cursor position after must be calculated |
| int positionAfter = calculatePositionAfter(proposal, completion, offset); |
| |
| // from java proposal |
| IJavaCompletionProposal javaProposal = super.createJavaCompletionProposal(proposal); |
| Image image = javaProposal.getImage(); |
| String displayString = javaProposal.getDisplayString(); |
| displayString = fixupDisplayString(displayString); |
| IContextInformation contextInformation = javaProposal.getContextInformation(); |
| String additionalInfo = javaProposal.getAdditionalProposalInfo(); |
| int relevance = javaProposal.getRelevance(); |
| |
| boolean updateLengthOnValidate = true; |
| |
| jspProposal = new JSPCompletionProposal(completion, offset, length, positionAfter, image, displayString, contextInformation, additionalInfo, relevance, updateLengthOnValidate); |
| } |
| return jspProposal; |
| } |
| |
| /** |
| * Cacluates the where the cursor should be after applying this proposal. |
| * eg. method(|) if the method proposal chosen had params. |
| * |
| * @param proposal |
| * @param completion |
| * @param currentCursorOffset |
| * @return |
| */ |
| private int calculatePositionAfter(CompletionProposal proposal, String completion, int currentCursorOffset) { |
| // calculate cursor position after |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=118398 |
| //int positionAfter = currentCursorOffset+completion.length(); |
| int positionAfter = completion.length(); |
| |
| int kind = proposal.getKind(); |
| |
| // may need better logic here... |
| // put cursor inside parenthesis if there's params |
| // only checking for any kind of declaration |
| if(kind == CompletionProposal.ANONYMOUS_CLASS_DECLARATION || kind == CompletionProposal.METHOD_DECLARATION || kind == CompletionProposal.POTENTIAL_METHOD_DECLARATION || kind == CompletionProposal.METHOD_REF) { |
| String[] params = Signature.getParameterTypes(String.valueOf(proposal.getSignature())); |
| if(completion.length() > 0 && params.length > 0) |
| positionAfter--; |
| } |
| return positionAfter; |
| } |
| |
| /** |
| * Replaces mangled (servlet) name with jsp file name. |
| * |
| * @param displayString |
| * @return |
| */ |
| private String fixupDisplayString(String displayString) { |
| StringBuffer fixedName = new StringBuffer(displayString); |
| String mangledName = getMangledName(); |
| if(mangledName != null) { |
| int index = displayString.indexOf(mangledName); |
| if(index != -1) { |
| fixedName = new StringBuffer(); |
| fixedName.append(displayString.substring(0, index)); |
| fixedName.append(getJspName()); |
| fixedName.append(displayString.substring(index + mangledName.length())); |
| } |
| } |
| return fixedName.toString(); |
| } |
| |
| private String getMangledName() { |
| return fMangledName; |
| } |
| |
| private void setMangledName(String mangledName) { |
| fMangledName = mangledName; |
| } |
| |
| private String getJspName() { |
| return fJspName; |
| } |
| |
| private void setJspName(String jspName) { |
| fJspName = jspName; |
| } |
| |
| static char[] getTypeTriggers() { |
| return TYPE_TRIGGERS; |
| } |
| |
| public JSPTranslation getTranslation() { |
| return fTranslation; |
| } |
| |
| } |