/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, 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
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.editor.gsp.adapter;
import java.util.List;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyJavaFieldCompletionProposal;
import org.codehaus.groovy.eclipse.codeassist.requestor.GroovyCompletionProposalComputer;
import org.codehaus.groovy.eclipse.core.GroovyCore;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.codehaus.jdt.groovy.model.ICodeCompletionDelegate;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.groovy.core.util.ReflectionUtils;
import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
import org.eclipse.jdt.internal.codeassist.InternalCompletionProposal;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal;
import org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
/**
* Extends content assist so that it can be used within gsp pages.
* @author Andrew Eisenberg
* @author Christian Dupuis
* @created Dec 3, 2009
*/
public class CodeCompletionDelegate implements
ICodeCompletionDelegate {
public void codeComplete(ICompilationUnit unit, ICompilationUnit unitToSkip,
int position, CompletionRequestor requestor,
WorkingCopyOwner owner, ITypeRoot typeRoot, IProgressMonitor monitor)
throws JavaModelException {
InternalCompletionContext completionContext = new InternalCompletionContext();
requestor.acceptContext(completionContext);
GroovyCompletionProposalComputer computer = new GroovyCompletionProposalComputer();
JavaContentAssistInvocationContext context = createContext((GroovyCompilationUnit) typeRoot, position);
try {
if (GrailsCoreActivator.testMode) {
// on build server, GSPContentAssistTests are failing because
// monitor is being canceled. Avoid that problem here
monitor = new NullProgressMonitor() {
@Override
public void setCanceled(boolean cancelled) {
// no-op
}
};
}
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask("Content assist", 1);
List<ICompletionProposal> proposals = computer.computeCompletionProposals(context, monitor);
for (ICompletionProposal proposal : proposals) {
CompletionProposal cp = null;
if (proposal instanceof LazyJavaCompletionProposal) {
cp = (CompletionProposal) ReflectionUtils.getPrivateField(LazyJavaCompletionProposal.class, "fProposal", proposal); //$NON-NLS-1$
} else if (proposal instanceof GroovyJavaFieldCompletionProposal) {
cp = ((GroovyJavaFieldCompletionProposal) proposal).getProposal();
} else if (proposal instanceof JavaCompletionProposal) {
cp = createMockProposal((JavaCompletionProposal) proposal);
}
if (cp != null) {
requestor.accept(cp);
}
}
} catch (Exception e) {
GroovyCore.logException("Exception with code completion", e); //$NON-NLS-1$
}
}
/**
* Create the assist context. There are many fields that could be initialized. In the future
* they may need to be. But for now, only do what is absolutely necessary
*/
private JavaContentAssistInvocationContext createContext(GroovyCompilationUnit unit, int offset) {
JavaContentAssistInvocationContext context = new JavaContentAssistInvocationContext(unit);
ReflectionUtils.setPrivateField(ContentAssistInvocationContext.class, "fOffset", context, offset); //$NON-NLS-1$
ReflectionUtils.setPrivateField(ContentAssistInvocationContext.class, "fDocument", context, new Document(new String(unit.getContents()))); //$NON-NLS-1$
return context;
}
public boolean shouldCodeComplete(CompletionRequestor requestor,
ITypeRoot typeRoot) {
return requestor instanceof org.eclipse.jst.jsp.ui.internal.contentassist.JSPProposalCollector && typeRoot instanceof GroovyCompilationUnit;
}
/**
* The proposals from fields and properties do not have an associated ICompletionProposal, so create a
* mock one
* @param javaProposal
* @return
*/
private CompletionProposal createMockProposal(JavaCompletionProposal javaProposal) {
InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.FIELD_REF, javaProposal.getReplacementOffset());
proposal.setDeclarationSignature(Signature.createTypeSignature("def", false).toCharArray()); //$NON-NLS-1$
proposal.setFlags(Flags.AccPublic);
proposal.setName(javaProposal.getReplacementString().toCharArray());
proposal.setCompletion(javaProposal.getReplacementString().toCharArray());
proposal.setSignature(Signature.createTypeSignature("def", false).toCharArray()); //$NON-NLS-1$
proposal.setReplaceRange(javaProposal.getReplacementOffset(), javaProposal.getReplacementOffset()+1);
proposal.setRelevance(5000);
return proposal;
}
}