/*
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.codeassist.processors;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistContext;
import org.codehaus.jdt.groovy.internal.compiler.ast.JDTResolver;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.groovy.search.ITypeResolver;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
public class PackageCompletionProcessor extends AbstractGroovyCompletionProcessor implements ITypeResolver {
protected JDTResolver resolver;
public PackageCompletionProcessor(ContentAssistContext context, JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {
super(context, javaContext, nameEnvironment);
}
public void setResolverInformation(ModuleNode module, JDTResolver resolver) {
this.resolver = resolver;
}
public List<ICompletionProposal> generateProposals(IProgressMonitor monitor) {
ContentAssistContext context = getContext();
char[] packageCompletionText = getPackageCompletionText(context.fullCompletionExpression);
if (mightBePackage(packageCompletionText)) {
int expressionStart = context.completionLocation - context.fullCompletionExpression.trim().length();
GroovyProposalTypeSearchRequestor requestor = new GroovyProposalTypeSearchRequestor(//
context, getJavaContext(), expressionStart, context.completionEnd - expressionStart,
getNameEnvironment().nameLookup, monitor);
getNameEnvironment().findPackages(packageCompletionText, requestor);
List<ICompletionProposal> typeProposals = requestor.processAcceptedPackages();
boolean alsoLookForTypes = shouldLookForTypes(packageCompletionText);
if (alsoLookForTypes) {
getNameEnvironment().findTypes(packageCompletionText,
true /* find all member types, should be false when in constructor*/,
true /* camel case match */, getSearchFor(), requestor, monitor);
typeProposals.addAll(requestor.processAcceptedTypes(resolver));
}
return typeProposals;
}
return Collections.emptyList();
}
/**
* Do not look for types if there is no '.'. In this case,
* type searching is handled by {@link TypeCompletionProcessor}.
* @param packageCompletionText
* @return
*/
private boolean shouldLookForTypes(char[] packageCompletionText) {
return CharOperation.indexOf('.', packageCompletionText) > -1;
}
/**
* more complete search to see if this is a valid package name
* @param packageCompletionText
* @return
*/
private boolean mightBePackage(char[] packageCompletionText) {
if (packageCompletionText == null || packageCompletionText.length == 0) {
return false;
}
String text = String.valueOf(packageCompletionText);
String[] splits = text.split("\\.");
for (String split : splits) {
// use 1.7 because backwards compatibility ensures that nothing is missed.
if (split.length() > 0) {
IStatus status = JavaConventions.validateIdentifier(split, "1.7", "1.7");
if (status.getSeverity() >= IStatus.ERROR) {
return false;
}
}
}
return true;
}
/**
* removes whitespace and does a fail-fast if a non-java identifier is found
*/
private char[] getPackageCompletionText(String fullCompletionExpression) {
List<Character> chars = new LinkedList<Character>();
if (fullCompletionExpression == null) {
return CharOperation.NO_CHAR;
}
char[] fullArray = fullCompletionExpression.toCharArray();
for (int i = 0; i < fullArray.length; i++) {
if (Character.isWhitespace(fullArray[i])) {
continue;
} else if (Character.isJavaIdentifierPart(fullArray[i]) || fullArray[i] == '.') {
chars.add(fullArray[i]);
} else {
// fail fast if something odd is found like parens or brackets
return null;
}
}
char[] res = new char[chars.size()];
int i = 0;
for (Character c : chars) {
res[i] = c.charValue();
i++;
}
return res;
}
private int getSearchFor() {
switch(getContext().location) {
case EXTENDS:
return IJavaSearchConstants.CLASS;
case IMPLEMENTS:
return IJavaSearchConstants.INTERFACE;
case EXCEPTIONS:
return IJavaSearchConstants.CLASS;
default:
return IJavaSearchConstants.TYPE;
}
}
}