[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