/** * 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. */ package org.python.pydev.debug.newconsole; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.debug.core.ILaunch; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.python.pydev.core.ExtensionHelper; import org.python.pydev.core.ICodeCompletionASTManager; import org.python.pydev.core.ICodeCompletionASTManager.ImportInfo; import org.python.pydev.core.ICompletionRequest; import org.python.pydev.core.IInterpreterInfo; import org.python.pydev.core.IModule; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IToken; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.core.docutils.ImportsSelection; import org.python.pydev.core.docutils.PySelection; import org.python.pydev.core.docutils.PySelection.ActivationTokenAndQual; import org.python.pydev.debug.model.PyStackFrame; import org.python.pydev.editor.codecompletion.AbstractCompletionProcessorWithCycling; import org.python.pydev.editor.codecompletion.IPyCodeCompletion; import org.python.pydev.editor.codecompletion.IPyCompletionProposal; import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant2; import org.python.pydev.editor.codecompletion.PyCompletionProposal; import org.python.pydev.editor.codecompletion.PyLinkedModeCompletionProposal; import org.python.pydev.editor.codecompletion.templates.PyTemplateCompletionProcessor; import org.python.pydev.editor.simpleassist.ISimpleAssistParticipant2; import com.aptana.interactive_console.console.IScriptConsoleCommunication; import com.aptana.interactive_console.console.IScriptConsoleInterpreter; import com.aptana.interactive_console.console.InterpreterResponse; import com.aptana.interactive_console.console.ui.IScriptConsoleViewer; import com.aptana.shared_core.callbacks.ICallback; import com.aptana.shared_core.structure.Tuple; /** * Default implementation for the console interpreter. * * Will ask things to the IScriptConsoleCommunication */ public class PydevConsoleInterpreter implements IScriptConsoleInterpreter { private IScriptConsoleCommunication consoleCommunication; private List<Runnable> closeRunnables = new ArrayList<Runnable>(); private List<ISimpleAssistParticipant2> simpleParticipants; private List<IPythonNature> naturesUsed = new ArrayList<IPythonNature>(); private IInterpreterInfo interpreterInfo; private PyStackFrame frame; private ILaunch launch; private Process process; @SuppressWarnings("unchecked") public PydevConsoleInterpreter() { List<Object> p = ExtensionHelper.getParticipants(ExtensionHelper.PYDEV_SIMPLE_ASSIST); ArrayList<ISimpleAssistParticipant2> list = new ArrayList<ISimpleAssistParticipant2>(); for (Object o : p) { if (o instanceof ISimpleAssistParticipant2) { list.add((ISimpleAssistParticipant2) o); } } this.simpleParticipants = list; } /* * (non-Javadoc) * @see com.aptana.interactive_console.console.IScriptConsoleInterpreter#exec(java.lang.String) */ public void exec(String command, final ICallback<Object, InterpreterResponse> onResponseReceived, final ICallback<Object, Tuple<String, String>> onContentsReceived) { consoleCommunication.execInterpreter(command, onResponseReceived, onContentsReceived); } /** * Set frame context for the new pydev console interpreter * * @param frame */ public void setFrame(PyStackFrame frame) throws Exception { this.frame = frame; } @SuppressWarnings("unchecked") public ICompletionProposal[] getCompletions(IScriptConsoleViewer viewer, String commandLine, int position, int offset, int whatToShow) throws Exception { final String text = commandLine.substring(0, position); ActivationTokenAndQual tokenAndQual = PySelection.getActivationTokenAndQual(new Document(text), text.length(), true, false); //Code-completion for imports ImportInfo importsTipper = ImportsSelection.getImportsTipperStr(text, false); if (importsTipper.importsTipperStr.length() != 0) { importsTipper.importsTipperStr = importsTipper.importsTipperStr.trim(); Set<IToken> tokens = new TreeSet<IToken>(); boolean onlyGetDirectModules = false; //Check all the natures. for (final IPythonNature nature : naturesUsed) { ICodeCompletionASTManager astManager = nature.getAstManager(); IToken[] importTokens = astManager.getCompletionsForImport(importsTipper, new ICompletionRequest() { public IPythonNature getNature() { return nature; } public File getEditorFile() { return null; } public IModule getModule() throws MisconfigurationException { return null; } }, onlyGetDirectModules); //only get all modules for the 1st one we analyze (no need to get on the others) onlyGetDirectModules = true; tokens.addAll(Arrays.asList(importTokens)); } int qlen = tokenAndQual.qualifier.length(); List<ICompletionProposal> ret = new ArrayList<ICompletionProposal>(tokens.size()); Iterator<IToken> it = tokens.iterator(); for (int i = 0; i < tokens.size(); i++) { IToken t = it.next(); int replacementOffset = offset - qlen; String representation = t.getRepresentation(); if (representation.startsWith(tokenAndQual.qualifier)) { ret.add(new PyLinkedModeCompletionProposal(representation, replacementOffset, qlen, representation .length(), t, null, null, IPyCompletionProposal.PRIORITY_DEFAULT, PyCompletionProposal.ON_APPLY_DEFAULT, "")); } } return ret.toArray(new ICompletionProposal[ret.size()]); } //END Code-completion for imports String actTok = tokenAndQual.activationToken; if (tokenAndQual.qualifier != null && tokenAndQual.qualifier.length() > 0) { if (actTok.length() > 0 && actTok.charAt(actTok.length() - 1) != '.') { actTok += '.'; } actTok += tokenAndQual.qualifier; } boolean showOnlyTemplates = whatToShow == AbstractCompletionProcessorWithCycling.SHOW_ONLY_TEMPLATES; //simple completions (clients) ArrayList<ICompletionProposal> results = new ArrayList<ICompletionProposal>(); for (ISimpleAssistParticipant2 participant : simpleParticipants) { results.addAll(participant.computeConsoleProposals(tokenAndQual.activationToken, tokenAndQual.qualifier, offset)); } ArrayList<ICompletionProposal> results2 = new ArrayList<ICompletionProposal>(); if (!showOnlyTemplates) { //shell completions if (consoleCommunication != null) { ICompletionProposal[] consoleCompletions = consoleCommunication.getCompletions(text, actTok, offset); results2.addAll(Arrays.asList(consoleCompletions)); } } if (tokenAndQual.activationToken.length() == 0) { //templates (only if we have no activation token) PyTemplateCompletionProcessor pyTemplateCompletionProcessor = new PyTemplateCompletionProcessor(); pyTemplateCompletionProcessor.addTemplateProposals(viewer, offset, results2); } Collections.sort(results2, IPyCodeCompletion.PROPOSAL_COMPARATOR); ArrayList<ICompletionProposal> results3 = new ArrayList<ICompletionProposal>(); if (!showOnlyTemplates) { //other participants List<Object> participants = ExtensionHelper.getParticipants(ExtensionHelper.PYDEV_COMPLETION); for (Object participant : participants) { if (participant instanceof IPyDevCompletionParticipant2) { IPyDevCompletionParticipant2 participant2 = (IPyDevCompletionParticipant2) participant; results3.addAll(participant2.computeConsoleCompletions(tokenAndQual, this.naturesUsed, viewer, offset)); } } Collections.sort(results3, IPyCodeCompletion.PROPOSAL_COMPARATOR); } results.addAll(results2); results.addAll(results3); return results.toArray(new ICompletionProposal[results.size()]); } /* * (non-Javadoc) * @see com.aptana.interactive_console.console.IScriptConsoleShell#getDescription(org.eclipse.jface.text.IDocument, int) */ public String getDescription(IDocument doc, int position) throws Exception { ActivationTokenAndQual tokenAndQual = PySelection.getActivationTokenAndQual(doc, position, true, false); String actTok = tokenAndQual.activationToken; if (tokenAndQual.qualifier != null && tokenAndQual.qualifier.length() > 0) { if (actTok.length() > 0 && actTok.charAt(actTok.length() - 1) != '.') { actTok += '.'; } actTok += tokenAndQual.qualifier; } return consoleCommunication.getDescription(actTok); } /* * (non-Javadoc) * @see com.aptana.interactive_console.console.IScriptConsoleShell#close() */ public void close() { if (consoleCommunication != null) { try { consoleCommunication.close(); } catch (Exception e) { //ignore } consoleCommunication = null; } // run all close runnables. for (Runnable r : this.closeRunnables) { r.run(); } //we can close just once! this.closeRunnables = null; } /* * (non-Javadoc) * @see com.aptana.interactive_console.console.IConsoleRequest#setConsoleCommunication(com.aptana.interactive_console.console.IScriptConsoleCommunication) */ public void setConsoleCommunication(IScriptConsoleCommunication protocol) { this.consoleCommunication = protocol; } public IScriptConsoleCommunication getConsoleCommunication() { return consoleCommunication; } public void addCloseOperation(Runnable runnable) { this.closeRunnables.add(runnable); } public void setNaturesUsed(List<IPythonNature> naturesUsed) { if (naturesUsed == null) { naturesUsed = new ArrayList<IPythonNature>(); } this.naturesUsed = naturesUsed; } public void setInterpreterInfo(IInterpreterInfo interpreterInfo) { this.interpreterInfo = interpreterInfo; } public IInterpreterInfo getInterpreterInfo() { return this.interpreterInfo; } public void setLaunch(ILaunch launch) { this.launch = launch; } public ILaunch getLaunch() { return launch; } public void setProcess(Process process) { this.process = process; } public Process getProcess() { return process; } public PyStackFrame getFrame() { return frame; } /** * Enable/Disable linking of the debug console with the suspended frame. */ public void linkWithDebugSelection(boolean isLinkedWithDebug) { this.consoleCommunication.linkWithDebugSelection(isLinkedWithDebug); } }