Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add file completions to interactive console

Adds file and folder command completion to the interactive console.
Supports relative and absolute paths in normal console, and absolute
paths in debug console.
  • Loading branch information...
commit 88a35936c26b7c15972857c53945d06d25681212 1 parent aab57f7
Jonah Graham authored
Showing with 497 additions and 13 deletions.
  1. +8 −0 plugins/org.python.pydev.core/src/org/python/pydev/core/IToken.java
  2. +8 −1 plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java
  3. +10 −0 plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java
  4. +132 −5 plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java
  5. +287 −0 ....python.pydev.debug/tests_console/org/python/pydev/debug/newconsole/ConsoleFileAndFolderCompletionTest.java
  6. +8 −0 plugins/org.python.pydev/PySrc/pydevconsole.py
  7. +6 −4 plugins/org.python.pydev/src/org/python/pydev/ui/UIConstants.java
  8. +6 −0 plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionImages.java
  9. +1 −0  ...ns/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionInitializer.java
  10. +10 −0 ...rg.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionPreferencesPage.java
  11. +3 −0  plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PythonCompletionProcessor.java
  12. +10 −0 plugins/org.python.pydev/src_dltk_console/org/python/pydev/dltk/console/IScriptConsoleCommunication.java
  13. +8 −3 plugins/org.python.pydev/tests/org/python/pydev/ui/BundleInfoStub.java
8 plugins/org.python.pydev.core/src/org/python/pydev/core/IToken.java
View
@@ -76,6 +76,14 @@
* 'foo' and 'bar' would be generated with this type
*/
public static final int TYPE_OBJECT_FOUND_INTERFACE = 10;
+ /**
+ * Type for OS folder
+ */
+ public static final int TYPE_OS_PATH_FOLDER = 11;
+ /**
+ * Type for OS file
+ */
+ public static final int TYPE_OS_PATH_FILE = 12;
/**
* @return the type for this token
9 plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java
View
@@ -6,6 +6,7 @@
*/
package org.python.pydev.debug.console;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
@@ -171,8 +172,14 @@ public void commandComplete(AbstractDebuggerCommand cmd) {
}
}
+
+
+ @Override
+ public File getCWD() throws Exception {
+ // Obtaining CWD from pydevd not currently supported
+ return null;
+ }
}
-
/**
* The content assistant added to the console.
10 plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java
View
@@ -6,6 +6,7 @@
*/
package org.python.pydev.debug.newconsole;
+import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -421,5 +422,14 @@ public String getDescription(String text) throws Exception {
return client.execute("getDescription", new Object[]{text}).toString();
}
+ @Override
+ public File getCWD() throws Exception {
+ if (waitingForInput) {
+ return null;
+ }
+ Object execute = client.execute("getCWD", new Object[] {});
+ File file = new File(execute.toString());
+ return file;
+ }
}
137 plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java
View
@@ -7,6 +7,7 @@
package org.python.pydev.debug.newconsole;
import java.io.File;
+import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -18,13 +19,15 @@
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.swt.graphics.Image;
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.IPythonNature;
import org.python.pydev.core.IToken;
-import org.python.pydev.core.ICodeCompletionASTManager.ImportInfo;
+import org.python.pydev.core.Tuple;
import org.python.pydev.core.callbacks.ICallback;
import org.python.pydev.core.docutils.ImportsSelection;
import org.python.pydev.core.docutils.PySelection;
@@ -37,6 +40,7 @@
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.PyCodeCompletionImages;
import org.python.pydev.editor.codecompletion.PyCompletionProposal;
import org.python.pydev.editor.codecompletion.PyLinkedModeCompletionProposal;
import org.python.pydev.editor.codecompletion.templates.PyTemplateCompletionProcessor;
@@ -89,9 +93,38 @@ public Object call(InterpreterResponse response){
public ICompletionProposal[] getCompletions(IScriptConsoleViewer viewer, String commandLine,
int position, int offset, int whatToShow) throws Exception {
+ boolean showOnlyTemplates = whatToShow == AbstractCompletionProcessorWithCycling.SHOW_ONLY_TEMPLATES;
String text = commandLine.substring(0, position);
- ActivationTokenAndQual tokenAndQual = PySelection.getActivationTokenAndQual(new Document(text), text.length(), true, false);
+
+ // If we are completing something that is almost certainly a path, only
+ // provide path completions. To be a path, from the end of the string
+ // the first non alpha-numeric, or ., etc character (specifially
+ // !isJavaIdentifierPart, as PySelection.extractActivationToken() must
+ // be a slash
+ Document doc = new Document(text);
+ int testOffset = text.length();
+ while (testOffset > 0) {
+ Tuple<String, Integer> tokenTuple = PySelection
+ .extractActivationToken(doc, testOffset, false);
+ testOffset -= tokenTuple.o1.length();
+ if (tokenTuple.o1.length() == 0 || testOffset <= 0
+ || doc.getChar(testOffset - 1) != '.')
+ break;
+ }
+ if (testOffset > 0 && doc.getChar(testOffset - 1) == '/') {
+ ICompletionProposal[] fileAndFolderCompletions = getFileAndFolderCompletions(
+ text, offset, consoleCommunication);
+ if (fileAndFolderCompletions.length > 0) {
+ if (showOnlyTemplates) {
+ return new ICompletionProposal[0];
+ }
+ return fileAndFolderCompletions;
+ }
+ }
+
+ ActivationTokenAndQual tokenAndQual = PySelection
+ .getActivationTokenAndQual(doc, text.length(), true, false);
//Code-completion for imports
@@ -155,7 +188,6 @@ public File getEditorFile(){
}
- boolean showOnlyTemplates = whatToShow == AbstractCompletionProcessorWithCycling.SHOW_ONLY_TEMPLATES;
//simple completions (clients)
ArrayList<ICompletionProposal> results = new ArrayList<ICompletionProposal>();
@@ -173,6 +205,14 @@ public File getEditorFile(){
if(consoleCommunication != null){
ICompletionProposal[] consoleCompletions = consoleCommunication.getCompletions(actTok, offset);
results2.addAll(Arrays.asList(consoleCompletions));
+
+ // Obtain a list of files and folders that match completion
+ // We don't use the activation token because it's creation
+ // leaves
+ // out "/" that precedes it.
+ consoleCompletions = getFileAndFolderCompletions(text, offset,
+ consoleCommunication);
+ results2.addAll(Arrays.asList(consoleCompletions));
}
}
@@ -180,7 +220,7 @@ public File getEditorFile(){
//templates (only if we have no activation token)
PyTemplateCompletionProcessor pyTemplateCompletionProcessor = new PyTemplateCompletionProcessor();
pyTemplateCompletionProcessor.addTemplateProposals(viewer, offset, results2);
-
+
Collections.sort(results2, IPyCodeCompletion.PROPOSAL_COMPARATOR);
}
@@ -202,7 +242,94 @@ public File getEditorFile(){
return results.toArray(new ICompletionProposal[results.size()]);
}
-
+ // Package private for tests
+ /* package */static ICompletionProposal[] getFileAndFolderCompletions(
+ String text, int offset, IScriptConsoleCommunication consoleComms)
+ throws Exception {
+ String fullPath = getPathCompletionToken(text);
+ boolean isAbsolute = new File(fullPath).isAbsolute()
+ || fullPath.startsWith("/");
+
+ final String fileNamePrefix;
+ final File baseDir;
+ int dirEnd = fullPath.lastIndexOf('/');
+ File cwd = null;
+ if (dirEnd == -1 || !isAbsolute) {
+ cwd = consoleComms.getCWD();
+ if (cwd == null) {
+ return new ICompletionProposal[0];
+ }
+ }
+ if (dirEnd >= 0) {
+ String absStr = fullPath.substring(0, dirEnd + 1);
+ fileNamePrefix = fullPath.substring(dirEnd + 1);
+ if (isAbsolute) {
+ baseDir = new File(absStr);
+ } else {
+ baseDir = new File(cwd, absStr);
+ }
+ } else {
+ baseDir = cwd;
+ fileNamePrefix = fullPath;
+ }
+
+ String[] files = baseDir.list(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.startsWith(fileNamePrefix);
+ }
+ });
+ List<ICompletionProposal> results = new ArrayList<ICompletionProposal>();
+ if (files != null) {
+ for (String file : files) {
+ Image image;
+ String display = file;
+ if (new File(baseDir, file).isDirectory()) {
+ image = PyCodeCompletionImages
+ .getImageForType(IToken.TYPE_OS_PATH_FOLDER);
+ } else {
+ image = PyCodeCompletionImages
+ .getImageForType(IToken.TYPE_OS_PATH_FILE);
+ }
+ PyCompletionProposal pyCompletionProposal = new PyCompletionProposal(
+ file, offset - fileNamePrefix.length(),
+ fileNamePrefix.length(), file.length(), image, display,
+ null, null, IPyCompletionProposal.PRIORITY_DEFAULT,
+ PyCompletionProposal.ON_APPLY_DEFAULT, "");
+ results.add(pyCompletionProposal);
+
+ }
+ Collections.sort(results, IPyCodeCompletion.PROPOSAL_COMPARATOR);
+ }
+ return results.toArray(new ICompletionProposal[0]);
+ }
+
+ /**
+ * Return from the text string the portion of it which may be a path.
+ *
+ * @param text
+ * to search
+ * @return substring of text that may be a full path
+ */
+ private static String getPathCompletionToken(String text) {
+ int i = text.length();
+ // Find the likely beginning of the full path name
+ // Path names start at white-space, or at the beginning of the
+ // contained string
+ // This search method means that there is no support for cases
+ // when the path name has white space, single or double quotes in the
+ // name.
+ while (i > 0) {
+ char ch = text.charAt(i - 1);
+ if (Character.isWhitespace(ch) || ch == '"' || ch == '\'')
+ break;
+ i--;
+ }
+ String fullPath = text.substring(i).replace('\\', '/');
+ return fullPath;
+ }
+
/*
* (non-Javadoc)
* @see org.python.pydev.dltk.console.IScriptConsoleShell#getDescription(org.eclipse.jface.text.IDocument, int)
287 ...thon.pydev.debug/tests_console/org/python/pydev/debug/newconsole/ConsoleFileAndFolderCompletionTest.java
View
@@ -0,0 +1,287 @@
+package org.python.pydev.debug.newconsole;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.python.pydev.core.IToken;
+import org.python.pydev.core.TestDependent;
+import org.python.pydev.core.callbacks.ICallback;
+import org.python.pydev.dltk.console.IScriptConsoleCommunication;
+import org.python.pydev.dltk.console.InterpreterResponse;
+import org.python.pydev.editor.codecompletion.PyCodeCompletionImages;
+import org.python.pydev.editor.codecompletion.revisited.CodeCompletionTestsBase;
+
+public class ConsoleFileAndFolderCompletionTest extends CodeCompletionTestsBase {
+
+ private static class DummyConsoleComms implements
+ IScriptConsoleCommunication {
+
+ private File cwd;
+
+ public DummyConsoleComms(File cwd) {
+ this.cwd = cwd;
+ }
+
+ public DummyConsoleComms() {
+ this.cwd = null;
+ }
+
+ public DummyConsoleComms(String cwd) {
+ this.cwd = new File(cwd);
+ }
+
+ @Override
+ public void execInterpreter(String command,
+ ICallback<Object, InterpreterResponse> onResponseReceived) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ICompletionProposal[] getCompletions(String text, int offset)
+ throws Exception {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getDescription(String text) throws Exception {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public File getCWD() throws Exception {
+ return cwd;
+ }
+
+ @Override
+ public void close() throws Exception {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ private DummyConsoleComms dummyConsoleComms;
+ private List<File> rootFolders = new ArrayList<File>();
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ dummyConsoleComms = new DummyConsoleComms(TestDependent.PYTHON_INSTALL);
+ }
+
+ // Ideally we would just use FileUtils.deleteDirectory from Apache
+ // commons-io
+ // (http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#deleteDirectory%28java.io.File%29)
+ // But for now this shortcut will do
+ void deleteRoot(File root) throws IOException {
+ if (root.isDirectory()) {
+ for (File child : root.listFiles())
+ deleteRoot(child);
+ }
+ if (!root.delete())
+ throw new IOException("Failed to delete file: " + root);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ for (File root : rootFolders) {
+ deleteRoot(root);
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Create, in a temporary location, the set of files and folders passed in
+ * paths. Path entries ending in / mean create directory. Parent directory
+ * will be created automatically.
+ *
+ * @param paths
+ * files and folders to create
+ * @return the root created. The created folder is automatically deleted
+ * during teardown.
+ */
+ public File createFilesAndFolders(String[] paths) {
+ try {
+ File root = File.createTempFile("pydevtest", "");
+ if (!root.delete() || !root.mkdir()) {
+ throw new IOException("Failed to create root dir "
+ + root.toString());
+ }
+ rootFolders.add(root);
+
+ for (String entry : paths) {
+ if (entry.endsWith("/")) {
+ // Make a directory
+ File dir = new File(root, entry);
+ if (!dir.mkdirs()) {
+ throw new IOException("mkdirs returned false for "
+ + entry);
+ }
+ } else {
+ // make a file
+ File file = new File(root, entry);
+ File parent = file.getParentFile();
+ if (!parent.exists() && !parent.mkdirs()) {
+ throw new IOException("mkdirs returned false for "
+ + parent.toString());
+ }
+ if (!file.createNewFile()) {
+ throw new IOException(
+ "createNewFile returned false for " + entry);
+ }
+ }
+ }
+
+ return root;
+ } catch (IOException e) {
+ fail("Failed to create files and folders for test."
+ + e.getMessage());
+ return null;
+ }
+ }
+
+ // Make sure the mechanism works
+ public void testCreateFiles() {
+ File root = createFilesAndFolders(new String[] { "hello", "goodbye/",
+ "dir1/dir2/", "dir3/file4" });
+ assertTrue(root.exists() && root.isDirectory());
+ assertTrue(new File(root, "hello").exists()
+ && new File(root, "hello").isFile());
+ assertTrue(new File(root, "goodbye").exists()
+ && new File(root, "goodbye").isDirectory());
+ assertTrue(new File(root, "dir1/dir2").exists()
+ && new File(root, "dir1/dir2").isDirectory());
+ assertTrue(new File(root, "dir3/file4").exists()
+ && new File(root, "dir3/file4").isFile());
+ }
+
+ private void runCompletion(String s, String[] expected) throws Exception {
+ runCompletion(s, expected, dummyConsoleComms);
+ }
+
+ private void runCompletion(String s, String[] expected,
+ IScriptConsoleCommunication console) throws Exception {
+ runCompletion(s, expected.length, expected, console);
+ }
+
+ private void runCompletion(String s, int returned, String[] expected,
+ IScriptConsoleCommunication console) throws Exception {
+ ICompletionProposal[] completions = PydevConsoleInterpreter
+ .getFileAndFolderCompletions(s, s.length(), console);
+ if (returned >= 0)
+ assertTrue(completions.length == returned);
+ for (String expect : expected) {
+ boolean isDir = false;
+ if (expect.endsWith("/")) {
+ expect = expect.substring(0, expect.length() - 1);
+ isDir = true;
+ }
+ ICompletionProposal match = assertContains(expect, completions);
+ if (isDir) {
+ assertEquals(
+ PyCodeCompletionImages
+ .getImageForType(IToken.TYPE_OS_PATH_FOLDER),
+ match.getImage());
+ } else {
+ assertEquals(
+ PyCodeCompletionImages
+ .getImageForType(IToken.TYPE_OS_PATH_FILE),
+ match.getImage());
+ }
+ }
+ }
+
+ public void testCompletions() throws Exception {
+ File root = createFilesAndFolders(new String[] { "hello", "goodbye/" });
+
+ // Absolute completions
+ runCompletion(new File(root, "hel").toString(),
+ new String[] { "hello" });
+ runCompletion(new File(root, "good").toString(),
+ new String[] { "goodbye/" });
+ runCompletion(root.toString() + "/",
+ new String[] { "hello", "goodbye/" });
+
+ // Relative completions
+ IScriptConsoleCommunication comms = new DummyConsoleComms(root);
+ runCompletion("hel", new String[] { "hello" }, comms);
+ runCompletion("good", new String[] { "goodbye/" }, comms);
+ runCompletion("", new String[] { "hello", "goodbye/" }, comms);
+
+ // Completions with a string
+ runCompletion("\"hel", new String[] { "hello" }, comms);
+ runCompletion("\"good", new String[] { "goodbye/" }, comms);
+ runCompletion("\"", new String[] { "hello", "goodbye/" }, comms);
+ runCompletion("'hel", new String[] { "hello" }, comms);
+ runCompletion(" \"hel", new String[] { "hello" }, comms);
+ runCompletion(" 'hel", new String[] { "hello" }, comms);
+ }
+
+ public void testFailToGetCWDCompletionAbsolute() {
+ try {
+ File root = createFilesAndFolders(new String[] { "hello",
+ "goodbye/" });
+ String s = root.toString();
+ PydevConsoleInterpreter.getFileAndFolderCompletions(s, s.length(),
+ new DummyConsoleComms() {
+ @Override
+ public File getCWD() throws Exception {
+ throw new Exception("Failed to get CWD");
+ }
+ });
+ } catch (Exception e) {
+ fail("no exception should be thrown");
+ }
+ }
+
+ public void testFailToGetCWDCompletionRelative() {
+ try {
+ PydevConsoleInterpreter.getFileAndFolderCompletions("", 0,
+ new DummyConsoleComms() {
+ @Override
+ public File getCWD() throws Exception {
+ throw new Exception("Failed to get CWD");
+ }
+ });
+ fail("Should have had an exception");
+ } catch (Exception e) {
+ assertEquals("Failed to get CWD", e.getMessage());
+ }
+ }
+
+ public void testNonExistantDir() throws Exception {
+ File root = createFilesAndFolders(new String[] { "hello", "goodbye/" });
+
+ // Absolute completions
+ runCompletion(new File(root, "doesnotexist").toString(),
+ new String[] {});
+ runCompletion(new File(root, "doesnotexist/file").toString(),
+ new String[] {});
+
+ // Relative completions
+ IScriptConsoleCommunication comms = new DummyConsoleComms(root);
+ runCompletion(new File(root, "doesnotexist").toString(),
+ new String[] {}, comms);
+ runCompletion(new File(root, "doesnotexist/file").toString(),
+ new String[] {}, comms);
+ }
+
+ // On Windows, /file is not considered absolute because it doesn't start
+ // with X: (or multiple slashes, see File.isAbsolute), but python treats it
+ // as absolute on the current drive anyway.
+ public void testRootCompletion() throws Exception {
+ File root = createFilesAndFolders(new String[] {});
+
+ File last = null;
+ while (root.getParentFile() != null) {
+ last = root;
+ root = root.getParentFile();
+ }
+
+ IScriptConsoleCommunication comms = new DummyConsoleComms(root);
+ runCompletion("/", -1, new String[] { last.getName() + "/" }, comms);
+ }
+
+}
8 plugins/org.python.pydev/PySrc/pydevconsole.py
View
@@ -277,6 +277,13 @@ def getDescription(self, text):
import traceback;traceback.print_exc()
return ''
+ def getCWD(self):
+ try:
+ return os.getcwd()
+ except:
+ import traceback;traceback.print_exc()
+ return ''
+
def close(self):
sys.exit(0)
@@ -319,6 +326,7 @@ def StartServer(host, port, client_port):
server.register_function(interpreter.addExec)
server.register_function(interpreter.getCompletions)
server.register_function(interpreter.getDescription)
+ server.register_function(interpreter.getCWD)
server.register_function(interpreter.close)
server.serve_forever()
10 plugins/org.python.pydev/src/org/python/pydev/ui/UIConstants.java
View
@@ -75,6 +75,8 @@
public static final String COMPLETION_CLASS_ICON = CLASS_ICON;
public static final String COMPLETION_PARAMETERS_ICON = "icons/parameters_obj.gif";
public static final String COMPLETION_EPYDOC = "icons/annotation_obj.gif";
+ public static final String COMPLETION_OS_PATH_FOLDER = "icons/folder.gif";
+ public static final String COMPLETION_OS_PATH_FILE = "icons/file.gif";
//content assist
public static final String ASSIST_ANNOTATION = "icons/annotation_obj.gif";
@@ -119,9 +121,9 @@
public static final String FORWARD = "icons/forward_nav.gif";
public static final String BACK = "icons/backward_nav.gif";
public static final String HOME = "icons/home_nav.gif";
-
- public static final String FORCE_TABS_ACTIVE = "icons/tabs_active.png";
- public static final String FORCE_TABS_INACTIVE = "icons/tabs_inactive.png";
- public static final String PY_LINT_ICON = "icons/pylint.png";
+
+ public static final String FORCE_TABS_ACTIVE = "icons/tabs_active.png";
+ public static final String FORCE_TABS_INACTIVE = "icons/tabs_inactive.png";
+ public static final String PY_LINT_ICON = "icons/pylint.png";
public static final String WARNING = "icons/warning.png";
}
6 plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionImages.java
View
@@ -55,6 +55,12 @@ public static Image getImageForType(int type){
case IToken.TYPE_EPYDOC:
return imageCache.get(UIConstants.COMPLETION_EPYDOC);
+ case IToken.TYPE_OS_PATH_FOLDER:
+ return imageCache.get(UIConstants.COMPLETION_OS_PATH_FOLDER);
+
+ case IToken.TYPE_OS_PATH_FILE:
+ return imageCache.get(UIConstants.COMPLETION_OS_PATH_FILE);
+
default:
return null;
}
1  ...org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionInitializer.java
View
@@ -30,6 +30,7 @@ public void initializeDefaultPreferences() {
node.putBoolean(PyCodeCompletionPreferencesPage.USE_AUTOCOMPLETE, PyCodeCompletionPreferencesPage.DEFAULT_USE_AUTOCOMPLETE);
node.putBoolean(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_ON_PAR, PyCodeCompletionPreferencesPage.DEFAULT_AUTOCOMPLETE_ON_PAR);
node.putBoolean(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_ON_ALL_ASCII_CHARS, PyCodeCompletionPreferencesPage.DEFAULT_AUTOCOMPLETE_ON_ALL_ASCII_CHARS);
+ node.putBoolean(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_ON_SLASH, PyCodeCompletionPreferencesPage.DEFAULT_AUTOCOMPLETE_ON_SLASH);
//When to apply
10 ...python.pydev/src_completions/org/python/pydev/editor/codecompletion/PyCodeCompletionPreferencesPage.java
View
@@ -42,6 +42,9 @@
public static final String AUTOCOMPLETE_ON_ALL_ASCII_CHARS = "AUTOCOMPLETE_ON_ALL_ASCII_CHARS";
public static final boolean DEFAULT_AUTOCOMPLETE_ON_ALL_ASCII_CHARS = false;
+ public static final String AUTOCOMPLETE_ON_SLASH = "AUTOCOMPLETE_ON_SLASH";
+ public static final boolean DEFAULT_AUTOCOMPLETE_ON_SLASH = false;
+
public static final String USE_AUTOCOMPLETE = "USE_AUTOCOMPLETE";
public static final boolean DEFAULT_USE_AUTOCOMPLETE = true;
@@ -119,6 +122,9 @@ protected void createFieldEditors() {
AUTOCOMPLETE_ON_ALL_ASCII_CHARS, "Request completion on all letter chars and '_'?", p));
addField(new BooleanFieldEditor(
+ AUTOCOMPLETE_ON_SLASH, "Request completion on '/'?", p));
+
+ addField(new BooleanFieldEditor(
APPLY_COMPLETION_ON_DOT, "Apply completion on '.'?", p));
addField(new BooleanFieldEditor(
@@ -201,6 +207,10 @@ public static boolean useAutocompleteOnAllAsciiChars() {
return getPreferences().getBoolean(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_ON_ALL_ASCII_CHARS);
}
+ public static boolean isToAutocompleteOnSlash() {
+ return getPreferences().getBoolean(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_ON_SLASH);
+ }
+
public static int getAutocompleteDelay() {
return getPreferences().getInt(PyCodeCompletionPreferencesPage.AUTOCOMPLETE_DELAY);
}
3  ...s/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/PythonCompletionProcessor.java
View
@@ -306,6 +306,9 @@ public void propertyChange(PropertyChangeEvent event) {
if (PyCodeCompletionPreferencesPage.isToAutocompleteOnPar()) {
c = StringUtils.addChar(c, '(');
}
+ if (PyCodeCompletionPreferencesPage.isToAutocompleteOnSlash()) {
+ c = StringUtils.addChar(c, '/');
+ }
activationChars = c;
}
}
10 plugins/org.python.pydev/src_dltk_console/org/python/pydev/dltk/console/IScriptConsoleCommunication.java
View
@@ -9,6 +9,8 @@
*******************************************************************************/
package org.python.pydev.dltk.console;
+import java.io.File;
+
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.python.pydev.core.callbacks.ICallback;
@@ -48,6 +50,14 @@
public String getDescription(String text) throws Exception;
/**
+ * Returns the current working directory of the interpreter.
+ *
+ * @return the current working directory (os.getcwd) or null if not available
+ * @throws Exception
+ */
+ public File getCWD() throws Exception;
+
+ /**
* Stops the communication with the server. Should ask the server to terminate at this point.
* @throws Exception
*/
11 plugins/org.python.pydev/tests/org/python/pydev/ui/BundleInfoStub.java
View
@@ -23,7 +23,9 @@
public class BundleInfoStub implements IBundleInfo {
- public File getRelativePath(IPath relative) throws CoreException {
+ private ImageCache imageCache;
+
+ public File getRelativePath(IPath relative) throws CoreException {
if(relative.toString().indexOf("interpreterInfo.py") != -1){
return new File(TestDependent.TEST_PYDEV_PLUGIN_LOC+"PySrc/interpreterInfo.py");
}
@@ -46,9 +48,12 @@ public String getPluginID() {
return "plugin_id";
}
- public ImageCache getImageCache() {
+ public synchronized ImageCache getImageCache() {
try {
- return new ImageCache(new URL("file:///" + TestDependent.TEST_PYDEV_PLUGIN_LOC));
+ if (imageCache == null) {
+ imageCache = new ImageCache(new URL("file:///" + TestDependent.TEST_PYDEV_PLUGIN_LOC));
+ }
+ return imageCache;
} catch (Exception e) {
throw new RuntimeException(e);
}
Please sign in to comment.
Something went wrong with that request. Please try again.