[Pydev-cvs] org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited SystemASTManager.j
Brought to you by:
fabioz
From: Fabio Z. <fa...@us...> - 2006-01-16 17:17:59
|
Update of /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14759/src/org/python/pydev/editor/codecompletion/revisited Modified Files: PythonPathHelper.java SystemModulesManager.java ProjectModulesManager.java ASTManager.java ModulesManager.java Added Files: SystemASTManager.java AbstractASTManager.java Log Message: Index: SystemModulesManager.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited/SystemModulesManager.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** SystemModulesManager.java 15 Jan 2006 00:25:10 -0000 1.5 --- SystemModulesManager.java 16 Jan 2006 17:17:49 -0000 1.6 *************** *** 6,11 **** --- 6,15 ---- package org.python.pydev.editor.codecompletion.revisited; + import java.util.ArrayList; import java.util.Collection; + import java.util.List; + import org.python.pydev.core.IModule; + import org.python.pydev.core.IPythonNature; import org.python.pydev.core.ISystemModulesManager; *************** *** 17,25 **** private static final long serialVersionUID = 1L; private String[] builtins; /** * @param forcedLibs */ ! public SystemModulesManager(Collection forcedLibs) { regenerateForcedBuilltins(forcedLibs); } --- 21,30 ---- private static final long serialVersionUID = 1L; private String[] builtins; + private IPythonNature nature; /** * @param forcedLibs */ ! public SystemModulesManager(Collection<String> forcedLibs) { regenerateForcedBuilltins(forcedLibs); } *************** *** 28,32 **** * @see org.python.pydev.core.ISystemModulesManager#regenerateForcedBuilltins(java.util.Collection) */ ! public void regenerateForcedBuilltins(Collection forcedLibs){ this.builtins = (String[]) forcedLibs.toArray(new String[0]); } --- 33,37 ---- * @see org.python.pydev.core.ISystemModulesManager#regenerateForcedBuilltins(java.util.Collection) */ ! public void regenerateForcedBuilltins(Collection<String> forcedLibs){ this.builtins = (String[]) forcedLibs.toArray(new String[0]); } *************** *** 42,48 **** * @see org.python.pydev.core.ISystemModulesManager#setBuiltins(java.util.Collection) */ ! public void setBuiltins(Collection forcedLibs) { regenerateForcedBuilltins(forcedLibs); } } --- 47,78 ---- * @see org.python.pydev.core.ISystemModulesManager#setBuiltins(java.util.Collection) */ ! public void setBuiltins(Collection<String> forcedLibs) { regenerateForcedBuilltins(forcedLibs); } + public void setPythonNature(IPythonNature nature) { + this.nature = nature; + } + + public IPythonNature getNature() { + return nature; + } + + public ISystemModulesManager getSystemModulesManager() { + return this; //itself + } + + public IModule getModule(String name, IPythonNature nature, boolean checkSystemManager, boolean dontSearchInit) { + return super.getModule(name, nature, dontSearchInit); + } + + + public String resolveModule(String full, boolean checkSystemManager) { + return super.resolveModule(full); + } + + public List<String> getCompletePythonPath() { + return new ArrayList<String>(super.getPythonPath()); + } + } --- NEW FILE: SystemASTManager.java --- package org.python.pydev.editor.codecompletion.revisited; import java.io.File; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.IPythonNature; import org.python.pydev.ui.interpreters.IInterpreterManager; public class SystemASTManager extends AbstractASTManager{ private IInterpreterManager manager; public SystemASTManager(IInterpreterManager manager, IPythonNature nature) { this.manager = manager; this.modulesManager = this.manager.getDefaultInterpreterInfo(new NullProgressMonitor()).modulesManager; setNature(nature); } public void changePythonPath(String pythonpath, IProject project, IProgressMonitor monitor) { throw new RuntimeException("Not implemented"); } public void setProject(IProject project, boolean restoreDeltas) { throw new RuntimeException("Not implemented"); } public void rebuildModule(File file, IDocument doc, IProject project, IProgressMonitor monitor, IPythonNature nature) { throw new RuntimeException("Not implemented"); } public void removeModule(File file, IProject project, IProgressMonitor monitor) { throw new RuntimeException("Not implemented"); } public void validatePathInfo(String pythonpath, IProject project, IProgressMonitor monitor) { throw new RuntimeException("Not implemented"); } } Index: ModulesManager.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited/ModulesManager.java,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** ModulesManager.java 15 Jan 2006 00:25:10 -0000 1.31 --- ModulesManager.java 16 Jan 2006 17:17:49 -0000 1.32 *************** *** 22,28 **** --- 22,32 ---- import org.eclipse.core.resources.IProject; + import org.eclipse.core.resources.IResource; + import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; + import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.IModule; + import org.python.pydev.core.IModulesManager; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.ModulesKey; *************** *** 33,41 **** import org.python.pydev.editor.codecompletion.revisited.modules.EmptyModule; import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule; /** * @author Fabio Zadrozny */ ! public abstract class ModulesManager implements Serializable { /** --- 37,46 ---- import org.python.pydev.editor.codecompletion.revisited.modules.EmptyModule; import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule; + import org.python.pydev.plugin.PydevPlugin; /** * @author Fabio Zadrozny */ ! public abstract class ModulesManager implements IModulesManager, Serializable { /** *************** *** 45,48 **** --- 50,59 ---- */ protected transient Map<ModulesKey, AbstractModule> modules = new HashMap<ModulesKey, AbstractModule>(); + + /** + * This is the set of files that was found just right after unpickle (it should not be changed after that, + * and serves only as a reference cache). + */ + protected transient Set<File> files = new HashSet<File>(); /** *************** *** 51,55 **** protected PythonPathHelper pythonPathHelper = new PythonPathHelper(); ! private static final long serialVersionUID = 1L; /** --- 62,66 ---- protected PythonPathHelper pythonPathHelper = new PythonPathHelper(); ! private static final long serialVersionUID = 2L; /** *************** *** 58,61 **** --- 69,73 ---- private void readObject(ObjectInputStream aStream) throws IOException, ClassNotFoundException { modules = new HashMap<ModulesKey, AbstractModule>(); + files = new HashSet<File>(); aStream.defaultReadObject(); Set set = (Set) aStream.readObject(); *************** *** 64,67 **** --- 76,82 ---- //restore with empty modules. modules.put(key, AbstractModule.createEmptyModule(key.name, key.file)); + if(key.file != null){ + files.add(key.file); + } } } *************** *** 73,77 **** aStream.defaultWriteObject(); //write only the keys ! aStream.writeObject(new HashSet(this.modules.keySet())); } --- 88,92 ---- aStream.defaultWriteObject(); //write only the keys ! aStream.writeObject(new HashSet<ModulesKey>(this.modules.keySet())); } *************** *** 95,115 **** public abstract String[] getBuiltins(); ! /** ! * ! * @param pythonpath ! * @param project may be null if there is no associated project. ! * @param monitor ! */ ! public void changePythonPath(String pythonpath, final IProject project, IProgressMonitor monitor) { ! List pythonpathList = pythonPathHelper.setPythonPath(pythonpath); ! ! Map<ModulesKey, AbstractModule> mods = new HashMap<ModulesKey, AbstractModule>(); ! ! List completions = new ArrayList(); ! List<String> fromJar = new ArrayList<String>(); ! int total = 0; ! //first thing: get all files available from the python path and sum them up. for (Iterator iter = pythonpathList.iterator(); iter.hasNext() && monitor.isCanceled() == false;) { String element = (String) iter.next(); --- 110,158 ---- public abstract String[] getBuiltins(); ! ! public void validatePathInfo(String pythonpath, final IProject project, IProgressMonitor monitor) { ! //it is all comented because it could take quite some time to do that validation, so, we have to check ! //for a better way to do it... ! ! // List<String> lPythonpath = new ArrayList<String>(); ! // List<File> completions = new ArrayList<File>(); ! // List<String> fromJar = new ArrayList<String>(); ! // ! // int total = listFilesForCompletion(monitor, lPythonpath, completions, fromJar); ! // ! // this.pythonPathHelper.getPythonPathFromStr(pythonpath, lPythonpath); ! // if(!this.pythonPathHelper.pythonpath.equals(lPythonpath)){ ! // // the pythonpath is not the same ! // lPythonpath = pythonPathHelper.setPythonPath(pythonpath); ! // PydevPlugin.log(IStatus.INFO, "The pythonpath was not valid and will be restored.", null, true); ! // changePythonPath(pythonpath, project, monitor, lPythonpath, completions, fromJar, total); ! // ! // }else if(!validateFiles(completions)){ ! // //the files are not valid ! // PydevPlugin.log(IStatus.INFO, "The pythonpath files were not valid and will be restored.", null, true); ! // changePythonPath(pythonpath, project, monitor, lPythonpath, completions, fromJar, total); ! // } ! } ! private boolean validateFiles(List<File> completions) { ! for (File f : completions) { ! if(!files.contains(f)){ ! return false; ! } ! } ! return true; ! } ! /** ! * ! * @param monitor this is the monitor ! * @param pythonpathList this is the pythonpath ! * @param completions OUT - the files that were gotten as valid python modules ! * @param fromJar OUT - the names of the modules that were found inside a jar ! * @return the total number of modules found (that's completions + fromJar) ! */ ! private int listFilesForCompletion(IProgressMonitor monitor, List<String> pythonpathList, List<File> completions, List<String> fromJar) { ! int total = 0; ! //first thing: get all files available from the python path and sum them up. for (Iterator iter = pythonpathList.iterator(); iter.hasNext() && monitor.isCanceled() == false;) { String element = (String) iter.next(); *************** *** 117,121 **** //the slow part is getting the files... not much we can do (I think). File root = new File(element); ! List[] below = pythonPathHelper.getModulesBelow(root, monitor); if(below != null){ completions.addAll(below[0]); --- 160,164 ---- //the slow part is getting the files... not much we can do (I think). File root = new File(element); ! List<File>[] below = pythonPathHelper.getModulesBelow(root, monitor); if(below != null){ completions.addAll(below[0]); *************** *** 130,134 **** --- 173,195 ---- } } + return total; + } + + public void changePythonPath(String pythonpath, final IProject project, IProgressMonitor monitor) { + List<String> pythonpathList = pythonPathHelper.setPythonPath(pythonpath); + List<File> completions = new ArrayList<File>(); + List<String> fromJar = new ArrayList<String>(); + int total = listFilesForCompletion(monitor, pythonpathList, completions, fromJar); + changePythonPath(pythonpath, project, monitor, pythonpathList, completions, fromJar, total); + } + + /** + * @param pythonpath string with the new pythonpath (separated by |) + * @param project may be null if there is no associated project. + */ + private void changePythonPath(String pythonpath, final IProject project, IProgressMonitor monitor, + List<String> pythonpathList, List<File> completions, List<String> fromJar, int total) { + Map<ModulesKey, AbstractModule> mods = new HashMap<ModulesKey, AbstractModule>(); int j = 0; *************** *** 189,192 **** --- 250,254 ---- } + /** * @see org.python.pydev.core.ICodeCompletionASTManager#rebuildModule(java.io.File, org.eclipse.jface.text.IDocument, *************** *** 430,434 **** } ! /** * @param full * @return --- 492,525 ---- } ! ! /** ! * @see org.python.pydev.core.IProjectModulesManager#isInPythonPath(org.eclipse.core.resources.IResource, org.eclipse.core.resources.IProject) ! */ ! public boolean isInPythonPath(IResource member, IProject container) { ! return resolveModule(member, container) != null; ! } ! ! ! /** ! * @see org.python.pydev.core.IProjectModulesManager#resolveModule(org.eclipse.core.resources.IResource, org.eclipse.core.resources.IProject) ! */ ! public String resolveModule(IResource member, IProject container) { ! IPath location = PydevPlugin.getLocation(member.getFullPath(), container); ! if(location == null){ ! //not in workspace?... maybe it was removed, so, do nothing, but let the user know about it ! PydevPlugin.log(getResolveModuleErr(member)); ! return null; ! }else{ ! File inOs = new File(location.toOSString()); ! return resolveModule(REF.getFileAbsolutePath(inOs)); ! } ! } ! ! protected String getResolveModuleErr(IResource member) { ! return "Unable to find the path "+member+" in the project were it\n" + ! "is added as a source folder for pydev."+this.getClass(); ! } ! ! /** * @param full * @return *************** *** 438,443 **** } ! public List getPythonPath(){ ! return new ArrayList(pythonPathHelper.pythonpath); } } --- 529,534 ---- } ! public List<String> getPythonPath(){ ! return new ArrayList<String>(pythonPathHelper.pythonpath); } } --- NEW FILE: AbstractASTManager.java --- package org.python.pydev.editor.codecompletion.revisited; import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import org.python.parser.SimpleNode; import org.python.parser.ast.FunctionDef; import org.python.pydev.core.FindInfo; import org.python.pydev.core.FullRepIterable; import org.python.pydev.core.ICodeCompletionASTManager; import org.python.pydev.core.ICompletionRequest; import org.python.pydev.core.ICompletionState; import org.python.pydev.core.IModule; import org.python.pydev.core.IModulesManager; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IToken; import org.python.pydev.core.ModulesKey; import org.python.pydev.core.REF; import org.python.pydev.core.Tuple; import org.python.pydev.editor.actions.PyAction; import org.python.pydev.editor.codecompletion.CompletionRequest; import org.python.pydev.editor.codecompletion.PyCodeCompletion; import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule; import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule; import org.python.pydev.editor.codecompletion.revisited.visitors.Definition; import org.python.pydev.parser.PyParser; import org.python.pydev.parser.visitors.NodeUtils; public abstract class AbstractASTManager implements ICodeCompletionASTManager, Serializable { public AbstractASTManager(){ } /** * This is the guy that will handle project things for us */ public IModulesManager modulesManager; public IModulesManager getModulesManager(){ return modulesManager; } /** * Set the nature this ast manager works with (if no project is available and a nature is). */ public void setNature(IPythonNature nature){ getModulesManager().setPythonNature(nature); } public IPythonNature getNature() { return getModulesManager().getNature(); } public abstract void changePythonPath(String pythonpath, IProject project, IProgressMonitor monitor) ; public abstract void setProject(IProject project, boolean restoreDeltas) ; public abstract void rebuildModule(File file, IDocument doc, IProject project, IProgressMonitor monitor, IPythonNature nature) ; public abstract void removeModule(File file, IProject project, IProgressMonitor monitor) ; public abstract void validatePathInfo(String pythonpath, IProject project, IProgressMonitor monitor) ; /** * Returns the imports that start with a given string. The comparisson is not case dependent. Passes all the modules in the cache. * * @param original is the name of the import module eg. 'from toimport import ' would mean that the original is 'toimport' * or something like 'foo.bar' or an empty string (if only 'import'). * @return a Set with the imports as tuples with the name, the docstring. */ public IToken[] getCompletionsForImport(final String original, ICompletionRequest r) { CompletionRequest request = (CompletionRequest) r; IPythonNature nature = request.nature; String relative = null; if(request.editorFile != null){ String moduleName = nature.getAstManager().getModulesManager().resolveModule(REF.getFileAbsolutePath(request.editorFile)); if(moduleName != null){ String tail = FullRepIterable.headAndTail(moduleName)[0]; if(original.length() > 0){ relative = tail+"."+original; }else{ relative = tail; } } } String absoluteModule = original; if (absoluteModule.endsWith(".")) { absoluteModule = absoluteModule.substring(0, absoluteModule.length() - 1); } absoluteModule = absoluteModule.toLowerCase().trim(); //set to hold the completion (no duplicates allowed). Set<IToken> set = new HashSet<IToken>(); //first we get the imports... that complete for the token. getAbsoluteImportTokens(absoluteModule, set, PyCodeCompletion.TYPE_IMPORT, false); //Now, if we have an initial module, we have to get the completions //for it. getTokensForModule(original, nature, absoluteModule, set); if(relative != null && relative.equals(absoluteModule) == false){ getAbsoluteImportTokens(relative, set, PyCodeCompletion.TYPE_RELATIVE_IMPORT, false); getTokensForModule(relative, nature, relative, set); } return (IToken[]) set.toArray(new IToken[0]); } /** * @param moduleToGetTokensFrom the string that represents the token from where we are getting the imports * @param set the set where the tokens should be added */ protected void getAbsoluteImportTokens(String moduleToGetTokensFrom, Set<IToken> set, int type, boolean onlyFilesOnSameLevel) { for (Iterator iter = Arrays.asList(modulesManager.getAllModules()).iterator(); iter.hasNext();) { ModulesKey key = (ModulesKey) iter.next(); String element = key.name; if (element.startsWith(moduleToGetTokensFrom)) { if(onlyFilesOnSameLevel && key.file != null && key.file.isDirectory()){ continue; // we only want those that are in the same directory, and not in other directories... } element = element.substring(moduleToGetTokensFrom.length()); //we just want those that are direct //this means that if we had initially element = testlib.unittest.anothertest //and element became later = .unittest.anothertest, it will be ignored (we //should only analyze it if it was something as testlib.unittest and became .unittest //we only check this if we only want file modules (in if(onlyFilesOnSameLevel && PyAction.countChars('.', element) > 1){ continue; } boolean goForIt = false; //if initial is not empty only get those that start with a dot (submodules, not //modules that start with the same name). //e.g. we want xml.dom //and not xmlrpclib //if we have xml token (not using the qualifier here) if (moduleToGetTokensFrom.length() != 0) { if (element.startsWith(".")) { element = element.substring(1); goForIt = true; } } else { goForIt = true; } if (element.length() > 0 && goForIt) { String[] splitted = element.split("\\."); if (splitted.length > 0) { //this is the completion set.add(new ConcreteToken(splitted[0], "", "", moduleToGetTokensFrom, type)); } } } } } /** * @param original this is the initial module where the completion should happen (may have class in it too) * @param moduleToGetTokensFrom * @param set set where the tokens should be added */ protected void getTokensForModule(String original, IPythonNature nature, String moduleToGetTokensFrom, Set<IToken> set) { if (moduleToGetTokensFrom.length() > 0) { if (original.endsWith(".")) { original = original.substring(0, original.length() - 1); } Tuple<IModule, String> modTok = findModuleFromPath(original, nature, false, null); //the current module name is not used as it is not relative IModule m = modTok.o1; String tok = modTok.o2; if(m == null){ //we were unable to find it with the given path, so, there's nothing else to do here... return; } IToken[] globalTokens; if(tok != null && tok.length() > 0){ CompletionState state2 = new CompletionState(-1,-1,tok,nature); state2.builtinsGotten = true; //we don't want to get builtins here globalTokens = m.getGlobalTokens(state2, this); }else{ CompletionState state2 = new CompletionState(-1,-1,"",nature); state2.builtinsGotten = true; //we don't want to get builtins here globalTokens = getCompletionsForModule(m, state2); } for (int i = 0; i < globalTokens.length; i++) { IToken element = globalTokens[i]; //this is the completion set.add(element); } } } /** * @param file * @param doc * @param state * @return */ public static IModule createModule(File file, IDocument doc, ICompletionState state, ICodeCompletionASTManager manager) { IPythonNature pythonNature = state.getNature(); int line = state.getLine(); IModulesManager projModulesManager = manager.getModulesManager(); return AbstractModule.createModuleFromDoc(file, doc, pythonNature, line, projModulesManager); } /** * @see org.python.pydev.core.ICodeCompletionASTManager#getCompletionsForToken(java.io.File, org.eclipse.jface.text.IDocument, org.python.pydev.editor.codecompletion.revisited.CompletionState) */ public IToken[] getCompletionsForToken(File file, IDocument doc, ICompletionState state) { IModule module = createModule(file, doc, state, this); return getCompletionsForModule(module, state); } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getCompletionsForToken(org.eclipse.jface.text.IDocument, org.python.pydev.editor.codecompletion.revisited.CompletionState) */ public IToken[] getCompletionsForToken(IDocument doc, ICompletionState state) { IToken[] completionsForModule; try { Object[] obj = PyParser.reparseDocument(new PyParser.ParserInfo(doc, true, state.getNature(), state.getLine())); SimpleNode n = (SimpleNode) obj[0]; IModule module = AbstractModule.createModule(n); completionsForModule = getCompletionsForModule(module, state); } catch (CompletionRecursionException e) { completionsForModule = new IToken[]{ new ConcreteToken(e.getMessage(), e.getMessage(), "","", PyCodeCompletion.TYPE_UNKNOWN)}; } return completionsForModule; } /** * This method returns the module that corresponds to the path passed as a parameter. * * @param name * @return the module represented by this name */ public IModule getModule(String name, IPythonNature nature, boolean dontSearchInit) { return modulesManager.getModule(name, nature, dontSearchInit); } /** * Identifies the token passed and if it maps to a builtin not 'easily recognizable', as * a string or list, we return it. * * @param state * @return */ protected IToken[] getBuiltinsCompletions(ICompletionState state){ ICompletionState state2 = state.getCopy(); //check for the builtin types. state2.setActivationToken (NodeUtils.getBuiltinType(state.getActivationToken())); if(state2.getActivationToken() != null){ IModule m = getModule("__builtin__", state.getNature(), false); return m.getGlobalTokens(state2, this); } return null; } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getCompletionsForModule(org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule, org.python.pydev.editor.codecompletion.revisited.CompletionState) */ public IToken[] getCompletionsForModule(IModule module, ICompletionState state) { return getCompletionsForModule(module, state, true); } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getCompletionsForModule(org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule, org.python.pydev.editor.codecompletion.revisited.CompletionState, boolean) */ public IToken[] getCompletionsForModule(IModule module, ICompletionState state, boolean searchSameLevelMods) { ArrayList<IToken> importedModules = new ArrayList<IToken>(); if(state.getLocalImportsGotten() == false){ //in the first analyzed module, we have to get the local imports too. state.setLocalImportsGotten (true); if(module != null){ importedModules.addAll(module.getLocalImportedModules(state.getLine(), state.getCol())); } } IToken[] builtinsCompletions = getBuiltinsCompletions(state); if(builtinsCompletions != null){ return builtinsCompletions; } if (module != null) { //get the tokens (global, imported and wild imported) IToken[] globalTokens = module.getGlobalTokens(); importedModules.addAll(Arrays.asList(module.getTokenImportedModules())); IToken[] wildImportedModules = module.getWildImportedModules(); //now, lets check if this is actually a module that is an __init__ (if so, we have to get all //the other .py files as modules that are in the same level as the __init__) Set<IToken> initial = new HashSet<IToken>(); if(searchSameLevelMods){ String modName = module.getName(); if(modName != null && modName.endsWith(".__init__")){ HashSet<IToken> gotten = new HashSet<IToken>(); getAbsoluteImportTokens(FullRepIterable.getParentModule(modName), gotten, PyCodeCompletion.TYPE_IMPORT, true); for (IToken token : gotten) { if(token.getRepresentation().equals("__init__") == false){ initial.add(token); } } } } if (state.getActivationToken().length() == 0) { List<IToken> completions = getGlobalCompletions(globalTokens, importedModules.toArray(new IToken[0]), wildImportedModules, state, module); //now find the locals for the module if (state.getLine() >= 0){ IToken[] localTokens = module.getLocalTokens(state.getLine(), state.getCol()); for (int i = 0; i < localTokens.length; i++) { completions.add(localTokens[i]); } } completions.addAll(initial); //just addd all that are in the same level if it was an __init__ return completions.toArray(new IToken[0]); }else{ //ok, we have a token, find it and get its completions. //first check if the token is a module... if it is, get the completions for that module. IToken[] t = findTokensOnImportedMods(importedModules.toArray(new IToken[0]), state, module); if(t != null && t.length > 0){ return t; } //if it is an __init__, modules on the same level are treated as local tokens if(searchSameLevelMods){ t = searchOnSameLevelMods(initial, state); if(t != null && t.length > 0){ return t; } } //wild imports: recursively go and get those completions and see if any matches it. for (int i = 0; i < wildImportedModules.length; i++) { IToken name = wildImportedModules[i]; IModule mod = getModule(name.getAsRelativeImport(module.getName()), state.getNature(), false); //relative (for wild imports this is ok... only a module can be used in wild imports) if (mod == null) { mod = getModule(name.getOriginalRep(), state.getNature(), false); //absolute } if (mod != null) { IToken[] completionsForModule = getCompletionsForModule(mod, state); if(completionsForModule.length > 0) return completionsForModule; } else { //"Module not found:" + name.getRepresentation() } } //it was not a module (would have returned already), so, try to get the completions for a global token defined. IToken[] tokens = null; tokens = module.getGlobalTokens(state, this); if (tokens.length > 0){ return tokens; } //If it was still not found, go to builtins. IModule builtinsMod = getModule("__builtin__", state.getNature(), false); if(builtinsMod != null && builtinsMod != module){ tokens = getCompletionsForModule( builtinsMod, state); if (tokens.length > 0){ if (tokens[0].getRepresentation().equals("ERROR:") == false){ return tokens; } } } return getAssignCompletions( module, state); } }else{ System.err.println("Module passed in is null!!"); } return new IToken[0]; } /** * Attempt to search on modules on the same level as this one (this will only happen if we are in an __init__ * module (otherwise, the initial set will be empty) * * @param initial this is the set of tokens generated from modules in the same level * @param state the current state of the completion * * @return a list of tokens found. */ protected IToken[] searchOnSameLevelMods(Set<IToken> initial, ICompletionState state) { for (IToken token : initial) { //ok, maybe it was from the set that is in the same level as this one (this will only happen if we are on an __init__ module) String rep = token.getRepresentation(); if(state.getActivationToken().startsWith(rep)){ String absoluteImport = token.getAsAbsoluteImport(); IModule sameLevelMod = getModule(absoluteImport, state.getNature(), true); if(sameLevelMod == null){ return null; } String qualifier = state.getActivationToken().substring(rep.length()); ICompletionState copy = state.getCopy(); copy.setBuiltinsGotten (true); //we don't want builtins... if(state.getActivationToken().equals(rep)){ copy.setActivationToken (""); return getCompletionsForModule(sameLevelMod, copy); } else if(qualifier.startsWith(".")){ copy.setActivationToken (qualifier.substring(1)); return getCompletionsForModule(sameLevelMod, copy); } } } return null; } /** * If we got here, either there really is no definition from the token * or it is not looking for a definition. This means that probably * it is something like. * * It also can happen in many scopes, so, first we have to check the current * scope and then pass to higher scopes * * e.g. foo = Foo() * foo. | Ctrl+Space * * so, first thing is discovering in which scope we are (Storing previous scopes so * that we can search in other scopes as well). * * * @param activationToken * @param qualifier * @param module * @param line * @param col * @return */ public IToken[] getAssignCompletions( IModule module, ICompletionState state) { if (module instanceof SourceModule) { SourceModule s = (SourceModule) module; try { Definition[] defs = s.findDefinition(state.getActivationToken(), state.getLine(), state.getCol(), state.getNature(), new ArrayList<FindInfo>()); for (int i = 0; i < defs.length; i++) { if(!(defs[0].ast instanceof FunctionDef)){ //we might want to extend that later to check the return of some function... ICompletionState copy = state.getCopy(); copy.setActivationToken (defs[i].value); copy.setLine(defs[i].line); copy.setCol(defs[i].col); module = defs[i].module; state.checkDefinitionMemory(module, defs[i]); IToken[] tks = getCompletionsForModule(module, copy); if(tks.length > 0) return tks; } } } catch (CompletionRecursionException e) { //thats ok } catch (Exception e) { throw new RuntimeException(e); } catch (Throwable t) { throw new RuntimeException("A throwable exception has been detected "+t.getClass()); } } return new IToken[0]; } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getGlobalCompletions */ public List getGlobalCompletions(IToken[] globalTokens, IToken[] importedModules, IToken[] wildImportedModules, ICompletionState state, IModule current) { List<IToken> completions = new ArrayList<IToken>(); //in completion with nothing, just go for what is imported and global tokens. for (int i = 0; i < globalTokens.length; i++) { completions.add(globalTokens[i]); } //now go for the token imports for (int i = 0; i < importedModules.length; i++) { completions.add(importedModules[i]); } //wild imports: recursively go and get those completions. for (int i = 0; i < wildImportedModules.length; i++) { IToken name = wildImportedModules[i]; getCompletionsForWildImport(state, current, completions, name); } if(!state.getBuiltinsGotten()){ state.setBuiltinsGotten (true) ; //last thing: get completions from module __builtin__ getBuiltinCompletions(state, completions); } return completions; } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getBuiltinCompletions */ public List getBuiltinCompletions(ICompletionState state, List completions) { IModule builtMod = getModule("__builtin__", state.getNature(), false); if(builtMod != null){ IToken[] toks = builtMod.getGlobalTokens(); for (int i = 0; i < toks.length; i++) { completions.add(toks[i]); } } return completions; } /** * @see org.python.pydev.editor.codecompletion.revisited.ICodeCompletionASTManage#getCompletionsForWildImport */ public List getCompletionsForWildImport(ICompletionState state, IModule current, List completions, IToken name) { try { //this one is an exception... even though we are getting the name as a relative import, we say it //is not because we want to get the module considering __init__ IModule mod = null; if(current != null){ //we cannot get the relative path if we don't have a current module mod = getModule(name.getAsRelativeImport(current.getName()), state.getNature(), false); } if (mod == null) { mod = getModule(name.getOriginalRep(), state.getNature(), false); //absolute import } if (mod != null) { state.checkWildImportInMemory(current, mod); IToken[] completionsForModule = getCompletionsForModule(mod, state); for (int j = 0; j < completionsForModule.length; j++) { completions.add(completionsForModule[j]); } } else { //"Module not found:" + name.getRepresentation() } } catch (CompletionRecursionException e) { //probably found a recursion... let's return the tokens we have so far } return completions; } public IToken[] findTokensOnImportedMods( IToken[] importedModules, ICompletionState state, IModule current) { Tuple<IModule, String> o = findOnImportedMods(importedModules, state.getNature(), state.getActivationToken(), current.getName()); if(o == null) return null; IModule mod = o.o1; String tok = o.o2; if(tok.length() == 0){ //the activation token corresponds to an imported module. We have to get its global tokens and return them. ICompletionState copy = state.getCopy(); copy.setActivationToken(""); copy.setBuiltinsGotten(true); //we don't want builtins... return getCompletionsForModule(mod, copy); }else if (mod != null){ ICompletionState copy = state.getCopy(); copy.setActivationToken(tok); copy.setCol(-1); copy.setLine(-1); return getCompletionsForModule(mod, copy); } return null; } /** * @param activationToken * @param importedModules * @param module * @return tuple with: * 0: mod * 1: tok */ public Tuple<IModule, String> findOnImportedMods( IPythonNature nature, String activationToken, IModule current) { IToken[] importedModules = current.getTokenImportedModules(); return findOnImportedMods(importedModules, nature, activationToken, current.getName()); } /** * This function tries to find some activation token defined in some imported module. * @return tuple with: the module and the token that should be used from it. * * @param this is the activation token we have. It may be a single token or some dotted name. * * If it is a dotted name, such as testcase.TestCase, we need to match against some import * represented as testcase or testcase.TestCase. * * If a testcase.TestCase matches against some import named testcase, the import is returned and * the TestCase is put as the module * * 0: mod * 1: tok */ public Tuple<IModule, String> findOnImportedMods( IToken[] importedModules, IPythonNature nature, String activationToken, String currentModuleName) { for (IToken importedModule : importedModules) { FullRepIterable iterable = new FullRepIterable(activationToken, true); for(String tok : iterable){ final String modRep = importedModule.getRepresentation(); //this is its 'real' representation (alias) on the file (if it is from xxx import a as yyy, it is yyy) if(modRep.equals(tok)){ return findOnImportedMods(importedModule, tok, nature, activationToken, currentModuleName); } } } return null; } /** * Checks if some module can be resolved and returns the module it is resolved to (and to which token). */ protected Tuple<IModule, String> findOnImportedMods(IToken importedModule, String tok, IPythonNature nature, String activationToken, String currentModuleName) { Tuple<IModule, String> modTok = null; IModule mod = null; //check as relative with complete rep String asRelativeImport = importedModule.getAsRelativeImport(currentModuleName); modTok = findModuleFromPath(asRelativeImport, nature, true, currentModuleName); mod = modTok.o1; if(checkValidity(currentModuleName, mod)){ Tuple<IModule, String> ret = fixTok(modTok, tok, activationToken); return ret; } //check if the import actually represents some token in an __init__ file String originalWithoutRep = importedModule.getOriginalWithoutRep(); if(!originalWithoutRep.endsWith("__init__")){ originalWithoutRep = originalWithoutRep + ".__init__"; } modTok = findModuleFromPath(originalWithoutRep, nature, true, null); mod = modTok.o1; if(modTok.o2.endsWith("__init__") == false && checkValidity(currentModuleName, mod)){ if(mod.isInGlobalTokens(importedModule.getRepresentation(), nature, false)){ //then this is the token we're looking for (otherwise, it might be a module). Tuple<IModule, String> ret = fixTok(modTok, tok, activationToken); if(ret.o2.length() == 0){ ret.o2 = importedModule.getRepresentation(); }else{ ret.o2 = importedModule.getRepresentation()+"."+ret.o2; } return ret; } } //the most 'simple' case: check as absolute with original rep modTok = findModuleFromPath(importedModule.getOriginalRep(), nature, false, null); mod = modTok.o1; if(checkValidity(currentModuleName, mod)){ Tuple<IModule, String> ret = fixTok(modTok, tok, activationToken); return ret; } //ok, one last shot, to see a relative looking in folders __init__ modTok = findModuleFromPath(asRelativeImport, nature, false, null); mod = modTok.o1; if(checkValidity(currentModuleName, mod)){ Tuple<IModule, String> ret = fixTok(modTok, tok, activationToken); //now let's see if what we did when we found it as a relative import is correct: //if we didn't find it in an __init__ module, all should be ok if(!mod.getName().endsWith("__init__")){ return ret; } //otherwise, we have to be more cautious... //if the activation token is empty, then it is the module we were looking for //if it is not the initial token we were looking for, it is correct //if it is in the global tokens of the found module it is correct //if none of this situations was found, we probably just found the same token we had when we started (unless I'm mistaken...) else if(activationToken.length() == 0 || ret.o2.equals(activationToken) == false || mod.isInGlobalTokens(activationToken, nature, false)){ return ret; } } return null; } protected boolean checkValidity(String currentModuleName, IModule mod) { if(mod == null){ return false; } String modName = mod.getName(); if(modName == null){ return true; } //still in the same module if(modName.equals(currentModuleName)){ return false; } // if(currentModuleName != null && modName.endsWith(".__init__")){ // //we have to check it without the __init__ // String withoutLastPart = FullRepIterable.getWithoutLastPart(modName); // if(withoutLastPart.equals(currentModuleName)){ // return false; // } // } return true; } /** * Fixes the token if we found a module that was just a substring from the initial activation token. * * This means that if we had testcase.TestCase and found it as TestCase, the token is added with TestCase */ protected Tuple<IModule, String> fixTok(Tuple<IModule, String> modTok, String tok, String activationToken) { if(activationToken.length() > tok.length() && activationToken.startsWith(tok)){ String toAdd = activationToken.substring(tok.length() + 1); if(modTok.o2.length() == 0){ modTok.o2 = toAdd; }else{ modTok.o2 += "."+toAdd; } } return modTok; } /** * This function receives a path (rep) and extracts a module from that path. * First it tries with the full path, and them removes a part of the final of * that path until it finds the module or the path is empty. * * @param rep * @param currentModuleName this is the module name (used to check validity for relative imports) -- not used if dontSearchInit is false * @return tuple with found module and the String removed from the path in * order to find the module. */ protected Tuple<IModule, String> findModuleFromPath(String rep, IPythonNature nature, boolean dontSearchInit, String currentModuleName){ String tok = ""; IModule mod = getModule(rep, nature, dontSearchInit); String mRep = rep; int index; while(mod == null && (index = mRep.lastIndexOf('.')) != -1){ tok = mRep.substring(index+1) + "."+tok; mRep = mRep.substring(0,index); mod = getModule(mRep, nature, dontSearchInit); } if (tok.endsWith(".")){ tok = tok.substring(0, tok.length()-1); //remove last point if found. } if(dontSearchInit && currentModuleName != null && mod != null){ String parentModule = FullRepIterable.getParentModule(currentModuleName); //if we are looking for some relative import token, it can only match if the name found is not less than the parent //of the current module because of the way in that relative imports are meant to be written. //if it equal, it should not match either, as it was found as the parent module... this can not happen because it must find //it with __init__ if it was the parent module if (mod.getName().length() <= parentModule.length()){ return new Tuple<IModule, String>(null, null); } } return new Tuple<IModule, String>((AbstractModule)mod, tok); } } Index: PythonPathHelper.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited/PythonPathHelper.java,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** PythonPathHelper.java 2 Jan 2006 19:10:26 -0000 1.31 --- PythonPathHelper.java 16 Jan 2006 17:17:49 -0000 1.32 *************** *** 75,79 **** * @return the files in position 0 and folders in position 1. */ ! public List[] getModulesBelow(File root, IProgressMonitor monitor){ if(!root.exists()){ return null; --- 75,79 ---- * @return the files in position 0 and folders in position 1. */ ! public List<File>[] getModulesBelow(File root, IProgressMonitor monitor){ if(!root.exists()){ return null; *************** *** 376,380 **** public List<String> setPythonPath(String string) { pythonpath.clear(); ! String[] strings = string.split("\\|"); for (int i = 0; i < strings.length; i++) { String defaultPathStr = getDefaultPathStr(strings[i]); --- 376,389 ---- public List<String> setPythonPath(String string) { pythonpath.clear(); ! getPythonPathFromStr(string, pythonpath); ! return new ArrayList<String>(pythonpath); ! } ! ! /** ! * @param string this is the string that has the pythonpath (separated by |) ! * @param lPath OUT: this list is filled with the pythonpath. ! */ ! public void getPythonPathFromStr(String string, List<String> lPath) { ! String[] strings = string.split("\\|"); for (int i = 0; i < strings.length; i++) { String defaultPathStr = getDefaultPathStr(strings[i]); *************** *** 384,393 **** //we have to get it with the appropriate cases and in a canonical form String path = REF.getFileAbsolutePath(file); ! pythonpath.add(path); } } } ! return new ArrayList<String>(pythonpath); ! } public static String getPythonFileEncoding(IDocument doc) { --- 393,401 ---- //we have to get it with the appropriate cases and in a canonical form String path = REF.getFileAbsolutePath(file); ! lPath.add(path); } } } ! } public static String getPythonFileEncoding(IDocument doc) { Index: ASTManager.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev/src/org/python/pydev/editor/codecompletion/revisited/ASTManager.java,v retrieving revision 1.89 retrieving revision 1.90 diff -C2 -d -r1.89 -r1.90 *** ASTManager.java 15 Jan 2006 00:25:10 -0000 1.89 --- ASTManager.java 16 Jan 2006 17:17:49 -0000 1.90 *************** *** 11,47 **** import java.io.ObjectInputStream; import java.io.Serializable; - import java.util.ArrayList; - import java.util.Arrays; - import java.util.HashSet; - import java.util.Iterator; - import java.util.List; - import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; - import org.python.parser.SimpleNode; - import org.python.parser.ast.FunctionDef; - import org.python.pydev.core.FindInfo; - import org.python.pydev.core.FullRepIterable; import org.python.pydev.core.ICodeCompletionASTManager; ! import org.python.pydev.core.ICompletionRequest; ! import org.python.pydev.core.ICompletionState; ! import org.python.pydev.core.IModule; import org.python.pydev.core.IProjectModulesManager; import org.python.pydev.core.IPythonNature; - import org.python.pydev.core.IToken; - import org.python.pydev.core.ModulesKey; - import org.python.pydev.core.REF; - import org.python.pydev.core.Tuple; - import org.python.pydev.editor.actions.PyAction; - import org.python.pydev.editor.codecompletion.CompletionRequest; - import org.python.pydev.editor.codecompletion.PyCodeCompletion; - import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule; - import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule; - import org.python.pydev.editor.codecompletion.revisited.visitors.Definition; - import org.python.pydev.parser.PyParser; - import org.python.pydev.parser.visitors.NodeUtils; - import org.python.pydev.plugin.nature.PythonNature; --- 11,22 ---- import java.io.ObjectInputStream; import java.io.Serializable; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import org.python.pydev.core.ICodeCompletionASTManager; ! import org.python.pydev.core.IModulesManager; import org.python.pydev.core.IProjectModulesManager; import org.python.pydev.core.IPythonNature; *************** *** 56,70 **** * @author Fabio Zadrozny */ ! public class ASTManager implements ICodeCompletionASTManager, Serializable{ ! private static final long serialVersionUID = 1L; ! ! /** ! * This is the guy that will handle project things for us ! */ ! public ProjectModulesManager projectModulesManager = new ProjectModulesManager(); ! public ProjectModulesManager getProjectModulesManager(){ ! return projectModulesManager; ! } /** --- 31,37 ---- * @author Fabio Zadrozny */ ! public class ASTManager extends AbstractASTManager implements ICodeCompletionASTManager, Serializable{ ! protected static final long serialVersionUID = 1L; /** *************** *** 72,88 **** */ public void setProject(IProject project, boolean restoreDeltas){ ! projectModulesManager.setProject(project, restoreDeltas); } ! /** ! * Set the nature this ast manager works with (if no project is available and a nature is). ! */ ! public void setNature(IPythonNature nature){ ! projectModulesManager.setPythonNature(nature); ! } ! ! public IPythonNature getNature() { ! return projectModulesManager.getNature(); } //----------------------- AUXILIARIES --- 39,56 ---- */ public void setProject(IProject project, boolean restoreDeltas){ ! getProjectModulesManager().setProject(project, restoreDeltas); } ! private IProjectModulesManager getProjectModulesManager() { ! if(modulesManager == null){ ! modulesManager = new ProjectModulesManager(); ! } ! return (IProjectModulesManager) modulesManager; ! } ! ! public IModulesManager createModulesManager(){ ! return new ProjectModulesManager(); } + //----------------------- AUXILIARIES *************** *** 90,876 **** public void changePythonPath(String pythonpath, final IProject project, IProgressMonitor monitor) { ! projectModulesManager.changePythonPath(pythonpath, project, monitor); } public void rebuildModule(File f, IDocument doc, final IProject project, IProgressMonitor monitor, IPythonNature nature) { ! projectModulesManager.rebuildModule(f, doc, project, monitor, nature); } public void removeModule(File file, IProject project, IProgressMonitor monitor) { ! projectModulesManager.removeModule(file, project, monitor); ! } ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! //----------------------------------- COMPLETIONS ! ! /** ! * Returns the imports that start with a given string. The comparisson is not case dependent. Passes all the modules in the cache. ! * ! * @param original is the name of the import module eg. 'from toimport import ' would mean that the original is 'toimport' ! * or something like 'foo.bar' or an empty string (if only 'import'). ! * @return a Set with the imports as tuples with the name, the docstring. ! */ ! public IToken[] getCompletionsForImport(final String original, ICompletionRequest r) { ! CompletionRequest request = (CompletionRequest) r; ! PythonNature nature = request.nature; ! ! String relative = null; ! if(request.editorFile != null){ ! String moduleName = nature.getAstManager().getProjectModulesManager().resolveModule(REF.getFileAbsolutePath(request.editorFile)); ! if(moduleName != null){ ! String tail = FullRepIterable.headAndTail(moduleName)[0]; ! if(original.length() > 0){ ! relative = tail+"."+original; ! }else{ ! relative = tail; ! } ! } ! } ! ! String absoluteModule = original; ! if (absoluteModule.endsWith(".")) { ! absoluteModule = absoluteModule.substring(0, absoluteModule.length() - 1); ! } ! absoluteModule = absoluteModule.toLowerCase().trim(); ! ! //set to hold the completion (no duplicates allowed). ! Set<IToken> set = new HashSet<IToken>(); ! ! //first we get the imports... that complete for the token. ! getAbsoluteImportTokens(absoluteModule, set, PyCodeCompletion.TYPE_IMPORT, false); ! ! //Now, if we have an initial module, we have to get the completions ! //for it. ! getTokensForModule(original, nature, absoluteModule, set); ! ! if(relative != null && relative.equals(absoluteModule) == false){ ! getAbsoluteImportTokens(relative, set, PyCodeCompletion.TYPE_RELATIVE_IMPORT, false); ! getTokensForModule(relative, nature, relative, set); ! } ! return (IToken[]) set.toArray(new IToken[0]); ! } ! ! /** ! * @param moduleToGetTokensFrom the string that represents the token from where we are getting the imports ! * @param set the set where the tokens should be added ! */ ! private void getAbsoluteImportTokens(String moduleToGetTokensFrom, Set<IToken> set, int type, boolean onlyFilesOnSameLevel) { ! for (Iterator iter = Arrays.asList(projectModulesManager.getAllModules()).iterator(); iter.hasNext();) { ! ModulesKey key = (ModulesKey) iter.next(); ! ! String element = key.name; ! if (element.startsWith(moduleToGetTokensFrom)) { ! if(onlyFilesOnSameLevel && key.file != null && key.file.isDirectory()){ ! continue; // we only want those that are in the same directory, and not in other directories... ! } ! element = element.substring(moduleToGetTokensFrom.length()); ! ! //we just want those that are direct ! //this means that if we had initially element = testlib.unittest.anothertest ! //and element became later... [truncated message content] |