/******************************************************************************* * Copyright (c) 2005, 2012 eBay Inc. * 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 * *******************************************************************************/ package org.eclipse.vjet.eclipse.ui.text.completion; import org.eclipse.vjet.eclipse.codeassist.CodeassistUtils; import org.eclipse.vjet.eclipse.codeassist.keywords.CompletionContext; import org.eclipse.vjet.eclipse.internal.ui.text.completion.VjoCompletionProposal; import org.eclipse.vjet.eclipse.internal.ui.text.completion.VjoProposalContextInformation; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.dltk.mod.core.CompletionProposal; import org.eclipse.dltk.mod.core.IModelElement; import org.eclipse.dltk.mod.core.IScriptProject; import org.eclipse.dltk.mod.core.ISourceModule; import org.eclipse.dltk.mod.internal.core.JSSourceMethod; import org.eclipse.dltk.mod.ui.DLTKUIPlugin; import org.eclipse.dltk.mod.ui.PreferenceConstants; import org.eclipse.dltk.mod.ui.text.completion.LazyScriptCompletionProposal; import org.eclipse.dltk.mod.ui.text.completion.MethodProposalInfo; import org.eclipse.dltk.mod.ui.text.completion.ProposalContextInformation; import org.eclipse.dltk.mod.ui.text.completion.ProposalInfo; import org.eclipse.dltk.mod.ui.text.completion.ScriptContentAssistInvocationContext; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4; import org.eclipse.jface.text.contentassist.IContextInformation; 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.swt.graphics.Point; import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; public class VjoScriptMethodCompletionProposal extends LazyScriptCompletionProposal implements ICompletionProposalExtension4 { /** * Triggers for method proposals without parameters. Do not modify. */ protected final static char[] METHOD_TRIGGERS = new char[] { ';', ',', '.', '\t', '[' }; /** * Triggers for method proposals. Do not modify. */ protected final static char[] METHOD_WITH_ARGUMENTS_TRIGGERS = new char[] { '(', '-', ' ' }; /** Triggers for method name proposals (static imports). Do not modify. */ protected final static char[] METHOD_NAME_TRIGGERS = new char[] { ';' }; private IRegion fSelectedRegion; // initialized by apply() private boolean fHasParameters; private boolean fHasParametersComputed = false; private int fContextInformationPosition; private ISourceModule fSourceModule; public VjoScriptMethodCompletionProposal(CompletionProposal proposal, ScriptContentAssistInvocationContext context) { super(proposal, context); } public void apply(IDocument document, char trigger, int offset) { if (trigger == ' ' || trigger == '(') trigger = '\0'; super.apply(document, trigger, offset); if (needsLinkedMode()) { setUpLinkedMode(document, ')'); } if (fProposal.getCompletion().length == 0) { return; } int baseOffset = getReplacementOffset() + getCursorPosition(); int exit = getReplacementOffset() + getReplacementString().length(); int[] fArgumentOffsets = null; int[] fArgumentLengths = null; char[][] findParameterNames = fProposal.findParameterNames(null); if (findParameterNames != null && findParameterNames.length > 0) { fArgumentOffsets = new int[findParameterNames.length]; fArgumentLengths = new int[findParameterNames.length]; int argumentOffset = 0; for (int i = 0; i < findParameterNames.length; i++) { fArgumentLengths[i] = findParameterNames[i].length; fArgumentOffsets[i] = argumentOffset; argumentOffset += findParameterNames[i].length + 1; // name and // COMMA } } if (fArgumentOffsets != null && getTextViewer() != null) { try { LinkedModeModel model = new LinkedModeModel(); for (int i = 0; i != fArgumentOffsets.length; i++) { LinkedPositionGroup group = new LinkedPositionGroup(); group.addPosition(new LinkedPosition(document, baseOffset + fArgumentOffsets[i], fArgumentLengths[i], LinkedPositionGroup.NO_STOP)); model.addGroup(group); } model.forceInstall(); LinkedModeUI ui = new EditorLinkedModeUI(model, getTextViewer()); ui.setExitPosition(getTextViewer(), exit, 0, Integer.MAX_VALUE); ui.setExitPolicy(new ExitPolicy(')', document)); ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT); ui.enter(); fSelectedRegion = ui.getSelectedRegion(); } catch (BadLocationException e) { } } else { fSelectedRegion = new Region(exit, 0); } } protected boolean needsLinkedMode() { return false; // we do it our selfs } /** * @see org.eclipse.dltk.mod.ui.text.completion.AbstractScriptCompletionProposal#getSelection(org.eclipse.jface.text.IDocument) */ public Point getSelection(IDocument document) { if (fSelectedRegion == null) return new Point(getReplacementOffset(), 0); return new Point(fSelectedRegion.getOffset(), fSelectedRegion .getLength()); } public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { if (hasArgumentList()) { String completion = String.valueOf(fProposal.getName()); if (isCamelCaseMatching()) { String prefix = getPrefix(document, completionOffset); return getCamelCaseCompound(prefix, completion); } return completion; } return super.getPrefixCompletionText(document, completionOffset); } protected IContextInformation computeContextInformation() { // no context information for METHOD_NAME_REF proposals (e.g. for static // imports) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=94654 if (fProposal.getKind() == CompletionProposal.METHOD_REF && hasParameters() && (getReplacementString().endsWith(RPAREN) || getReplacementString() .length() == 0)) { ProposalContextInformation contextInformation = new VjoProposalContextInformation( fProposal); if (fContextInformationPosition != 0 && fProposal.getCompletion().length == 0) contextInformation .setContextInformationPosition(fContextInformationPosition); return contextInformation; } return super.computeContextInformation(); } protected char[] computeTriggerCharacters() { if (fProposal.getKind() == CompletionProposal.METHOD_NAME_REFERENCE) return METHOD_NAME_TRIGGERS; if (hasParameters()) return METHOD_WITH_ARGUMENTS_TRIGGERS; return METHOD_TRIGGERS; } /** * Returns <code>true</code> if the method being inserted has at least one * parameter. Note that this does not say anything about whether the * argument list should be inserted. This depends on the position in the * document and the kind of proposal; see {@link #hasArgumentList() }. * * @return <code>true</code> if the method has any parameters, * <code>false</code> if it has no parameters */ protected final boolean hasParameters() { if (!fHasParametersComputed) { fHasParametersComputed = true; char[][] findParameterNames = fProposal.findParameterNames(null); fHasParameters = findParameterNames != null && findParameterNames.length > 0; } return fHasParameters; } // private boolean computeHasParameters() throws IllegalArgumentException { // return Signature.getParameterCount(fProposal.getSignature()) > 0; // } /** * Returns <code>true</code> if the argument list should be inserted by * the proposal, <code>false</code> if not. * * @return <code>true</code> when the proposal is not in javadoc nor * within an import and comprises the parameter list */ protected boolean hasArgumentList() { if (CompletionProposal.METHOD_NAME_REFERENCE == fProposal.getKind()) return false; IPreferenceStore preferenceStore = DLTKUIPlugin.getDefault() .getPreferenceStore(); boolean noOverwrite = preferenceStore .getBoolean(PreferenceConstants.CODEASSIST_INSERT_COMPLETION) ^ isToggleEating(); char[] completion = fProposal.getCompletion(); return !isInScriptdoc() && completion.length > 0 && (noOverwrite || completion[completion.length - 1] == ')'); } protected String computeReplacementString() { if (!hasArgumentList()) return super.computeReplacementString(); // we're inserting a method plus the argument list - respect formatter // preferences StringBuffer buffer = new StringBuffer(); JSSourceMethod method = (JSSourceMethod) fProposal.getModelElement(); if (CodeassistUtils.isStatic(method)) { buffer.append(CodeassistUtils.getCompletionToken(method, fSourceModule)); } else if (!CodeassistUtils.isStatic(method) && !CompletionContext.isInstanceContext() && !CodeassistUtils.isNativeObject(method)) { buffer.append(CodeassistUtils.THIS_STATIC); } buffer.append(fProposal.getName()); // FormatterPrefs prefs= getFormatterPrefs(); // if (prefs.beforeOpeningParen) // buffer.append(SPACE); buffer.append(LPAREN); if (hasParameters()) { setCursorPosition(buffer.length()); // if (prefs.afterOpeningParen) // buffer.append(SPACE); char[][] findParameterNames = fProposal.findParameterNames(null); for (int i = 0; i < findParameterNames.length;) { buffer.append(findParameterNames[i]); i++; if (i < findParameterNames.length) { buffer.append(COMMA); } } // don't add the trailing space, but let the user type it in himself // - typing the closing paren will exit // if (prefs.beforeClosingParen) // buffer.append(SPACE); } else { // if (prefs.inEmptyList) // buffer.append(SPACE); } buffer.append(RPAREN); return buffer.toString(); } protected ProposalInfo computeProposalInfo() { IScriptProject project = fInvocationContext.getProject(); if (project != null) return new MethodProposalInfo(project, fProposal); return super.computeProposalInfo(); } /** * Overrides the default context information position. Ignored if set to * zero. * * @param contextInformationPosition * the replaced position. */ public void setContextInformationPosition(int contextInformationPosition) { fContextInformationPosition = contextInformationPosition; } protected boolean isValidPrefix(String prefix) { if (super.isValidPrefix(prefix)) return true; String word = getDisplayString(); if (isInScriptdoc()) { int idx = word.indexOf("{@link "); //$NON-NLS-1$ if (idx == 0) { word = word.substring(7); } else { idx = word.indexOf("{@value "); //$NON-NLS-1$ if (idx == 0) { word = word.substring(8); } } } return isPrefix(prefix, word); } protected void handleSmartTrigger(IDocument document, char trigger, int referenceOffset) throws BadLocationException { // TODO Auto-generated method stub } protected boolean isSmartTrigger(char trigger) { return false; } public boolean isAutoInsertable() { return false; } @Override public Object getAdditionalProposalInfo(IProgressMonitor monitor) { IModelElement element = getModelElement(); String info = VjoCompletionProposal.getAdditionalPropesalInfo(element,getCSSStyles()); return info; } public void setSourceModule(ISourceModule sourceModule) { fSourceModule = sourceModule; } protected int computeRelevance() { return CodeassistUtils.getRelevance(fProposal); } }