From e0b6698722947edd4c84e73520db2c2e2f9faa45 Mon Sep 17 00:00:00 2001 From: Mark Ganson TheMarkster <39143564+mwganson@users.noreply.github.com> Date: Sun, 19 Jan 2025 15:36:33 -0600 Subject: [PATCH] [Python console] add Execute in console context menu item (#18716) * [Python console] add Execute in console context menu item * Update src/Gui/PythonEditor.cpp Co-authored-by: Kacper Donat --------- Co-authored-by: Chris Hennes Co-authored-by: Kacper Donat --- src/Gui/PythonEditor.cpp | 73 ++++++++++++++++++++++++++++++++++++++++ src/Gui/PythonEditor.h | 1 + 2 files changed, 74 insertions(+) diff --git a/src/Gui/PythonEditor.cpp b/src/Gui/PythonEditor.cpp index 04f4f5dfc2..3da59a5ce9 100644 --- a/src/Gui/PythonEditor.cpp +++ b/src/Gui/PythonEditor.cpp @@ -25,11 +25,13 @@ # include # include # include +# include # include # include #endif #include +#include #include "PythonEditor.h" #include "Application.h" @@ -77,8 +79,12 @@ PythonEditor::PythonEditor(QWidget* parent) auto uncomment = new QShortcut(this); uncomment->setKey(QKeySequence(QString::fromLatin1("ALT+U"))); + auto execInConsole = new QShortcut(this); + execInConsole->setKey(QKeySequence(QString::fromLatin1("ALT+SHIFT+P"))); + connect(comment, &QShortcut::activated, this, &PythonEditor::onComment); connect(uncomment, &QShortcut::activated, this, &PythonEditor::onUncomment); + connect(execInConsole, &QShortcut::activated, this, &PythonEditor::onExecuteInConsole); } /** Destroys the object and frees any allocated resources */ @@ -172,6 +178,9 @@ void PythonEditor::contextMenuEvent ( QContextMenuEvent * e ) comment->setShortcut(QKeySequence(QString::fromLatin1("ALT+C"))); QAction* uncomment = menu->addAction( tr("Uncomment"), this, &PythonEditor::onUncomment); uncomment->setShortcut(QKeySequence(QString::fromLatin1("ALT+U"))); + QAction* execInConsole = menu->addAction( tr("Execute in console"), + this, &PythonEditor::onExecuteInConsole); + execInConsole->setShortcut(QKeySequence(QString::fromLatin1("ALT+Shift+P"))); } menu->exec(e->globalPos()); @@ -275,6 +284,70 @@ void PythonEditor::onUncomment() cursor.endEditBlock(); } +void PythonEditor::onExecuteInConsole() +{ + QTextCursor cursor = textCursor(); + int selStart = cursor.selectionStart(); + int selEnd = cursor.selectionEnd(); + QTextBlock block; + QString selectedCode; + + for (block = document()->begin(); block.isValid(); block = block.next()) { + int pos = block.position(); + int off = block.length() - 1; + if (pos >= selStart || pos + off >= selStart) { + if (pos + 1 > selEnd) { + break; + } + + QString lineText = block.text(); + selectedCode.append(lineText + QLatin1String("\n")); + } + } + + if (!selectedCode.isEmpty()) { + + /** Dedent the block of code so that the first selected + * line has no indentation, but the remaining lines + * keep their indentation relative to that first line. + */ + + // get the leading whitespace of the first line + QStringList lines = selectedCode.split(QLatin1Char('\n')); + QString firstLineIndent; + for (const QString& line : lines) { + if (!line.isEmpty()) { + int leadingWhitespace = line.indexOf(QRegularExpression(QLatin1String("\\S"))); + if (leadingWhitespace > 0) { + firstLineIndent = line.left(leadingWhitespace); + } + break; + } + } + + // remove that first line whitespace from all the lines + for (QString& line : lines) { + if (!line.isEmpty() && line.startsWith(firstLineIndent)) { + line.remove(0, firstLineIndent.length()); + } + } + + // join the lines into a single QString so we can execute as a single block + QString dedentedCode = lines.join(QLatin1Char('\n')); + + if (!dedentedCode.isEmpty()) { + try { + Gui::Command::doCommand(Gui::Command::Doc, dedentedCode.toStdString().c_str()); + } catch (const Base::Exception& e) { + QString errorMessage = QString::fromStdString(e.what()); + Base::Console().Error("Error executing Python code:\n%s\n", errorMessage.toUtf8().constData()); + } catch (...) { + Base::Console().Error("An unknown error occurred while executing Python code.\n"); + } + } + } +} + // ------------------------------------------------------------------------ namespace Gui { diff --git a/src/Gui/PythonEditor.h b/src/Gui/PythonEditor.h index 432975d9df..d4eb538f7e 100644 --- a/src/Gui/PythonEditor.h +++ b/src/Gui/PythonEditor.h @@ -60,6 +60,7 @@ public Q_SLOTS: * this line is skipped. */ void onUncomment(); + void onExecuteInConsole(); void setFileName(const QString&); void startDebug();