/**
* Copyright (c) 2005-2011 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 07/09/2005
*/
package com.python.pydev.codecompletion.ctxinsensitive;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.python.pydev.core.ICompletionState;
import org.python.pydev.core.ILocalScope;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IToken;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.docutils.PySelection.ActivationTokenAndQual;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.codecompletion.CompletionRequest;
import org.python.pydev.editor.codecompletion.IPyCompletionProposal;
import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant;
import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant2;
import org.python.pydev.editor.codecompletion.revisited.modules.SourceToken;
import org.python.pydev.plugin.PydevPlugin;
import com.aptana.interactive_console.console.ui.IScriptConsoleViewer;
import com.aptana.shared_core.string.FastStringBuffer;
import com.python.pydev.analysis.AnalysisPlugin;
import com.python.pydev.analysis.CtxInsensitiveImportComplProposal;
import com.python.pydev.analysis.additionalinfo.AbstractAdditionalTokensInfo;
import com.python.pydev.analysis.additionalinfo.AdditionalProjectInterpreterInfo;
import com.python.pydev.analysis.additionalinfo.AdditionalSystemInterpreterInfo;
import com.python.pydev.analysis.additionalinfo.IInfo;
import com.python.pydev.analysis.ui.AutoImportsPreferencesPage;
import com.python.pydev.codecompletion.ui.CodeCompletionPreferencesPage;
/**
* Provides the completions in a context-insensitive way for classes and methods (both for the editor or the console).
*
* @author Fabio
*/
public class CtxParticipant implements IPyDevCompletionParticipant, IPyDevCompletionParticipant2 {
// Console completions ---------------------------------------------------------------------------------------------
/**
* IPyDevCompletionParticipant2
*/
public Collection<ICompletionProposal> computeConsoleCompletions(ActivationTokenAndQual tokenAndQual,
List<IPythonNature> naturesUsed, IScriptConsoleViewer viewer, int requestOffset) {
List<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.getCharsForContextInsensitiveGlobalTokensCompletion()
&& naturesUsed != null && naturesUsed.size() > 0) { //at least n characters required...
boolean addAutoImport = AutoImportsPreferencesPage.doAutoImport();
int qlen = qual.length();
String lowerQual = qual.toLowerCase();
for (IPythonNature nature : naturesUsed) {
fillNatureCompletionsForConsole(viewer, requestOffset, completions, qual, addAutoImport, qlen,
lowerQual, nature, false);
}
//and at last, get from the system
fillNatureCompletionsForConsole(viewer, requestOffset, completions, qual, addAutoImport, qlen, lowerQual,
naturesUsed.get(0), true);
}
return completions;
}
private void fillNatureCompletionsForConsole(IScriptConsoleViewer viewer, int requestOffset,
List<ICompletionProposal> completions, String qual, boolean addAutoImport, int qlen, String lowerQual,
IPythonNature nature, boolean getSystem) {
AbstractAdditionalTokensInfo additionalInfoForProject;
if (getSystem) {
try {
additionalInfoForProject = AdditionalSystemInterpreterInfo.getAdditionalSystemInfo(
PydevPlugin.getInterpreterManager(nature), nature.getProjectInterpreter().getExecutableOrJar());
} catch (Exception e) {
Log.log(e);
return;
}
} else {
try {
additionalInfoForProject = AdditionalProjectInterpreterInfo.getAdditionalInfoForProject(nature);
} catch (Exception e) {
Log.log(e);
return;
}
}
Collection<IInfo> tokensStartingWith = additionalInfoForProject.getTokensStartingWith(qual,
AbstractAdditionalTokensInfo.TOP_LEVEL);
FastStringBuffer realImportRep = new FastStringBuffer();
FastStringBuffer displayString = new FastStringBuffer();
FastStringBuffer tempBuf = new FastStringBuffer();
boolean doIgnoreImportsStartingWithUnder = AutoImportsPreferencesPage.doIgnoreImportsStartingWithUnder();
for (IInfo info : tokensStartingWith) {
//there always must be a declaringModuleName
String declaringModuleName = info.getDeclaringModuleName();
boolean hasInit = false;
if (declaringModuleName.endsWith(".__init__")) {
declaringModuleName = declaringModuleName.substring(0, declaringModuleName.length() - 9);//remove the .__init__
hasInit = true;
}
String rep = info.getName();
String lowerRep = rep.toLowerCase();
if (!lowerRep.startsWith(lowerQual)) {
continue;
}
if (addAutoImport) {
realImportRep.clear();
realImportRep.append("from ");
realImportRep.append(AutoImportsPreferencesPage.removeImportsStartingWithUnderIfNeeded(
declaringModuleName, tempBuf, doIgnoreImportsStartingWithUnder));
realImportRep.append(" import ");
realImportRep.append(rep);
}
displayString.clear();
displayString.append(rep);
displayString.append(" - ");
displayString.append(declaringModuleName);
if (hasInit) {
displayString.append(".__init__");
}
PyConsoleCompletion proposal = new PyConsoleCompletion(rep, requestOffset - qlen, qlen,
realImportRep.length(), AnalysisPlugin.getImageForAutoImportTypeInfo(info),
displayString.toString(), (IContextInformation) null, "",
lowerRep.equals(lowerQual) ? IPyCompletionProposal.PRIORITY_LOCALS_1
: IPyCompletionProposal.PRIORITY_GLOBALS, realImportRep.toString(), viewer);
completions.add(proposal);
}
}
// Editor completions ----------------------------------------------------------------------------------------------
private Collection<CtxInsensitiveImportComplProposal> getThem(CompletionRequest request, ICompletionState state,
boolean addAutoImport) throws MisconfigurationException {
ArrayList<CtxInsensitiveImportComplProposal> completions = new ArrayList<CtxInsensitiveImportComplProposal>();
if (request.isInCalltip) {
return completions;
}
HashSet<String> importedNames = getImportedNames(state);
String qual = request.qualifier;
if (qual.length() >= CodeCompletionPreferencesPage.getCharsForContextInsensitiveGlobalTokensCompletion()) { //at least n characters required...
String lowerQual = qual.toLowerCase();
String initialModule = request.resolveModule();
List<IInfo> tokensStartingWith = AdditionalProjectInterpreterInfo.getTokensStartingWith(qual,
request.nature, AbstractAdditionalTokensInfo.TOP_LEVEL);
FastStringBuffer realImportRep = new FastStringBuffer();
FastStringBuffer displayString = new FastStringBuffer();
FastStringBuffer tempBuf = new FastStringBuffer();
boolean doIgnoreImportsStartingWithUnder = AutoImportsPreferencesPage.doIgnoreImportsStartingWithUnder();
for (IInfo info : tokensStartingWith) {
//there always must be a declaringModuleName
String declaringModuleName = info.getDeclaringModuleName();
if (initialModule != null && declaringModuleName != null) {
if (initialModule.equals(declaringModuleName)) {
continue;
}
}
boolean hasInit = false;
if (declaringModuleName.endsWith(".__init__")) {
declaringModuleName = declaringModuleName.substring(0, declaringModuleName.length() - 9);//remove the .__init__
hasInit = true;
}
String rep = info.getName();
String lowerRep = rep.toLowerCase();
if (!lowerRep.startsWith(lowerQual) || importedNames.contains(rep)) {
continue;
}
if (addAutoImport) {
realImportRep.clear();
realImportRep.append("from ");
realImportRep.append(AutoImportsPreferencesPage.removeImportsStartingWithUnderIfNeeded(
declaringModuleName, tempBuf, doIgnoreImportsStartingWithUnder));
realImportRep.append(" import ");
realImportRep.append(rep);
}
displayString.clear();
displayString.append(rep);
displayString.append(" - ");
displayString.append(declaringModuleName);
if (hasInit) {
displayString.append(".__init__");
}
CtxInsensitiveImportComplProposal proposal = new CtxInsensitiveImportComplProposal(rep,
request.documentOffset - request.qlen, request.qlen, realImportRep.length(),
AnalysisPlugin.getImageForAutoImportTypeInfo(info), displayString.toString(),
(IContextInformation) null, "",
lowerRep.equals(lowerQual) ? IPyCompletionProposal.PRIORITY_LOCALS_1
: IPyCompletionProposal.PRIORITY_GLOBALS, realImportRep.toString());
completions.add(proposal);
}
}
return completions;
}
/**
* @return the names that are already imported in the current document
*/
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;
}
@SuppressWarnings("unchecked")
public Collection getGlobalCompletions(CompletionRequest request, ICompletionState state)
throws MisconfigurationException {
return getThem(request, state, AutoImportsPreferencesPage.doAutoImport());
}
/**
* IPyDevCompletionParticipant
*/
@SuppressWarnings("unchecked")
public Collection getCompletionsForMethodParameter(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
ArrayList<IToken> ret = new ArrayList<IToken>();
String qual = state.getQualifier();
if (qual.length() >= CodeCompletionPreferencesPage.getCharsForContextInsensitiveGlobalTokensCompletion()) { //at least n characters
List<IInfo> tokensStartingWith;
try {
tokensStartingWith = AdditionalProjectInterpreterInfo.getTokensStartingWith(qual, state.getNature(),
AbstractAdditionalTokensInfo.INNER);
} catch (MisconfigurationException e) {
Log.log(e);
return ret;
}
for (IInfo info : tokensStartingWith) {
ret.add(new SourceToken(null, info.getName(), null, null, info.getDeclaringModuleName(), info.getType()));
}
}
return ret;
}
/**
* IPyDevCompletionParticipant
* @throws MisconfigurationException
*/
@SuppressWarnings("unchecked")
public Collection getStringGlobalCompletions(CompletionRequest request, ICompletionState state)
throws MisconfigurationException {
return getThem(request, state, false);
}
public Collection<Object> getArgsCompletion(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
throw new RuntimeException("Deprecated");
}
@SuppressWarnings("unchecked")
public Collection<IToken> getCompletionsForTokenWithUndefinedType(ICompletionState state, ILocalScope localScope,
Collection<IToken> interfaceForLocal) {
return getCompletionsForMethodParameter(state, localScope, interfaceForLocal);
}
}