/** * Generates the cached tokens in the needed structure for a 'fast' search given a token * representation (creates a map with the name of the token --> token). */ private Map<String, IToken> internalGenerateCachedTokens( IPythonNature nature, ICompletionCache completionCache, String activationToken, boolean searchSameLevelMods) throws CompletionRecursionException { Map<String, IToken> cachedTokens = new HashMap<String, IToken>(); // if still not found, we have to get all the tokens, including regular and wild imports ICompletionState state = CompletionStateFactory.getEmptyCompletionState(nature, completionCache); ICodeCompletionASTManager astManager = nature.getAstManager(); state.setActivationToken(activationToken); // we don't want to gather builtins in this case. state.setBuiltinsGotten(true); IToken[] globalTokens = astManager.getCompletionsForModule(this, state, searchSameLevelMods); for (IToken token : globalTokens) { String rep = token.getRepresentation(); IToken t = cachedTokens.get(rep); if (t != null) { // only override tokens if it's a getattr that's not defined in the builtin module if (rep.equals("__getattribute__") || rep.equals("__getattr__")) { if (!isTokenFromBuiltins(token)) { cachedTokens.put(rep, token); } } } else { cachedTokens.put(rep, token); } } return cachedTokens; }
/** * Needed interface for adding the completions on a request * * @throws MisconfigurationException */ @SuppressWarnings("unchecked") public List getCodeCompletionProposals(ITextViewer viewer, CompletionRequest request) throws CoreException, BadLocationException, MisconfigurationException { ArrayList ret = new ArrayList(); request.showTemplates = false; // don't show templates in strings fillWithEpydocFields(viewer, request, ret); if (ret.size() == 0) { // if the size is not 0, it means that this is a place for the '@' stuff, and not for the // 'default' context for a string. ret.addAll( getStringGlobalsFromParticipants( request, CompletionStateFactory.getEmptyCompletionState( request.activationToken, request.nature, new CompletionCache()))); // the code-below does not work well because the module may not have an actual import for the // activation token, // so, it is useless too many times // if(request.activationToken.length() != 0){ // PyCodeCompletion completion = new PyCodeCompletion(); // ret.addAll(completion.getCodeCompletionProposals(viewer, request)); // } } fillWithParams(viewer, request, ret); return ret; }
@Override public boolean isInGlobalTokens( String tok, IPythonNature nature, ICompletionCache completionCache) { // we have to override because there is no way to check if it is in some import from some other // place if it has dots on the tok... if (tok.indexOf('.') == -1) { return isInDirectGlobalTokens(tok, completionCache); } else { ICompletionState state = CompletionStateFactory.getEmptyCompletionState(nature, completionCache); String[] headAndTail = FullRepIterable.headAndTail(tok); state.setActivationToken(headAndTail[0]); String head = headAndTail[1]; IToken[] globalTokens = getGlobalTokens(state, nature.getAstManager()); for (IToken token : globalTokens) { if (token.getRepresentation().equals(head)) { return true; } } } return false; }
@Override public void addProps( MarkerAnnotationAndPosition markerAnnotation, IAnalysisPreferences analysisPreferences, String line, PySelection ps, int offset, IPythonNature nature, PyEdit edit, List<ICompletionProposal> props) throws BadLocationException, CoreException { if (nature == null) { return; } ICodeCompletionASTManager astManager = nature.getAstManager(); if (astManager == null) { return; } if (markerAnnotation.position == null) { return; } IMarker marker = markerAnnotation.markerAnnotation.getMarker(); Integer id = (Integer) marker.getAttribute(AnalysisRunner.PYDEV_ANALYSIS_TYPE); int start = markerAnnotation.position.offset; int end = start + markerAnnotation.position.length; ps.setSelection(start, end); String markerContents; try { markerContents = ps.getSelectedText(); } catch (Exception e1) { return; // Selection may be wrong. } IDocument doc = ps.getDoc(); List<String> parametersAfterCall = ps.getParametersAfterCall(end); switch (id) { case IAnalysisPreferences.TYPE_UNDEFINED_VARIABLE: addCreateClassOption(ps, edit, props, markerContents, parametersAfterCall); addCreateMethodOption(ps, edit, props, markerContents, parametersAfterCall); break; case IAnalysisPreferences.TYPE_UNDEFINED_IMPORT_VARIABLE: // Say we had something as: // import sys // sys.Bar // in which case 'Bar' is undefined // in this situation, the activationTokenAndQual would be "sys." and "Bar" // and we want to get the definition for "sys" String[] activationTokenAndQual = ps.getActivationTokenAndQual(true); if (activationTokenAndQual[0].endsWith(".")) { ArrayList<IDefinition> selected = findDefinitions(nature, edit, start - 2, doc); for (IDefinition iDefinition : selected) { IModule module = iDefinition.getModule(); if (module.getFile() != null) { Definition definition = (Definition) iDefinition; File file = module.getFile(); if (definition.ast == null) { // if we have no ast in the definition, it means the module itself was found (global // scope) // Add option to create class at the given module! addCreateClassOption(ps, edit, props, markerContents, parametersAfterCall, file); addCreateMethodOption(ps, edit, props, markerContents, parametersAfterCall, file); } else if (definition.ast instanceof ClassDef) { ClassDef classDef = (ClassDef) definition.ast; // Ok, we should create a field or method in this case (accessing a classmethod or // staticmethod) PyCreateMethodOrField pyCreateMethod = new PyCreateMethodOrField(); String className = NodeUtils.getNameFromNameTok(classDef.name); pyCreateMethod.setCreateInClass(className); pyCreateMethod.setCreateAs(PyCreateMethodOrField.CLASSMETHOD); addCreateClassmethodOption( ps, edit, props, markerContents, parametersAfterCall, pyCreateMethod, file, className); } } } } break; case IAnalysisPreferences.TYPE_UNRESOLVED_IMPORT: // This case is the following: from other_module4 import Foo // with 'Foo' being undefined. // So, we have to suggest creating a Foo class/method in other_module4 PyImportsHandling importsHandling = new PyImportsHandling(ps.getDoc(), false); int offsetLine = ps.getLineOfOffset(start); String selectedText = ps.getSelectedText(); Tuple<IModule, String> found = null; String foundFromImportStr = null; boolean isImportFrom = false; OUT: for (ImportHandle handle : importsHandling) { if (handle.startFoundLine == offsetLine || handle.endFoundLine == offsetLine || (handle.startFoundLine < offsetLine && handle.endFoundLine > offsetLine)) { List<ImportHandleInfo> importInfo = handle.getImportInfo(); for (ImportHandleInfo importHandleInfo : importInfo) { String fromImportStr = importHandleInfo.getFromImportStr(); List<String> importedStr = importHandleInfo.getImportedStr(); for (String imported : importedStr) { if (selectedText.equals(imported)) { if (fromImportStr != null) { foundFromImportStr = fromImportStr + "." + imported; isImportFrom = true; } else { // if fromImportStr == null, it's not a from xxx import yyy (i.e.: simple // import) foundFromImportStr = imported; } try { String currentModule = nature.resolveModule(edit.getEditorFile()); ICompletionState state = CompletionStateFactory.getEmptyCompletionState( nature, new CompletionCache()); found = nature .getAstManager() .findModule( foundFromImportStr, currentModule, state, new SourceModule( currentModule, edit.getEditorFile(), edit.getAST(), null)); } catch (Exception e) { Log.log(e); } break OUT; } } } break OUT; } } boolean addOptionToCreateClassOrMethod = isImportFrom; if (found != null && found.o1 != null) { // Ok, we found a module, now, it may be that we still have to create some intermediary // modules // or just create a class or method at the end. if (found.o1 instanceof SourceModule) { // if all was found, there's nothing left to create. if (found.o2 != null && found.o2.length() > 0) { SourceModule sourceModule = (SourceModule) found.o1; File file = sourceModule.getFile(); if (found.o2.indexOf('.') != -1) { // We have to create some intermediary structure. if (!addOptionToCreateClassOrMethod) { // Cannot create class or method from the info (only the module structure). if (sourceModule.getName().endsWith(".__init__")) { File f = getFileStructure(file.getParentFile(), found.o2); addCreateModuleOption(ps, edit, props, markerContents, f); } } else { // Ok, the leaf may be a class or method. if (sourceModule.getName().endsWith(".__init__")) { String moduleName = FullRepIterable.getWithoutLastPart(sourceModule.getName()); String withoutLastPart = FullRepIterable.getWithoutLastPart(found.o2); moduleName += "." + withoutLastPart; String classOrMethodName = FullRepIterable.getLastPart(found.o2); File f = getFileStructure(file.getParentFile(), withoutLastPart); addCreateClassInNewModuleOption( ps, edit, props, classOrMethodName, moduleName, parametersAfterCall, f); addCreateMethodInNewModuleOption( ps, edit, props, classOrMethodName, moduleName, parametersAfterCall, f); } } } else { // Ok, it's all there, we just have to create the leaf. if (!addOptionToCreateClassOrMethod || sourceModule.getName().endsWith(".__init__")) { // Cannot create class or method from the info (only the module structure). if (sourceModule.getName().endsWith(".__init__")) { File f = new File( file.getParent(), found.o2 + FileTypesPreferencesPage.getDefaultDottedPythonExtension()); addCreateModuleOption(ps, edit, props, markerContents, f); } } else { // Ok, the leaf may be a class or method. addCreateClassOption(ps, edit, props, markerContents, parametersAfterCall, file); addCreateMethodOption(ps, edit, props, markerContents, parametersAfterCall, file); } } } } } else if (foundFromImportStr != null) { // We couldn't find anything there, so, we have to create the modules structure as needed // and // maybe create a class or module at the end (but only if it's an import from). // Ok, it's all there, we just have to create the leaf. // Discover the source folder where we should create the structure. File editorFile = edit.getEditorFile(); String onlyProjectPythonPathStr = nature.getPythonPathNature().getOnlyProjectPythonPathStr(false); List<String> split = StringUtils.splitAndRemoveEmptyTrimmed(onlyProjectPythonPathStr, '|'); for (int i = 0; i < split.size(); i++) { String fullPath = FileUtils.getFileAbsolutePath(split.get(i)); fullPath = PythonPathHelper.getDefaultPathStr(fullPath); split.set(i, fullPath); } HashSet<String> projectSourcePath = new HashSet<String>(split); if (projectSourcePath.size() == 0) { return; // No source folder for editor... this shouldn't happen (code analysis wouldn't // even run on it). } String fullPath = FileUtils.getFileAbsolutePath(editorFile); fullPath = PythonPathHelper.getDefaultPathStr(fullPath); String foundSourceFolderFullPath = null; if (projectSourcePath.size() == 1) { foundSourceFolderFullPath = projectSourcePath.iterator().next(); } else { for (String string : projectSourcePath) { if (fullPath.startsWith(string)) { // Use this as the source folder foundSourceFolderFullPath = string; break; } } } if (foundSourceFolderFullPath != null) { if (!addOptionToCreateClassOrMethod) { // Cannot create class or method from the info (only the module structure). File f = getFileStructure(new File(foundSourceFolderFullPath), foundFromImportStr); addCreateModuleOption(ps, edit, props, foundFromImportStr, f); } else { // Ok, the leaf may be a class or method. String moduleName = FullRepIterable.getWithoutLastPart(foundFromImportStr); File file = getFileStructure(new File(foundSourceFolderFullPath), moduleName); String lastPart = FullRepIterable.getLastPart(foundFromImportStr); addCreateClassInNewModuleOption( ps, edit, props, lastPart, moduleName, parametersAfterCall, file); addCreateMethodInNewModuleOption( ps, edit, props, lastPart, moduleName, parametersAfterCall, file); } } } break; } }