/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation 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:
* Andrew McCullough - initial API and implementation
* IBM Corporation - general improvement and bug fixes, partial reimplementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.jdt.codeassistant;
import org.eclipse.che.ide.ext.java.jdt.core.CompletionContext;
import org.eclipse.che.ide.ext.java.jdt.core.CompletionProposal;
import org.eclipse.che.ide.ext.java.jdt.core.Signature;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.util.SignatureUtil;
import org.eclipse.che.ide.ext.java.jdt.text.Document;
import org.eclipse.che.ide.ext.java.jdt.text.PositionUpdater;
import org.eclipse.che.ide.api.text.BadPositionCategoryException;
import org.eclipse.che.ide.api.text.Position;
import org.eclipse.che.ide.api.text.Region;
import org.eclipse.che.ide.api.text.RegionImpl;
/** This is a which includes templates that represent the best guess completion for each parameter of a method. */
public final class ParameterGuessingProposal extends JavaMethodCompletionProposal {
/**
* Creates a {@link ParameterGuessingProposal} or <code>null</code> if the core context isn't available or extended.
*
* @param proposal
* the original completion proposal
* @param context
* the currrent context
* @param fillBestGuess
* if set, the best guess will be filled in
* @return a proposal or <code>null</code>
*/
public static ParameterGuessingProposal createProposal(CompletionProposal proposal,
JavaContentAssistInvocationContext context, boolean fillBestGuess) {
CompletionContext coreContext = context.getCoreContext();
if (coreContext != null && coreContext.isExtended()) {
return new ParameterGuessingProposal(proposal, context, coreContext, fillBestGuess);
}
return null;
}
/** Tells whether this class is in debug mode. */
private static final boolean DEBUG = false;
//"true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jdt.ui/debug/ResultCollector")); //$NON-NLS-1$//$NON-NLS-2$
private CompletionProposal[][] fChoices; // initialized by guessParameters()
private Position[] fPositions; // initialized by guessParameters()
private Region fSelectedRegion; // initialized by apply()
private PositionUpdater fUpdater;
private final boolean fFillBestGuess;
private final CompletionContext fCoreContext;
private ParameterGuessingProposal(CompletionProposal proposal, JavaContentAssistInvocationContext context,
CompletionContext coreContext, boolean fillBestGuess) {
super(proposal, context);
fCoreContext = coreContext;
fFillBestGuess = fillBestGuess;
}
// private ASTNode getEnclosingElement() {
// return fCoreContext.getEnclosingElement();
// fInvocationContext.getCompilationUnit()
// f.findField(fieldHandle)
// }
// private IJavaElement[][] getAssignableElements() {
// char[] signature= SignatureUtil.fix83600(getProposal().getSignature());
// char[][] types= Signature.getParameterTypes(signature);
//
// IJavaElement[][] assignableElements= new IJavaElement[types.length][];
// for (int i= 0; i < types.length; i++) {
// assignableElements[i]= fCoreContext.getVisibleElements(new String(types[i]));
// }
// return assignableElements;
// }
/*
* @see ICompletionProposalExtension#apply(IDocument, char)
*/
@Override
public void apply(Document document, char trigger, int offset) {
// try {
super.apply(document, trigger, offset);
// int baseOffset= getReplacementOffset();
// String replacement= getReplacementString();
//
// if (fPositions != null && getTextViewer() != null) {
//
// LinkedModeModel model= new LinkedModeModel();
//
// for (int i= 0; i < fPositions.length; i++) {
// LinkedPositionGroup group= new LinkedPositionGroup();
// int positionOffset= fPositions[i].getOffset();
// int positionLength= fPositions[i].getLength();
//
// if (fChoices[i].length < 2) {
// group.addPosition(new LinkedPosition(document, positionOffset, positionLength, LinkedPositionGroup.NO_STOP));
// } else {
// ensurePositionCategoryInstalled(document, model);
// document.addPosition(getCategory(), fPositions[i]);
// group.addPosition(new ProposalPosition(document, positionOffset, positionLength, LinkedPositionGroup.NO_STOP,
// fChoices[i]));
// }
// model.addGroup(group);
// }
//
// model.forceInstall();
// JavaEditor editor= getJavaEditor();
// if (editor != null) {
// model.addLinkingListener(new EditorHighlightingSynchronizer(editor));
// }
//
// LinkedModeUI ui= new EditorLinkedModeUI(model, getTextViewer());
// ui.setExitPosition(getTextViewer(), baseOffset + replacement.length(), 0, Integer.MAX_VALUE);
// ui.setExitPolicy(new ExitPolicy(')', document));
// ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT);
// ui.setDoContextInfo(true);
// ui.enter();
// fSelectedRegion= ui.getSelectedRegion();
//
// } else {
// fSelectedRegion= new Region(baseOffset + replacement.length(), 0);
// }
//
// } catch (BadLocationException e) {
// ensurePositionCategoryRemoved(document);
// JavaPlugin.log(e);
// openErrorDialog(e);
// } catch (BadPositionCategoryException e) {
// ensurePositionCategoryRemoved(document);
// JavaPlugin.log(e);
// openErrorDialog(e);
// }
}
/*
* @see org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal#needsLinkedMode()
*/
@Override
protected boolean needsLinkedMode() {
return false; // we handle it ourselves
}
/*
* @see org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal#computeReplacementString()
*/
@Override
protected String computeReplacementString() {
if (!hasParameters() || !hasArgumentList())
return super.computeReplacementString();
long millis = DEBUG ? System.currentTimeMillis() : 0;
String replacement;
// try {
replacement = computeGuessingCompletion();
// } catch (JavaModelException x) {
// fPositions= null;
// fChoices= null;
// JavaPlugin.log(x);
// openErrorDialog(x);
// return super.computeReplacementString();
// }
if (DEBUG)
System.err.println("Parameter Guessing: " + (System.currentTimeMillis() - millis)); //$NON-NLS-1$
return replacement;
}
/**
* Creates the completion string. Offsets and Lengths are set to the offsets and lengths of the parameters.
*
* @return the completion string
*/
private String computeGuessingCompletion() {
StringBuffer buffer = new StringBuffer();
appendMethodNameReplacement(buffer);
FormatterPrefs prefs = getFormatterPrefs();
setCursorPosition(buffer.length());
if (prefs.afterOpeningParen)
buffer.append(SPACE);
char[][] parameterNames = fProposal.findParameterNames();
fChoices = guessParameters(parameterNames);
int count = fChoices.length;
int replacementOffset = getReplacementOffset();
for (int i = 0; i < count; i++) {
if (i != 0) {
if (prefs.beforeComma)
buffer.append(SPACE);
buffer.append(COMMA);
if (prefs.afterComma)
buffer.append(SPACE);
}
// ICompletionProposal proposal= fChoices[i][0];
// String argument= proposal.getDisplayString();
//
// Position position= fPositions[i];
// position.setOffset(replacementOffset + buffer.length());
// position.setLength(argument.length());
//
// if (proposal instanceof JavaCompletionProposal) // handle the "unknown" case where we only insert a proposal.
// ((JavaCompletionProposal) proposal).setReplacementOffset(replacementOffset + buffer.length());
buffer.append(parameterNames[i]);
}
if (prefs.beforeClosingParen)
buffer.append(SPACE);
buffer.append(RPAREN);
return buffer.toString();
}
// /**
// * Returns the currently active java editor, or <code>null</code> if it
// * cannot be determined.
// *
// * @return the currently active java editor, or <code>null</code>
// */
// private JavaEditor getJavaEditor() {
// IEditorPart part= JavaPlugin.getActivePage().getActiveEditor();
// if (part instanceof JavaEditor)
// return (JavaEditor) part;
// else
// return null;
// }
private CompletionProposal[][] guessParameters(char[][] parameterNames) {
// find matches in reverse order. Do this because people tend to declare the variable meant for the last
// parameter last. That is, local variables for the last parameter in the method completion are more
// likely to be closer to the point of code completion. As an example consider a "delegation" completion:
//
// public void myMethod(int param1, int param2, int param3) {
// someOtherObject.yourMethod(param1, param2, param3);
// }
//
// The other consideration is giving preference to variables that have not previously been used in this
// code completion (which avoids "someOtherObject.yourMethod(param1, param1, param1)";
int count = parameterNames.length;
fPositions = new Position[count];
fChoices = new CompletionProposal[count][];
String[] parameterTypes = getParameterTypes();
// ParameterGuesser guesser= new ParameterGuesser(getEnclosingElement());
// IJavaElement[][] assignableElements= getAssignableElements();
// for (int i= count - 1; i >= 0; i--) {
// String paramName= new String(parameterNames[i]);
// Position position= new Position(0,0);
//
// boolean isLastParameter= i == count - 1;
// ICompletionProposal[] argumentProposals= guesser.parameterProposals(parameterTypes[i], paramName, position,
// assignableElements[i], fFillBestGuess, isLastParameter);
// if (argumentProposals.length == 0) {
// JavaCompletionProposal proposal= new JavaCompletionProposal(paramName, 0, paramName.length(), null, new
// StyledString(paramName), 0, false, fInvocationContext);
// if (isLastParameter)
// proposal.setTriggerCharacters(new char[] { ',' });
// argumentProposals= new ICompletionProposal[] { proposal };
// }
//
// fPositions[i]= position;
// fChoices[i]= argumentProposals;
// }
return fChoices;
}
private String[] getParameterTypes() {
char[] signature = SignatureUtil.fix83600(fProposal.getSignature());
char[][] types = Signature.getParameterTypes(signature);
String[] ret = new String[types.length];
for (int i = 0; i < types.length; i++) {
ret[i] = new String(Signature.toCharArray(types[i]));
}
return ret;
}
/*
* @see ICompletionProposal#getSelection(IDocument)
*/
@Override
public Region getSelection(Document document) {
if (fSelectedRegion == null)
return new RegionImpl(getReplacementOffset(), 0);
return fSelectedRegion;
}
// private void openErrorDialog(Exception e) {
// Shell shell= getTextViewer().getTextWidget().getShell();
// MessageDialog.openError(shell, JavaTextMessages.ParameterGuessingProposal_error_msg, e.getMessage());
// }
// private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) {
// if (!document.containsPositionCategory(getCategory())) {
// document.addPositionCategory(getCategory());
// fUpdater= new InclusivePositionUpdater(getCategory());
// document.addPositionUpdater(fUpdater);
//
// model.addLinkingListener(new ILinkedModeListener() {
//
// /*
// * @see org.eclipse.jface.text.link.ILinkedModeListener#left(org.eclipse.jface.text.link.LinkedModeModel, int)
// */
// public void left(LinkedModeModel environment, int flags) {
// ensurePositionCategoryRemoved(document);
// }
//
// public void suspend(LinkedModeModel environment) {}
// public void resume(LinkedModeModel environment, int flags) {}
// });
// }
// }
private void ensurePositionCategoryRemoved(Document document) {
if (document.containsPositionCategory(getCategory())) {
try {
document.removePositionCategory(getCategory());
} catch (BadPositionCategoryException e) {
// ignore
}
document.removePositionUpdater(fUpdater);
}
}
private String getCategory() {
return "ParameterGuessingProposal_" + toString(); //$NON-NLS-1$
}
}