From 657c343ac806514aa140cd261efc10429e07f840 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 20 Nov 2017 15:11:50 +0000 Subject: [PATCH] Support multi-line input in the python shell --- qrenderdoc/Code/pyrenderdoc/PythonContext.cpp | 11 +++++----- qrenderdoc/Code/pyrenderdoc/PythonContext.h | 4 ++-- qrenderdoc/Widgets/Extended/RDLineEdit.cpp | 14 +++++++++++++ qrenderdoc/Widgets/Extended/RDLineEdit.h | 6 ++++++ qrenderdoc/Windows/PythonShell.cpp | 21 ++++++++++++++++--- qrenderdoc/Windows/PythonShell.h | 2 ++ 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index 8db94b8ed..ee78479b8 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -485,7 +485,7 @@ QString PythonContext::versionString() return QFormatStr("%1.%2.%3").arg(PY_MAJOR_VERSION).arg(PY_MINOR_VERSION).arg(PY_MICRO_VERSION); } -void PythonContext::executeString(const QString &filename, const QString &source, bool interactive) +void PythonContext::executeString(const QString &filename, const QString &source) { if(!initialised()) { @@ -501,8 +501,9 @@ void PythonContext::executeString(const QString &filename, const QString &source PyGILState_STATE gil = PyGILState_Ensure(); - PyObject *compiled = Py_CompileString(source.toUtf8().data(), filename.toUtf8().data(), - interactive ? Py_single_input : Py_file_input); + PyObject *compiled = + Py_CompileString(source.toUtf8().data(), filename.toUtf8().data(), + source.count(QLatin1Char('\n')) == 0 ? Py_single_input : Py_file_input); PyObject *ret = NULL; @@ -555,9 +556,9 @@ void PythonContext::executeString(const QString &filename, const QString &source emit exception(typeStr, valueStr, finalLine, frames); } -void PythonContext::executeString(const QString &source, bool interactive) +void PythonContext::executeString(const QString &source) { - executeString(lit(""), source, interactive); + executeString(lit(""), source); } void PythonContext::executeFile(const QString &filename) diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.h b/qrenderdoc/Code/pyrenderdoc/PythonContext.h index 92e0ed300..0a00561e7 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.h +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.h @@ -99,8 +99,8 @@ signals: void textOutput(bool isStdError, const QString &output); public slots: - void executeString(const QString &source, bool interactive = false); - void executeString(const QString &filename, const QString &source, bool interactive = false); + void executeString(const QString &source); + void executeString(const QString &filename, const QString &source); void executeFile(const QString &filename); void setGlobal(const char *varName, const char *typeName, void *object); void setPyGlobal(const char *varName, PyObject *object); diff --git a/qrenderdoc/Widgets/Extended/RDLineEdit.cpp b/qrenderdoc/Widgets/Extended/RDLineEdit.cpp index 8152cdee3..eb19d106c 100644 --- a/qrenderdoc/Widgets/Extended/RDLineEdit.cpp +++ b/qrenderdoc/Widgets/Extended/RDLineEdit.cpp @@ -49,3 +49,17 @@ void RDLineEdit::keyPressEvent(QKeyEvent *e) QLineEdit::keyPressEvent(e); emit(keyPress(e)); } + +bool RDLineEdit::event(QEvent *e) +{ + if(m_acceptTabs && e->type() == QEvent::KeyPress) + { + QKeyEvent *ke = (QKeyEvent *)e; + if(ke->key() == Qt::Key_Tab) + { + insert(lit("\t")); + return true; + } + } + return QLineEdit::event(e); +} diff --git a/qrenderdoc/Widgets/Extended/RDLineEdit.h b/qrenderdoc/Widgets/Extended/RDLineEdit.h index 8c99ebe62..523c9da06 100644 --- a/qrenderdoc/Widgets/Extended/RDLineEdit.h +++ b/qrenderdoc/Widgets/Extended/RDLineEdit.h @@ -33,6 +33,8 @@ public: explicit RDLineEdit(QWidget *parent = 0); ~RDLineEdit(); + void setAcceptTabCharacters(bool accept) { m_acceptTabs = accept; } + bool acceptTabCharacters() { return m_acceptTabs; } signals: void enter(); void leave(); @@ -44,4 +46,8 @@ protected: void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void keyPressEvent(QKeyEvent *e); + bool event(QEvent *e); + +private: + bool m_acceptTabs; }; diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 655c90a2f..5c5ddf72b 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -447,6 +447,8 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent) ui->interactiveOutput->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); ui->scriptOutput->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + ui->lineInput->setAcceptTabCharacters(true); + scriptEditor = new ScintillaEdit(this); scriptEditor->styleSetFont( @@ -513,14 +515,27 @@ void PythonShell::on_execute_clicked() appendText(ui->interactiveOutput, command + lit("\n")); - if(command.trimmed().length() > 0) - interactiveContext->executeString(command, true); - history.push_front(command); historyidx = -1; ui->lineInput->clear(); + // assume a trailing colon means there will be continuation. Store the command and add a continue + // prompt. If we're already continuing, then wait until we get a blank line before executing. + if(command.trimmed().right(1) == lit(":") || (!m_storedLines.isEmpty() && !command.isEmpty())) + { + appendText(ui->interactiveOutput, lit(".. ")); + m_storedLines += command + lit("\n"); + return; + } + + // concatenate any previous lines if we are doing a multi-line command. + command = m_storedLines + command; + m_storedLines = QString(); + + if(command.trimmed().length() > 0) + interactiveContext->executeString(command); + appendText(ui->interactiveOutput, lit(">> ")); } diff --git a/qrenderdoc/Windows/PythonShell.h b/qrenderdoc/Windows/PythonShell.h index 48810c74c..ba02f75e7 100644 --- a/qrenderdoc/Windows/PythonShell.h +++ b/qrenderdoc/Windows/PythonShell.h @@ -79,6 +79,8 @@ private: QList history; int historyidx = -1; + QString m_storedLines; + PythonContext *newContext(); QString scriptHeader();