📄 pycodecompletion.java
字号:
/*
* Created on Aug 11, 2004
*
* @author Fabio Zadrozny
*/
package org.python.pydev.editor.codecompletion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.python.pydev.core.ExtensionHelper;
import org.python.pydev.core.FullRepIterable;
import org.python.pydev.core.ICallback;
import org.python.pydev.core.ICodeCompletionASTManager;
import org.python.pydev.core.ICompletionState;
import org.python.pydev.core.ILocalScope;
import org.python.pydev.core.IModule;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IToken;
import org.python.pydev.core.ICodeCompletionASTManager.ImportInfo;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.CompletionRecursionException;
import org.python.pydev.editor.codecompletion.revisited.ASTManager;
import org.python.pydev.editor.codecompletion.revisited.AssignAnalysis;
import org.python.pydev.editor.codecompletion.revisited.CompletionState;
import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule;
import org.python.pydev.editor.codecompletion.revisited.modules.CompiledModule;
import org.python.pydev.editor.codecompletion.revisited.visitors.FindScopeVisitor;
import org.python.pydev.editor.codecompletion.shell.AbstractShell;
import org.python.pydev.parser.PyParser;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.visitors.NodeUtils;
/**
* @author Dmoore
* @author Fabio Zadrozny
*/
public class PyCodeCompletion extends AbstractPyCodeCompletion {
/**
* This constant is used to debug the code-completion process on a production environment,
* so that we gather enough information about what's happening and the possible reasons
* for some bug (at this moment this is being specifically added because of a halting bug
* for pydev in linux: https://sourceforge.net/tracker/index.php?func=detail&aid=1509582&group_id=85796&atid=577329)
*
* It is kept updated from the Preferences Page
*/
public static volatile boolean DEBUG_CODE_COMPLETION = PyCodeCompletionPreferencesPage.isToDebugCodeCompletion();
/**
* Called when a recursion exception is detected.
*/
public static ICallback<Object, CompletionRecursionException> onCompletionRecursionException;
/* (non-Javadoc)
* @see org.python.pydev.editor.codecompletion.IPyCodeCompletion#getCodeCompletionProposals(org.eclipse.jface.text.ITextViewer, org.python.pydev.editor.codecompletion.CompletionRequest)
*/
public List getCodeCompletionProposals(ITextViewer viewer, CompletionRequest request) throws CoreException, BadLocationException {
if(request.getPySelection().getCursorLineContents().trim().startsWith("#")){
//this may happen if the context is still not correctly computed in python
return new PyStringCodeCompletion().getCodeCompletionProposals(viewer, request);
}
if(DEBUG_CODE_COMPLETION){
Log.toLogFile(this,"Starting getCodeCompletionProposals");
Log.addLogLevel();
Log.toLogFile(this,"Request:"+request);
}
ArrayList<ICompletionProposal> ret = new ArrayList<ICompletionProposal>();
//let's see if we should do a code-completion in the current scope...
if(!isValidCompletionContext(request)){
request.showTemplates = false;
return ret;
}
try {
IPythonNature pythonNature = request.nature;
checkPythonNature(pythonNature);
ICodeCompletionASTManager astManager = pythonNature.getAstManager();
if (astManager == null) {
//we're probably still loading it.
return ret;
}
//list of Object[], IToken or ICompletionProposal
List<Object> tokensList = new ArrayList<Object>();
lazyStartShell(request);
String trimmed = request.activationToken.replace('.', ' ').trim();
ImportInfo importsTipper = getImportsTipperStr(request);
int line = request.doc.getLineOfOffset(request.documentOffset);
IRegion region = request.doc.getLineInformation(line);
ICompletionState state = new CompletionState(line, request.documentOffset - region.getOffset(), null, request.nature, request.qualifier);
state.setIsInCalltip(request.isInCalltip);
boolean importsTip = false;
if (importsTipper.importsTipperStr.length() != 0) {
//code completion in imports
request.isInCalltip = false; //if found after (, but in an import, it is not a calltip!
importsTip = doImportCompletion(request, astManager, tokensList, importsTipper);
} else if (trimmed.length() > 0 && request.activationToken.indexOf('.') != -1) {
//code completion for a token
doTokenCompletion(request, astManager, tokensList, trimmed, state);
} else {
//go to globals
doGlobalsCompletion(request, astManager, tokensList, state);
}
Map<String, IToken> alreadyChecked = new HashMap<String, IToken>();
String lowerCaseQual = request.qualifier.toLowerCase();
if(lowerCaseQual.length() >= PyCodeCompletionPreferencesPage.getArgumentsDeepAnalysisNChars()){
//this can take some time on the analysis, so, let's let the user choose on how many chars does he
//want to do the analysis...
state.pushFindResolveImportMemoryCtx();
try{
for(ListIterator it=tokensList.listIterator(); it.hasNext();){
Object o = it.next();
if(o instanceof IToken){
it.remove(); // always remove the tokens from the list (they'll be re-added later once they are filtered)
IToken initialToken = (IToken) o;
IToken token = initialToken;
String strRep = token.getRepresentation();
IToken prev = alreadyChecked.get(strRep);
if(prev != null){
if(prev.getArgs().length() != 0){
continue; // we already have a version with args... just keep going
}
}
if(!strRep.toLowerCase().startsWith(lowerCaseQual)){
//just re-add it if we're going to actually use it (depending on the qualifier)
continue;
}
while(token.isImportFrom()){
//we'll only add it here if it is an import from (so, set the flag to false for the outer add)
if(token.getArgs().length() > 0){
//if we already have the args, there's also no reason to do it (that's what we'll do here)
break;
}
ICompletionState s = state.getCopyForResolveImportWithActTok(token.getRepresentation());
s.checkFindResolveImportMemory(token);
IToken token2 = astManager.resolveImport(s, token);
if(token2 != null && initialToken != token2){
String args = token2.getArgs();
if(args.length() > 0){
//put it into the map (may override previous if it didn't have args)
initialToken.setArgs(args);
initialToken.setDocStr(token2.getDocStr());
break;
}
if(token2 == null ||
(token2.equals(token) &&
token2.getArgs().equals(token.getArgs()) &&
token2.getParentPackage().equals(token.getParentPackage()))){
token2.equals(token);
break;
}
token = token2;
}else{
break;
}
}
alreadyChecked.put(strRep, initialToken);
}
}
}finally{
state.popFindResolveImportMemoryCtx();
}
}
tokensList.addAll(alreadyChecked.values());
changeItokenToCompletionPropostal(viewer, request, ret, tokensList, importsTip, state);
} catch (CompletionRecursionException e) {
if(onCompletionRecursionException != null){
onCompletionRecursionException.call(e);
}
if(DEBUG_CODE_COMPLETION){
Log.toLogFile(e);
}
//PydevPlugin.log(e);
//ret.add(new CompletionProposal("",request.documentOffset,0,0,null,e.getMessage(), null,null));
}
if(DEBUG_CODE_COMPLETION){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -