[education/rkward] /: Do not repeat completed parts of incomplete statements
Thomas Friedrichsmeier
null at kde.org
Mon Oct 13 21:29:39 BST 2025
Git commit c05d1c14ee03ef254f8aff7a7022577dcc506b11 by Thomas Friedrichsmeier.
Committed on 13/10/2025 at 20:29.
Pushed by tfry into branch 'master'.
Do not repeat completed parts of incomplete statements
M +1 -0 ChangeLog
M +28 -0 rkward/autotests/core_test.cpp
M +1 -0 rkward/rbackend/rkrbackend.cpp
https://invent.kde.org/education/rkward/-/commit/c05d1c14ee03ef254f8aff7a7022577dcc506b11
diff --git a/ChangeLog b/ChangeLog
index 39dc12aed..4e20eedbb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
--- Version 0.8.3 - UNRELEASED
+- Fixed: Parts of a command entered interactively could run twice under specific circumstances
- Fixed: Output window would fail to open, automatically, for certain plugins
- Fixed: Width of "progress" dialogs (showing R output) would exceed screen size depending on configuration
diff --git a/rkward/autotests/core_test.cpp b/rkward/autotests/core_test.cpp
index 76e4091d8..76f1db257 100644
--- a/rkward/autotests/core_test.cpp
+++ b/rkward/autotests/core_test.cpp
@@ -8,6 +8,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include <QActionGroup>
#include <QApplication>
#include <QButtonGroup>
+#include <QClipboard>
#include <QDir>
#include <QElapsedTimer>
#include <QFile>
@@ -441,6 +442,33 @@ class RKWardCoreTest : public QObject {
QVERIFY(consoleout.value(6).contains(u"fourth"_s));
}
+ void partialConsoleCommandTest() {
+ /* Runs
+ * print("X"); if(TRUE) {
+ * print("Y")
+ * }
+ * interactively. Internally, this gets chunked into several commands, the first, up to ';'
+ * running, before the second is complete. We must not repeat the first command in this case! */
+ const auto unique_test_string = u"unique_test_string"_s;
+ const auto unique_inner_string = u"unique_inner_string"_s;
+ RKConsole::mainConsole()->activate(true);
+ // NOTE QTest::keyClicks() does not work well in RKConsole, somehow click don't arrive at the katepart.
+ // Instead, we just use pasting.
+ auto submit = [this](const QString &string) {
+ QApplication::clipboard()->setText(string);
+ RKConsole::mainConsole()->paste();
+ waitForAllFinished();
+ };
+ submit(u"print('%1'); if(TRUE) {\n"_s.arg(unique_test_string));
+ auto consoleout = RKConsole::mainConsole()->getFullContent().join(u'\n');
+ QCOMPARE(consoleout.count(unique_test_string), 2); // Once as command, once as output
+ submit(u"print('%1')\n"_s.arg(unique_inner_string));
+ submit(u"}\n"_s);
+ consoleout = RKConsole::mainConsole()->getFullContent().join(u'\n');
+ QCOMPARE(consoleout.count(unique_test_string), 2); // not repeated, again!
+ QCOMPARE(consoleout.count(unique_inner_string), 2);
+ }
+
void cancelCommandStressTest() {
int cancelled_commands = 0;
int commands_out = 0;
diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index 5712bb0ce..fa0541412 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -333,6 +333,7 @@ int RReadConsole(const char *prompt, unsigned char *buf, int buflen, int hist) {
// int n_frames = RKRSupport::SEXPToInt (RKRSupport::callSimpleFun0 (RFn::Rf_install ("sys.nframe"), ROb(R_GlobalEnv);
if (n_frames < 1) {
// No active frames? This can't be a call to readline(), so the previous command must have finished.
+ RKRBackend::repl_status.user_command_successful_up_to = RKRBackend::repl_status.user_command_transmitted_up_to;
if (RKRBackend::repl_status.user_command_completely_transmitted) {
replCommandFinished();
} else RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandTransmitted;
More information about the rkward-tracker
mailing list