Cannot do keyboard input in debug mode with interactive console turned on (PY-16825 )

In debug console we should handle input calls on Python side and notify Java side, like we do it in Interactive Python Console. After handling input we should send it back to Python process.
This commit is contained in:
Elizaveta Shashkova
2016-06-24 14:10:14 +03:00
parent 92838f48bc
commit 9a9cfcdbfa
9 changed files with 109 additions and 16 deletions
@@ -114,6 +114,31 @@ class StdIn(BaseStdIn):
return '\n'
#=======================================================================================================================
# DebugConsoleStdIn
#=======================================================================================================================
class DebugConsoleStdIn(BaseStdIn):
'''
Object to be added to stdin (to emulate it as non-blocking while the next line arrives)
'''
def __init__(self, dbg, original_stdin):
BaseStdIn.__init__(self)
self.debugger = dbg
self.original_stdin = original_stdin
def readline(self, *args, **kwargs):
# Notify Java side about input and call original function
try:
cmd = self.debugger.cmd_factory.make_input_requested_message()
self.debugger.writer.add_command(cmd)
return self.original_stdin.readline(*args, **kwargs)
except Exception:
import traceback
traceback.print_exc()
return '\n'
class CodeFragment:
def __init__(self, text, is_single_line=True):
self.text = text
@@ -138,6 +138,7 @@ CMD_GET_ARRAY = 143
CMD_STEP_INTO_MY_CODE = 144
CMD_GET_CONCURRENCY_EVENT = 145
CMD_SHOW_RETURN_VALUES = 146
CMD_INPUT_REQUESTED = 147
CMD_VERSION = 501
CMD_RETURN = 502
@@ -191,6 +192,7 @@ ID_TO_MEANING = {
'144': 'CMD_STEP_INTO_MY_CODE',
'145': 'CMD_GET_CONCURRENCY_EVENT',
'146': 'CMD_SHOW_RETURN_VALUES',
'147': 'CMD_INPUT_REQUESTED',
'501': 'CMD_VERSION',
'502': 'CMD_RETURN',
@@ -779,6 +781,13 @@ class NetCommandFactory:
except:
return self.make_error_message(0, get_exception_traceback_str())
def make_input_requested_message(self):
try:
return NetCommand(CMD_INPUT_REQUESTED, 0, '')
except:
return self.make_error_message(0, get_exception_traceback_str())
def make_exit_message(self):
try:
net = NetCommand(CMD_EXIT, 0, '')
+8
View File
@@ -1180,6 +1180,7 @@ def _locked_settrace(
if bufferStdErrToServer:
init_stderr_redirect()
patch_stdin(debugger)
debugger.set_trace_for_frame_and_parents(get_frame(), False, overwrite_prev_trace=overwrite_prev_trace)
@@ -1382,6 +1383,12 @@ def apply_debugger_options(setup_options):
enable_qt_support()
def patch_stdin(debugger):
from _pydev_bundle.pydev_console_utils import DebugConsoleStdIn
orig_stdin = sys.stdin
sys.stdin = DebugConsoleStdIn(debugger, orig_stdin)
#=======================================================================================================================
# main
#=======================================================================================================================
@@ -1512,6 +1519,7 @@ if __name__ == '__main__':
pass # It's ok not having stackless there...
is_module = setup['module']
patch_stdin(debugger)
if fix_app_engine_debug:
sys.stderr.write("pydev debugger: google app engine integration enabled\n")
@@ -37,5 +37,7 @@ public interface IPyDebugProcess extends PyFrameAccessor {
boolean isSuspendedOnAllThreadsPolicy();
void consoleInputRequested();
XDebugSession getSession();
}
@@ -50,6 +50,7 @@ public abstract class AbstractCommand<T> {
public static final int STEP_INTO_MY_CODE = 144;
public static final int LOG_CONCURRENCY_EVENT = 145;
public static final int SHOW_RETURN_VALUES = 146;
public static final int INPUT_REQUESTED = 147;
public static final int ERROR = 901;
@@ -197,6 +198,10 @@ public abstract class AbstractCommand<T> {
return command == WRITE_TO_CONSOLE;
}
public static boolean isInputRequested(final int command) {
return command == INPUT_REQUESTED;
}
public static boolean isExitEvent(final int command) {
return command == EXIT;
}
@@ -547,6 +547,9 @@ public class RemoteDebugger implements ProcessDebugger {
else if (AbstractCommand.isConcurrencyEvent(frame.getCommand())) {
recordConcurrencyEvent(ProtocolParser.parseConcurrencyEvent(frame.getPayload(), myDebugProcess.getPositionConverter()));
}
else if (AbstractCommand.isInputRequested(frame.getCommand())) {
myDebugProcess.consoleInputRequested();
}
else {
placeResponse(frame.getSequence(), frame);
}
@@ -95,6 +95,15 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
myExecuteActionHandler = consoleExecuteActionHandler;
}
public void inputRequested() {
final ConsoleCommunication consoleCommunication = myExecuteActionHandler.getConsoleCommunication();
if (consoleCommunication instanceof PythonDebugConsoleCommunication) {
((PythonDebugConsoleCommunication)consoleCommunication).waitingForInput = true;
myExecuteActionHandler.inputRequested();
myExecuteActionHandler.setEnabled(true);
}
}
@Override
public void requestFocus() {
IdeFocusManager.findInstance().requestFocus(getConsoleEditor().getContentComponent(), true);
@@ -15,8 +15,10 @@
*/
package com.jetbrains.python.console;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
import com.intellij.util.Function;
import com.jetbrains.python.console.pydev.AbstractConsoleCommunication;
import com.jetbrains.python.console.pydev.InterpreterResponse;
@@ -26,12 +28,16 @@ import com.jetbrains.python.debugger.PyDebuggerException;
import com.jetbrains.python.debugger.pydev.PyDebugCallback;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
/**
* @author traff
*/
public class PythonDebugConsoleCommunication extends AbstractConsoleCommunication {
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.console.pydev.PythonDebugConsoleCommunication");
private final PyDebugProcess myDebugProcess;
private final StringBuilder myExpression = new StringBuilder();
@@ -55,7 +61,7 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
@Override
public boolean isWaitingForInput() {
return false;
return waitingForInput;
}
@Override
@@ -78,24 +84,43 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
}
public void execInterpreter(ConsoleCodeFragment code, final Function<InterpreterResponse, Object> callback) {
myExpression.append(code.getText());
exec(new ConsoleCodeFragment(myExpression.toString(), false), new PyDebugCallback<Pair<String, Boolean>>() {
@Override
public void ok(Pair<String, Boolean> executed) {
boolean more = executed.second;
if (!more) {
myExpression.setLength(0);
if (waitingForInput) {
final OutputStream processInput = myDebugProcess.getProcessHandler().getProcessInput();
if (processInput != null) {
try {
final Charset defaultCharset = EncodingProjectManager.getInstance(myDebugProcess.getProject()).getDefaultCharset();
String text = code.getText();
// we save previous command text!!!
processInput.write((text + "\n").getBytes(defaultCharset));
processInput.flush();
}
catch (IOException e) {
LOG.error(e.getMessage());
}
callback.fun(new InterpreterResponse(more, isWaitingForInput()));
}
waitingForInput = false;
}
else {
@Override
public void error(PyDebuggerException exception) {
myExpression.setLength(0);
callback.fun(new InterpreterResponse(false, isWaitingForInput()));
}
});
myExpression.append(code.getText());
exec(new ConsoleCodeFragment(myExpression.toString(), false), new PyDebugCallback<Pair<String, Boolean>>() {
@Override
public void ok(Pair<String, Boolean> executed) {
boolean more = executed.second;
if (!more) {
myExpression.setLength(0);
}
callback.fun(new InterpreterResponse(more, isWaitingForInput()));
}
@Override
public void error(PyDebuggerException exception) {
myExpression.setLength(0);
callback.fun(new InterpreterResponse(false, isWaitingForInput()));
}
});
}
}
@Override
@@ -346,6 +346,13 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
}
}
@Override
public void consoleInputRequested() {
if (myExecutionConsole instanceof PythonDebugLanguageConsoleView) {
((PythonDebugLanguageConsoleView)myExecutionConsole).getPydevConsoleView().inputRequested();
}
}
protected void afterConnect() {
}