diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 544e8d4acfcd..444839c62168 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -25,6 +25,7 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \ CMD_CONSOLE_EXEC, \ CMD_ADD_EXCEPTION_BREAK, \ CMD_REMOVE_EXCEPTION_BREAK, \ + CMD_LOAD_SOURCE, \ GetGlobalDebugger, \ InternalChangeVariable, \ InternalGetCompletions, \ @@ -633,6 +634,17 @@ class PyDB: always_exception_set.remove(exc_type) update_exception_hook() + elif cmd_id == CMD_LOAD_SOURCE: + path = text + try: + print path + f = open(path, 'r') + source = f.read() + print source + self.cmdFactory.makeLoadSourceMessage(seq, source, self) + except: + return self.cmdFactory.makeErrorMessage(seq, GetExceptionTracebackStr()) + else: #I have no idea what this is all about cmd = self.cmdFactory.makeErrorMessage(seq, "unexpected command " + str(cmd_id)) diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index d141297100de..e6868cfd485b 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -103,7 +103,8 @@ CMD_RELOAD_CODE = 119 CMD_GET_COMPLETIONS = 120 CMD_CONSOLE_EXEC = 121 CMD_ADD_EXCEPTION_BREAK = 122 -CMD_REMOVE_EXCEPTION_BREAK = 122 +CMD_REMOVE_EXCEPTION_BREAK = 123 +CMD_LOAD_SOURCE = 124 CMD_VERSION = 501 CMD_RETURN = 502 CMD_ERROR = 901 @@ -545,6 +546,14 @@ class NetCommandFactory: except Exception: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) + def makeLoadSourceMessage(self, seq, source, dbg=None): + try: + net = NetCommand(str(CMD_LOAD_SOURCE), seq, '%s' % source) + if dbg: + dbg.writer.addCommand(net) + except: + return self.makeErrorMessage(0, GetExceptionTracebackStr()) + INTERNAL_TERMINATE_THREAD = 1 INTERNAL_SUSPEND_THREAD = 2 diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index 3a4cfad16b35..569eb5095923 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -2,7 +2,6 @@ package com.jetbrains.python.debugger.pydev; import com.jetbrains.python.debugger.PyDebuggerException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public abstract class AbstractCommand { @@ -27,6 +26,7 @@ public abstract class AbstractCommand { public static final int CONSOLE_EXEC = 121; public static final int ADD_EXCEPTION_BREAKPOINT = 122; public static final int REMOVE_EXCEPTION_BREAKPOINT = 123; + public static final int LOAD_SOURCE = 124; public static final int VERSION = 501; public static final String NEW_LINE_CHAR = "@_@NEW_LINE_CHAR@_@"; public static final String TAB_CHAR = "@_@TAB_CHAR@_@"; @@ -39,7 +39,7 @@ public abstract class AbstractCommand { myCommandCode = commandCode; } - @Nullable + @NotNull public final String getPayload() { Payload payload = new Payload(); buildPayload(payload); @@ -52,7 +52,6 @@ public abstract class AbstractCommand { return false; } - // todo: pass debugger to constructor(?) public void execute() throws PyDebuggerException { int sequence = myDebugger.getNextSequence(); if (isResponseExpected()) { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/LoadSourceCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/LoadSourceCommand.java new file mode 100644 index 000000000000..cdafeae93a52 --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/LoadSourceCommand.java @@ -0,0 +1,39 @@ +package com.jetbrains.python.debugger.pydev; + +import com.jetbrains.python.debugger.PyDebuggerException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author traff + */ +public class LoadSourceCommand extends AbstractCommand { + private final String myPath; + + private String myContent = null; + + protected LoadSourceCommand(@NotNull final RemoteDebugger debugger, String path) { + super(debugger, LOAD_SOURCE); + myPath = path; + } + + public boolean isResponseExpected() { + return true; + } + + @Override + protected void processResponse(final ProtocolFrame response) throws PyDebuggerException { + super.processResponse(response); + myContent = ProtocolParser.parseSourceContent(response.getPayload()); + } + + @Override + protected void buildPayload(Payload payload) { + payload.add(myPath); + } + + @Nullable + public String getContent() { + return myContent; + } +} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java index 69cd30e6ab41..b8b7a782af78 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java @@ -17,6 +17,10 @@ public class ProtocolParser { private ProtocolParser() { } + public static String parseSourceContent(String payload) throws PyDebuggerException { + return payload; + } + public static String decode(final String value) throws PyDebuggerException { try { return URLDecoder.decode(value, "UTF-8"); diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index b527b4601968..8ec59c8d6666 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -150,6 +150,18 @@ public class RemoteDebugger { return command.getNewValue(); } + @Nullable + public String loadSource(String path) { + LoadSourceCommand command = new LoadSourceCommand(this, path); + try { + command.execute(); + return command.getContent(); + } + catch (PyDebuggerException e) { + return "print 1"; + } + } + private static String composeName(final PyDebugValue var) { final StringBuilder sb = new StringBuilder(var.getTempName()); PyDebugValue p = var; @@ -472,7 +484,7 @@ public class RemoteDebugger { } private void fireCloseEvent() { - for (RemoteDebuggerCloseListener listener: myCloseListeners) { + for (RemoteDebuggerCloseListener listener : myCloseListeners) { listener.closed(); } } diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index c22e48211487..9b707368905b 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -88,6 +88,7 @@ + com.jetbrains.python.codeInsight.intentions.ImportToImportFromIntention diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index e4c7b441424e..c987bf642a4b 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -519,7 +519,7 @@ run.configuration.type.description=Starts server for remote debug remote.debug.info=Info remote.debug.server.hint=Run this remote debug configuration to start debug server. -remote.debug.server.hint2=Then copy \\helpers\\pydev package from your PyCharm distribution to location of your python script. +remote.debug.server.hint2=Add pycharm-debug.egg from PyCharm distribution to python path of your script. remote.debug.server.hint3=Use the following command in your script to connect to debug server: remote.debug.settings=Settings remote.debug.remote.host=Remote host @@ -527,3 +527,5 @@ remote.debug.port=Port remote.debug.remote.root.folder=Remote root folder remote.debug.local.root.folder=Local root folder remote.debug.server.hint4=If you want to enable stdout and stderr redirection to PyCharm console, use following command in your script: +remote.debug.local.host=Local host name +remote.debug.redirect.output=Redirect output to console diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index d0dd5fd8e824..6388b5b000ef 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -41,8 +41,6 @@ import static javax.swing.SwingUtilities.invokeLater; // todo: pydevd supports module reloading - look for a way to use the feature // todo: smart step into public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, ProcessListener { - - private final PyPositionConverter myPositionConverter; private final RemoteDebugger myDebugger; private final XBreakpointHandler[] myBreakpointHandlers; private final PyDebuggerEditorsProvider myEditorsProvider; @@ -58,18 +56,12 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr private boolean myClosing = false; - public PyDebugProcess(@NotNull XDebugSession session, - @NotNull final ServerSocket serverSocket, - @NotNull final ExecutionConsole executionConsole, - @Nullable final ProcessHandler processHandler) { - this(session, serverSocket, executionConsole, processHandler, new PyLocalPositionConverter()); - } - + private PyPositionConverter myPositionConverter; public PyDebugProcess(final @NotNull XDebugSession session, @NotNull final ServerSocket serverSocket, @NotNull final ExecutionConsole executionConsole, - @Nullable final ProcessHandler processHandler, @NotNull PyPositionConverter positionConverter) { + @Nullable final ProcessHandler processHandler) { super(session); session.setPauseActionSupported(true); myDebugger = new RemoteDebugger(this, serverSocket, 10); @@ -80,7 +72,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr if (myProcessHandler != null) { myProcessHandler.addProcessListener(this); } - myPositionConverter = positionConverter; + myPositionConverter = new PyLocalPositionConverter(); myDebugger.addCloseListener(new RemoteDebuggerCloseListener() { @Override public void closed() { @@ -89,6 +81,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr }); } + public void setPositionConverter(PyPositionConverter positionConverter) { + myPositionConverter = positionConverter; + } + + @Override public PyPositionConverter getPositionConverter() { return myPositionConverter; @@ -272,6 +269,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr myNewVariableValue.put(frame.getThreadFrameId(), newValue); } + @Nullable + public String loadSource(String path) { + return myDebugger.loadSource(path); + } + @Override public boolean isVariable(String name) { final Project project = getSession().getProject(); @@ -411,4 +413,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr @Override public void onTextAvailable(ProcessEvent event, Key outputType) { } + + public PyStackFrame createStackFrame(PyStackFrameInfo frameInfo) { + return new PyStackFrame(this, frameInfo); + } } diff --git a/python/src/com/jetbrains/python/debugger/PyExecutionStack.java b/python/src/com/jetbrains/python/debugger/PyExecutionStack.java index 599183114d9a..c8da6847ef84 100644 --- a/python/src/com/jetbrains/python/debugger/PyExecutionStack.java +++ b/python/src/com/jetbrains/python/debugger/PyExecutionStack.java @@ -53,7 +53,7 @@ public class PyExecutionStack extends XExecutionStack { } private static PyStackFrame convert(final PyDebugProcess debugProcess, final PyStackFrameInfo frameInfo) { - return new PyStackFrame(debugProcess, frameInfo); + return debugProcess.createStackFrame(frameInfo); } @Override diff --git a/python/src/com/jetbrains/python/debugger/PyLocalPositionConverter.java b/python/src/com/jetbrains/python/debugger/PyLocalPositionConverter.java index d46b79b3f631..8707120cd245 100644 --- a/python/src/com/jetbrains/python/debugger/PyLocalPositionConverter.java +++ b/python/src/com/jetbrains/python/debugger/PyLocalPositionConverter.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; public class PyLocalPositionConverter implements PyPositionConverter { protected static class PyLocalSourcePosition extends PySourcePosition { - PyLocalSourcePosition(final String file, final int line) { + public PyLocalSourcePosition(final String file, final int line) { super(file, line); } } diff --git a/python/src/com/jetbrains/python/debugger/PyRemotePositionConverter.java b/python/src/com/jetbrains/python/debugger/PyRemotePositionConverter.java deleted file mode 100644 index 58b02ffb66e8..000000000000 --- a/python/src/com/jetbrains/python/debugger/PyRemotePositionConverter.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.jetbrains.python.debugger; - -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.xdebugger.XSourcePosition; -import org.jetbrains.annotations.NotNull; - -/** - * @author traff - */ -public class PyRemotePositionConverter extends PyLocalPositionConverter { - private final String myLocalRoot; - private final String myRemoteRoot; - - public PyRemotePositionConverter(final String localRoot, final String remoteRoot) { - myLocalRoot = FileUtil.toSystemIndependentName(localRoot); - myRemoteRoot = FileUtil.toSystemIndependentName(remoteRoot); - } - - @NotNull - @Override - public PySourcePosition convert(@NotNull XSourcePosition position) { - String path = FileUtil.toSystemIndependentName(position.getFile().getPath()); - if (myLocalRoot.length() > 0) { - path = path.replace(myLocalRoot, myRemoteRoot); - } - return new PyLocalSourcePosition(path, position.getLine() + 1); - } - - @Override - public XSourcePosition convert(@NotNull PySourcePosition position) { - String path = FileUtil.toSystemIndependentName(position.getFile()); - if (myRemoteRoot.length() > 0) { - path = path.replace(myRemoteRoot, myLocalRoot); - } - final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); - return createXSourcePosition(file, position.getLine()); - } -} diff --git a/python/src/com/jetbrains/python/debugger/PyStackFrame.java b/python/src/com/jetbrains/python/debugger/PyStackFrame.java index 91554bf7f0f3..46ac0f47a241 100644 --- a/python/src/com/jetbrains/python/debugger/PyStackFrame.java +++ b/python/src/com/jetbrains/python/debugger/PyStackFrame.java @@ -110,4 +110,8 @@ public class PyStackFrame extends XStackFrame { return myFrameInfo.getThreadId() + ":" + myFrameInfo.getId(); } + protected XSourcePosition getPosition() { + return myPosition; + } + } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java index 25d558abab00..e822f6f1feaa 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java @@ -707,7 +707,7 @@ public class PythonSdkType extends SdkType { } @Nullable - public static Sdk findPythonSdk(Module module) { + public static Sdk findPythonSdk(@Nullable Module module) { if (module == null) return null; final Sdk sdk = ModuleRootManager.getInstance(module).getSdk(); if (sdk != null && sdk.getSdkType() instanceof PythonSdkType) return sdk;