/**
* Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Created on 21/08/2005
*/
package com.python.pydev.codecompletion.participant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.swt.graphics.Image;
import org.python.pydev.core.FullRepIterable;
import org.python.pydev.core.ICodeCompletionASTManager;
import org.python.pydev.core.ICompletionState;
import org.python.pydev.core.ILocalScope;
import org.python.pydev.core.IModulesManager;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IToken;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.PythonNatureWithoutProjectException;
import org.python.pydev.core.docutils.PySelection.ActivationTokenAndQual;
import org.python.pydev.editor.codecompletion.CompletionRequest;
import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant;
import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant2;
import org.python.pydev.editor.codecompletion.ProposalsComparator.CompareContext;
import org.python.pydev.editor.codecompletion.PyCodeCompletionImages;
import org.python.pydev.editor.codecompletion.PyCodeCompletionPreferencesPage;
import org.python.pydev.editor.codecompletion.PyCodeCompletionUtils;
import org.python.pydev.editor.codecompletion.PyCodeCompletionUtils.IFilter;
import org.python.pydev.shared_core.string.FastStringBuffer;
import org.python.pydev.shared_interactive_console.console.ui.IScriptConsoleViewer;
import org.python.pydev.shared_ui.proposals.IPyCompletionProposal;
import org.python.pydev.shared_ui.proposals.IPyCompletionProposal.ICompareContext;
import com.python.pydev.analysis.CtxInsensitiveImportComplProposal;
import com.python.pydev.analysis.ui.AutoImportsPreferencesPage;
import com.python.pydev.codecompletion.ctxinsensitive.PyConsoleCompletion;
import com.python.pydev.codecompletion.ui.CodeCompletionPreferencesPage;
/**
* Gathers completions from the modules available (for the editor or for the console).
*
* @author Fabio
*/
public class ImportsCompletionParticipant implements IPyDevCompletionParticipant, IPyDevCompletionParticipant2 {
// Console completions ---------------------------------------------------------------------------------------------
@Override
public Collection<ICompletionProposal> computeConsoleCompletions(ActivationTokenAndQual tokenAndQual,
Set<IPythonNature> naturesUsed, IScriptConsoleViewer viewer, int requestOffset) {
ArrayList<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
if (tokenAndQual.activationToken != null && tokenAndQual.activationToken.length() > 0) {
//we only want
return completions;
}
String qual = tokenAndQual.qualifier;
if (qual.length() >= CodeCompletionPreferencesPage.getCharsForContextInsensitiveModulesCompletion()
&& naturesUsed != null && naturesUsed.size() > 0) { //at least n characters required...
int qlen = qual.length();
boolean addAutoImport = AutoImportsPreferencesPage.doAutoImport();
for (IPythonNature nature : naturesUsed) {
fillCompletions(requestOffset, completions, qual, nature, qlen, addAutoImport, viewer);
}
}
return completions;
}
private void fillCompletions(int requestOffset, ArrayList<ICompletionProposal> completions, String qual,
IPythonNature nature, int qlen, boolean addAutoImport, IScriptConsoleViewer viewer) {
ICodeCompletionASTManager astManager = nature.getAstManager();
if (astManager == null) {
return;
}
Image img = PyCodeCompletionImages.getImageForType(IToken.TYPE_PACKAGE);
IModulesManager modulesManager = astManager.getModulesManager();
try {
if (modulesManager == null) {
nature.getProjectInterpreter(); //Just getting it here is likely to raise an error if it's not well configured.
}
} catch (PythonNatureWithoutProjectException e) {
throw new RuntimeException(e);
} catch (MisconfigurationException e) {
throw new RuntimeException(e);
}
String lowerQual = qual.toLowerCase();
final boolean useSubstringMatchInCodeCompletion = PyCodeCompletionPreferencesPage
.getUseSubstringMatchInCodeCompletion();
Set<String> allModuleNames = PyCodeCompletionUtils.getModulesNamesToFilterOn(useSubstringMatchInCodeCompletion,
modulesManager, qual);
IFilter nameFilter = PyCodeCompletionUtils.getNameFilter(useSubstringMatchInCodeCompletion, qual);
FastStringBuffer realImportRep = new FastStringBuffer();
FastStringBuffer displayString = new FastStringBuffer();
HashSet<String> alreadyFound = new HashSet<String>();
ICompareContext compareContext = new CompareContext(nature);
for (String name : allModuleNames) {
FullRepIterable iterable = new FullRepIterable(name);
for (String string : iterable) {
//clear the buffer...
realImportRep.clear();
String[] strings = FullRepIterable.headAndTail(string);
String importRep = strings[1];
if (!nameFilter.acceptName(importRep)) {
continue;
}
displayString.clear();
displayString.append(importRep);
String packageName = strings[0];
if (packageName.length() > 0) {
if (addAutoImport) {
realImportRep.append("from ");
realImportRep.append(packageName);
realImportRep.append(" ");
}
displayString.append(" - ");
displayString.append(packageName);
}
if (addAutoImport) {
realImportRep.append("import ");
realImportRep.append(strings[1]);
}
String found = displayString.toString();
if (alreadyFound.contains(found)) {
continue;
}
alreadyFound.add(found);
String displayAsStr = realImportRep.toString();
PyConsoleCompletion proposal = new PyConsoleCompletion(importRep, requestOffset - qlen, qlen,
realImportRep.length(), img, found, (IContextInformation) null, "",
displayAsStr.toLowerCase().equals(lowerQual) ? IPyCompletionProposal.PRIORITY_PACKAGES_EXACT
: IPyCompletionProposal.PRIORITY_PACKAGES,
displayAsStr, viewer, compareContext);
completions.add(proposal);
}
}
}
// Editor completions ----------------------------------------------------------------------------------------------
private Collection<CtxInsensitiveImportComplProposal> getThem(CompletionRequest request, ICompletionState state,
boolean addAutoImport) throws MisconfigurationException {
ArrayList<CtxInsensitiveImportComplProposal> list = new ArrayList<CtxInsensitiveImportComplProposal>();
if (request.isInCalltip) {
return list;
}
if (request.qualifier.length() >= CodeCompletionPreferencesPage
.getCharsForContextInsensitiveModulesCompletion()) { //at least n characters required...
ICodeCompletionASTManager astManager = request.nature.getAstManager();
if (astManager == null) {
return list;
}
String initialModule = request.resolveModule();
Image img = PyCodeCompletionImages.getImageForType(IToken.TYPE_PACKAGE);
IModulesManager projectModulesManager = astManager.getModulesManager();
String lowerQual = request.qualifier.toLowerCase();
final boolean useSubstringMatchInCodeCompletion = request.useSubstringMatchInCodeCompletion;
IModulesManager[] managersInvolved = projectModulesManager.getManagersInvolved(true);
for (int i = 0; i < managersInvolved.length; i++) {
IModulesManager currentManager = managersInvolved[i];
final Set<String> allModuleNames = PyCodeCompletionUtils.getModulesNamesToFilterOn(
useSubstringMatchInCodeCompletion, currentManager, request.qualifier);
final IFilter nameFilter = PyCodeCompletionUtils.getNameFilter(useSubstringMatchInCodeCompletion,
request.qualifier);
FastStringBuffer realImportRep = new FastStringBuffer();
FastStringBuffer displayString = new FastStringBuffer();
HashSet<String> importedNames = getImportedNames(state);
for (String name : allModuleNames) {
if (name.equals(initialModule)) {
continue;
}
FullRepIterable iterable = new FullRepIterable(name);
for (String string : iterable) {
//clear the buffer...
realImportRep.clear();
String[] strings = FullRepIterable.headAndTail(string);
String importRep = strings[1];
if (!nameFilter.acceptName(importRep) || importedNames.contains(importRep)) {
continue;
}
displayString.clear();
displayString.append(importRep);
String packageName = strings[0];
if (packageName.length() > 0) {
if (addAutoImport) {
realImportRep.append("from ");
realImportRep.append(packageName);
realImportRep.append(" ");
}
displayString.append(" - ");
displayString.append(packageName);
}
if (addAutoImport) {
realImportRep.append("import ");
realImportRep.append(strings[1]);
}
String displayAsStr = displayString.toString();
CtxInsensitiveImportComplProposal proposal = new CtxInsensitiveImportComplProposal(
importRep,
request.documentOffset - request.qlen,
request.qlen,
realImportRep.length(),
img,
displayAsStr,
(IContextInformation) null,
"",
displayAsStr.toLowerCase().equals(lowerQual)
? IPyCompletionProposal.PRIORITY_PACKAGES_EXACT
: IPyCompletionProposal.PRIORITY_PACKAGES,
realImportRep.toString(),
new CompareContext(currentManager.getNature()));
list.add(proposal);
}
}
}
}
return list;
}
private HashSet<String> getImportedNames(ICompletionState state) {
List<IToken> tokenImportedModules = state.getTokenImportedModules();
HashSet<String> importedNames = new HashSet<String>();
if (tokenImportedModules != null) {
for (IToken token : tokenImportedModules) {
importedNames.add(token.getRepresentation());
}
}
return importedNames;
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection getGlobalCompletions(CompletionRequest request, ICompletionState state)
throws MisconfigurationException {
return getThem(request, state, AutoImportsPreferencesPage.doAutoImport());
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection getCompletionsForMethodParameter(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
return Collections.emptyList();
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection getStringGlobalCompletions(CompletionRequest request, ICompletionState state)
throws MisconfigurationException {
return getThem(request, state, false);
}
@Override
public Collection<Object> getArgsCompletion(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
throw new RuntimeException("Deprecated");
}
@Override
public Collection<IToken> getCompletionsForTokenWithUndefinedType(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
return Collections.emptyList();
}
@Override
public Collection<IToken> getCompletionsForType(ICompletionState state) {
return null;
}
}