mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Execute multi-line code fragments by runsrouce with 'exec' option instead of one line by one (PY-10769).
This commit is contained in:
@@ -132,6 +132,11 @@ class StdIn(BaseStdIn):
|
||||
return '\n'
|
||||
|
||||
|
||||
class ExecCode:
|
||||
def __init__(self, code, is_single_line=True):
|
||||
self.code = code
|
||||
self.is_single_line = is_single_line
|
||||
|
||||
#=======================================================================================================================
|
||||
# BaseInterpreterInterface
|
||||
#=======================================================================================================================
|
||||
@@ -142,20 +147,14 @@ class BaseInterpreterInterface:
|
||||
self.exec_queue = _queue.Queue(0)
|
||||
self.buffer = []
|
||||
|
||||
def needMore(self, buffer, line):
|
||||
if not buffer:
|
||||
buffer = []
|
||||
buffer.append(line)
|
||||
source = "\n".join(buffer)
|
||||
def needMoreForCode(self, source):
|
||||
if hasattr(self.interpreter, 'is_complete'):
|
||||
return not self.interpreter.is_complete(source)
|
||||
|
||||
try:
|
||||
code = self.interpreter.compile(source, "<input>", "single")
|
||||
code = self.interpreter.compile(source, "<input>", "exec")
|
||||
except (OverflowError, SyntaxError, ValueError):
|
||||
# Case 1
|
||||
return False
|
||||
|
||||
if code is None:
|
||||
# Case 2
|
||||
return True
|
||||
@@ -163,8 +162,16 @@ class BaseInterpreterInterface:
|
||||
# Case 3
|
||||
return False
|
||||
|
||||
def needMore(self, buffer, line):
|
||||
if not buffer:
|
||||
buffer = []
|
||||
buffer.append(line)
|
||||
source = "\n".join(buffer)
|
||||
|
||||
return self.needMoreForCode(source)
|
||||
|
||||
def addExec(self, line):
|
||||
|
||||
def addExec(self, command):
|
||||
original_in = sys.stdin
|
||||
try:
|
||||
help = None
|
||||
@@ -203,7 +210,7 @@ class BaseInterpreterInterface:
|
||||
|
||||
try:
|
||||
self.startExec()
|
||||
more = self.doAddExec(line)
|
||||
more = self.doAddExec(command)
|
||||
self.finishExec()
|
||||
finally:
|
||||
if help is not None:
|
||||
@@ -229,7 +236,7 @@ class BaseInterpreterInterface:
|
||||
return more, need_input
|
||||
|
||||
|
||||
def doAddExec(self, line):
|
||||
def doAddExec(self, command):
|
||||
'''
|
||||
Subclasses should override.
|
||||
|
||||
@@ -309,14 +316,22 @@ class BaseInterpreterInterface:
|
||||
|
||||
def execLine(self, line):
|
||||
try:
|
||||
#buffer = self.interpreter.buffer[:]
|
||||
self.exec_queue.put(line)
|
||||
self.exec_queue.put(ExecCode(line, True))
|
||||
return self.needMore(self.buffer, line)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def execMultipleLines(self, lines):
|
||||
try:
|
||||
self.exec_queue.put(ExecCode(lines, False))
|
||||
return self.needMoreForCode(lines)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def interrupt(self):
|
||||
try:
|
||||
if self.interruptable:
|
||||
|
||||
@@ -39,14 +39,14 @@ class InterpreterInterface(BaseInterpreterInterface):
|
||||
def get_greeting_msg(self):
|
||||
return self.interpreter.get_greeting_msg()
|
||||
|
||||
def doAddExec(self, line):
|
||||
def doAddExec(self, command):
|
||||
self.notify_about_magic()
|
||||
if (line.rstrip().endswith('??')):
|
||||
if (command.rstrip().endswith('??')):
|
||||
print('IPython-->')
|
||||
try:
|
||||
res = bool(self.interpreter.addExec(line))
|
||||
res = bool(self.interpreter.addExec(command))
|
||||
finally:
|
||||
if (line.rstrip().endswith('??')):
|
||||
if (command.rstrip().endswith('??')):
|
||||
print('<--IPython')
|
||||
|
||||
return res
|
||||
|
||||
@@ -10,7 +10,6 @@ import os
|
||||
import sys
|
||||
|
||||
from pydevd_constants import USE_LIB_COPY
|
||||
from pydevd_utils import *
|
||||
|
||||
if USE_LIB_COPY:
|
||||
import _pydev_threading as threading
|
||||
@@ -72,56 +71,25 @@ try:
|
||||
except ImportError:
|
||||
import _pydev_xmlrpclib as xmlrpclib
|
||||
|
||||
try:
|
||||
class ExecState:
|
||||
FIRST_CALL = True
|
||||
PYDEV_CONSOLE_RUN_IN_UI = False #Defines if we should run commands in the UI thread.
|
||||
|
||||
from org.python.pydev.core.uiutils import RunInUiThread #@UnresolvedImport
|
||||
from java.lang import Runnable #@UnresolvedImport
|
||||
class Command:
|
||||
def __init__(self, interpreter, command):
|
||||
"""
|
||||
:type command: object
|
||||
:type interpreter: InteractiveConsole
|
||||
"""
|
||||
self.interpreter = interpreter
|
||||
self.command = command
|
||||
self.more = None
|
||||
|
||||
class Command(Runnable):
|
||||
def __init__(self, interpreter, line):
|
||||
self.interpreter = interpreter
|
||||
self.line = line
|
||||
|
||||
def run(self):
|
||||
if ExecState.FIRST_CALL:
|
||||
ExecState.FIRST_CALL = False
|
||||
sys.stdout.write('\nYou are now in a console within Eclipse.\nUse it with care as it can halt the VM.\n')
|
||||
sys.stdout.write(
|
||||
'Typing a line with "PYDEV_CONSOLE_TOGGLE_RUN_IN_UI"\nwill start executing all the commands in the UI thread.\n\n')
|
||||
|
||||
if self.line == 'PYDEV_CONSOLE_TOGGLE_RUN_IN_UI':
|
||||
ExecState.PYDEV_CONSOLE_RUN_IN_UI = not ExecState.PYDEV_CONSOLE_RUN_IN_UI
|
||||
if ExecState.PYDEV_CONSOLE_RUN_IN_UI:
|
||||
sys.stdout.write(
|
||||
'Running commands in UI mode. WARNING: using sys.stdin (i.e.: calling raw_input()) WILL HALT ECLIPSE.\n')
|
||||
else:
|
||||
sys.stdout.write('No longer running commands in UI mode.\n')
|
||||
self.more = False
|
||||
else:
|
||||
self.more = self.interpreter.push(self.line)
|
||||
|
||||
|
||||
def Sync(runnable):
|
||||
if ExecState.PYDEV_CONSOLE_RUN_IN_UI:
|
||||
return RunInUiThread.sync(runnable)
|
||||
def run(self):
|
||||
if self.command.is_single_line:
|
||||
self.more = self.interpreter.push(self.command.code)
|
||||
else:
|
||||
return runnable.run()
|
||||
self.more = self.interpreter.runsource(self.command.code, '<input>', 'exec')
|
||||
|
||||
except:
|
||||
#If things are not there, define a way in which there's no 'real' sync, only the default execution.
|
||||
class Command:
|
||||
def __init__(self, interpreter, line):
|
||||
self.interpreter = interpreter
|
||||
self.line = line
|
||||
|
||||
def run(self):
|
||||
self.more = self.interpreter.push(self.line)
|
||||
|
||||
def Sync(runnable):
|
||||
runnable.run()
|
||||
def Sync(runnable):
|
||||
runnable.run()
|
||||
|
||||
try:
|
||||
try:
|
||||
@@ -152,8 +120,8 @@ class InterpreterInterface(BaseInterpreterInterface):
|
||||
self._input_error_printed = False
|
||||
|
||||
|
||||
def doAddExec(self, line):
|
||||
command = Command(self.interpreter, line)
|
||||
def doAddExec(self, command):
|
||||
command = Command(self.interpreter, command)
|
||||
Sync(command)
|
||||
return command.more
|
||||
|
||||
@@ -185,11 +153,11 @@ def process_exec_queue(interpreter):
|
||||
while 1:
|
||||
try:
|
||||
try:
|
||||
line = interpreter.exec_queue.get(block=True, timeout=0.05)
|
||||
command = interpreter.exec_queue.get(block=True, timeout=0.05)
|
||||
except _queue.Empty:
|
||||
continue
|
||||
|
||||
if not interpreter.addExec(line): #TODO: think about locks here
|
||||
if not interpreter.addExec(command): #TODO: think about locks here
|
||||
interpreter.buffer = []
|
||||
except KeyboardInterrupt:
|
||||
interpreter.buffer = []
|
||||
@@ -274,6 +242,7 @@ def start_server(host, port, interpreter):
|
||||
raise
|
||||
|
||||
server.register_function(interpreter.execLine)
|
||||
server.register_function(interpreter.execMultipleLines)
|
||||
server.register_function(interpreter.getCompletions)
|
||||
server.register_function(interpreter.getFrame)
|
||||
server.register_function(interpreter.getVariable)
|
||||
|
||||
@@ -18,7 +18,7 @@ public interface ConsoleCommunication {
|
||||
|
||||
boolean isExecuting();
|
||||
|
||||
void execInterpreter(String s, Function<InterpreterResponse, Object> callback);
|
||||
void execInterpreter(ConsoleCodeFragment code, Function<InterpreterResponse, Object> callback);
|
||||
|
||||
void interrupt();
|
||||
|
||||
@@ -27,4 +27,21 @@ public interface ConsoleCommunication {
|
||||
void notifyCommandExecuted();
|
||||
void notifyInputRequested();
|
||||
|
||||
class ConsoleCodeFragment {
|
||||
private final String myText;
|
||||
private final boolean myIsSingleLine;
|
||||
|
||||
public ConsoleCodeFragment(String text, boolean isSingleLine) {
|
||||
myText = text;
|
||||
myIsSingleLine = isSingleLine;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public boolean isSingleLine() {
|
||||
return myIsSingleLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2007 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
|
||||
*******************************************************************************/
|
||||
package com.jetbrains.python.console.pydev;
|
||||
|
||||
import com.intellij.util.Function;
|
||||
|
||||
/**
|
||||
* Interface for the console communication.
|
||||
*
|
||||
* This interface is meant to be the way to communicate with the shell.
|
||||
*/
|
||||
public interface IScriptConsoleCommunication {
|
||||
|
||||
/**
|
||||
* Executes a given command in the interpreter (push a line)
|
||||
*
|
||||
* @param command the command to be executed
|
||||
* @return the response from the interpreter (contains the stdout, stderr, etc).
|
||||
* @throws Exception
|
||||
*/
|
||||
void execInterpreter(String command, Function<InterpreterResponse, Object> onResponseReceived);
|
||||
|
||||
/**
|
||||
* Creates the completions to be applied in the interpreter.
|
||||
*
|
||||
* @param text the text with what should be completed (e.g.: xxx.bar.foo)
|
||||
* @param offset the offset where the completion was requested in the console document
|
||||
* @return a list of proposals that can be applied for the given text.
|
||||
* @throws Exception
|
||||
*/
|
||||
//public ICompletionProposal[] getCompletions(String text, int offset) throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the description to be shown on hover to the user
|
||||
*
|
||||
* @param text the text representing the completion to be applied
|
||||
* @return the description to be shown to the user
|
||||
* @throws Exception
|
||||
*/
|
||||
String getDescription(String text) throws Exception;
|
||||
|
||||
/**
|
||||
* Stops the communication with the server. Should ask the server to terminate at this point.
|
||||
* @throws Exception
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -53,10 +53,11 @@ import java.util.Vector;
|
||||
*
|
||||
* @author Fabio
|
||||
*/
|
||||
public class PydevConsoleCommunication extends AbstractConsoleCommunication implements IScriptConsoleCommunication, XmlRpcHandler,
|
||||
public class PydevConsoleCommunication extends AbstractConsoleCommunication implements XmlRpcHandler,
|
||||
PyFrameAccessor {
|
||||
|
||||
private static final String EXEC_LINE = "execLine";
|
||||
private static final String EXEC_MULTILINE = "execMultipleLines";
|
||||
private static final String GET_COMPLETIONS = "getCompletions";
|
||||
private static final String GET_DESCRIPTION = "getDescription";
|
||||
private static final String GET_FRAME = "getFrame";
|
||||
@@ -64,6 +65,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
private static final String CHANGE_VARIABLE = "changeVariable";
|
||||
private static final String HANDSHAKE = "handshake";
|
||||
private static final String CLOSE = "close";
|
||||
|
||||
/**
|
||||
* XML-RPC client for sending messages to the server.
|
||||
*/
|
||||
@@ -261,12 +263,13 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
/**
|
||||
* Executes the needed command
|
||||
*
|
||||
* @param command
|
||||
* @return a Pair with (null, more) or (error, false)
|
||||
* @throws XmlRpcException
|
||||
*/
|
||||
protected Pair<String, Boolean> exec(final String command) throws XmlRpcException {
|
||||
protected Pair<String, Boolean> exec(final ConsoleCodeFragment command) throws XmlRpcException {
|
||||
setExecuting(true);
|
||||
Object execute = myClient.execute(EXEC_LINE, new Object[]{command});
|
||||
Object execute = myClient.execute(command.isSingleLine() ? EXEC_LINE : EXEC_MULTILINE, new Object[]{command.getText()});
|
||||
|
||||
Object object;
|
||||
if (execute instanceof Vector) {
|
||||
@@ -314,10 +317,10 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
*
|
||||
* @param command the command to be executed in the client
|
||||
*/
|
||||
public void execInterpreter(final String command, final Function<InterpreterResponse, Object> onResponseReceived) {
|
||||
public void execInterpreter(final ConsoleCodeFragment command, final Function<InterpreterResponse, Object> onResponseReceived) {
|
||||
nextResponse = null;
|
||||
if (waitingForInput) {
|
||||
inputReceived = command;
|
||||
inputReceived = command.getText();
|
||||
waitingForInput = false;
|
||||
//the thread that we started in the last exec is still alive if we were waiting for an input.
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ import com.jetbrains.python.console.pydev.InterpreterResponse;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
*/
|
||||
@@ -76,10 +74,11 @@ public class PydevConsoleExecuteActionHandler extends ConsoleExecuteActionHandle
|
||||
processOneLine(text);
|
||||
}
|
||||
else {
|
||||
Scanner s = new Scanner(text);
|
||||
while (s.hasNextLine()) {
|
||||
String line = s.nextLine();
|
||||
processOneLine(line);
|
||||
if (StringUtil.countNewLines(text.trim()) > 0) {
|
||||
executeMultiLine(text);
|
||||
}
|
||||
else {
|
||||
processOneLine(text);
|
||||
}
|
||||
}
|
||||
if (execAnyway && myCurrentIndentSize > 0 && indentBefore == 0) { //if code was indented and we need to exec anyway
|
||||
@@ -87,6 +86,19 @@ public class PydevConsoleExecuteActionHandler extends ConsoleExecuteActionHandle
|
||||
}
|
||||
}
|
||||
|
||||
private void executeMultiLine(@NotNull String text) {
|
||||
if (myInputBuffer == null) {
|
||||
myInputBuffer = new StringBuilder();
|
||||
}
|
||||
|
||||
myInputBuffer.append(text);
|
||||
|
||||
final LanguageConsoleImpl console = myConsoleView.getConsole();
|
||||
final Editor currentEditor = console.getConsoleEditor();
|
||||
|
||||
sendLineToConsole(new ConsoleCommunication.ConsoleCodeFragment(myInputBuffer.toString(), false), null, console, currentEditor);
|
||||
}
|
||||
|
||||
private void processOneLine(String line) {
|
||||
int indentSize = IndentHelperImpl.getIndent(getProject(), PythonFileType.INSTANCE, line, false);
|
||||
line = StringUtil.trimTrailing(line);
|
||||
@@ -174,16 +186,22 @@ public class PydevConsoleExecuteActionHandler extends ConsoleExecuteActionHandle
|
||||
}
|
||||
|
||||
|
||||
sendLineToConsole(new ConsoleCommunication.ConsoleCodeFragment(myInputBuffer.toString(), true), line, console, currentEditor);
|
||||
}
|
||||
|
||||
private void sendLineToConsole(@NotNull final ConsoleCommunication.ConsoleCodeFragment code,
|
||||
@Nullable final String line,
|
||||
@NotNull final LanguageConsoleImpl console,
|
||||
@NotNull final Editor currentEditor) {
|
||||
if (myConsoleCommunication != null) {
|
||||
final boolean waitedForInputBefore = myConsoleCommunication.isWaitingForInput();
|
||||
final String command = myInputBuffer.toString();
|
||||
if (myConsoleCommunication.isWaitingForInput()) {
|
||||
myInputBuffer.setLength(0);
|
||||
}
|
||||
else {
|
||||
executingPrompt(console);
|
||||
}
|
||||
myConsoleCommunication.execInterpreter(command, new Function<InterpreterResponse, Object>() {
|
||||
myConsoleCommunication.execInterpreter(code, new Function<InterpreterResponse, Object>() {
|
||||
public Object fun(final InterpreterResponse interpreterResponse) {
|
||||
// clear
|
||||
myInputBuffer = null;
|
||||
@@ -192,7 +210,8 @@ public class PydevConsoleExecuteActionHandler extends ConsoleExecuteActionHandle
|
||||
more(console, currentEditor);
|
||||
if (myCurrentIndentSize == 0) {
|
||||
// compute current indentation
|
||||
setCurrentIndentSize(IndentHelperImpl.getIndent(getProject(), PythonFileType.INSTANCE, line, false) + getPythonIndent());
|
||||
setCurrentIndentSize(
|
||||
(line != null ? IndentHelperImpl.getIndent(getProject(), PythonFileType.INSTANCE, line, false) : 0) + getPythonIndent());
|
||||
// In this case we can insert indent automatically
|
||||
indentEditor(currentEditor, myCurrentIndentSize);
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void exec(final String command, final ProcessDebugger.DebugCallback<Pair<String, Boolean>> callback) {
|
||||
myDebugProcess.consoleExec(command, new ProcessDebugger.DebugCallback<String>() {
|
||||
protected void exec(final ConsoleCodeFragment command, final ProcessDebugger.DebugCallback<Pair<String, Boolean>> callback) {
|
||||
myDebugProcess.consoleExec(command.getText(), new ProcessDebugger.DebugCallback<String>() {
|
||||
@Override
|
||||
public void ok(String value) {
|
||||
callback.ok(parseExecResponseString(value));
|
||||
@@ -77,9 +77,9 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
|
||||
});
|
||||
}
|
||||
|
||||
public void execInterpreter(String s, final Function<InterpreterResponse, Object> callback) {
|
||||
myExpression.append(s);
|
||||
exec(myExpression.toString(), new ProcessDebugger.DebugCallback<Pair<String, Boolean>>() {
|
||||
public void execInterpreter(ConsoleCodeFragment code, final Function<InterpreterResponse, Object> callback) {
|
||||
myExpression.append(code.getText());
|
||||
exec(new ConsoleCodeFragment(myExpression.toString(), false), new ProcessDebugger.DebugCallback<Pair<String, Boolean>>() {
|
||||
@Override
|
||||
public void ok(Pair<String, Boolean> executed) {
|
||||
boolean more = executed.second;
|
||||
|
||||
Reference in New Issue
Block a user