[education/rkward/kf5] rkward: Adjust to the removal of Rf_addTaskCallback() in R (devel) 4.5

Thomas Friedrichsmeier null at kde.org
Tue Apr 22 13:00:59 BST 2025


Git commit 159f5df82776beed3f4f7a4091577db627453520 by Thomas Friedrichsmeier.
Committed on 22/04/2025 at 11:58.
Pushed by tfry into branch 'kf5'.

Adjust to the removal of Rf_addTaskCallback() in R (devel) 4.5

M  +28   -0    rkward/autotests/core_test.cpp
M  +12   -39   rkward/rbackend/rkrbackend.cpp

https://invent.kde.org/education/rkward/-/commit/159f5df82776beed3f4f7a4091577db627453520

diff --git a/rkward/autotests/core_test.cpp b/rkward/autotests/core_test.cpp
index d37e0ed8f..eb0dc9be5 100644
--- a/rkward/autotests/core_test.cpp
+++ b/rkward/autotests/core_test.cpp
@@ -238,6 +238,34 @@ private slots:
 		cleanGlobalenv();
 	}
 
+	void userCommandTest() {
+		// Two commands submitted on one user line should both be run
+		runCommandWithTimeout(new RCommand("print('first'); print('second')", RCommand::User), nullptr, [](RCommand *command) {
+			QVERIFY(!command->failed());
+			QVERIFY(command->fullOutput().contains("first"));
+			QVERIFY(command->fullOutput().contains("second"));
+		});
+		// Also, of course for commands on separate lines:
+		runCommandWithTimeout(new RCommand("print('first')\nprint('second')", RCommand::User), nullptr, [](RCommand *command) {
+			QVERIFY(!command->failed());
+			QVERIFY(command->fullOutput().contains("first"));
+			QVERIFY(command->fullOutput().contains("second"));
+		});
+		// or multi-line commands:
+		runCommandWithTimeout(new RCommand("{ print('first')\nprint('second') }", RCommand::User), nullptr, [](RCommand *command) {
+			QVERIFY(!command->failed());
+			QVERIFY(command->fullOutput().contains("first"));
+			QVERIFY(command->fullOutput().contains("second"));
+		});
+		// However, if a partial command fails, the next part should not get parsed:
+		runCommandWithTimeout(new RCommand("stop('first'); print('second')", RCommand::User), nullptr, [](RCommand *command) {
+			QVERIFY(command->failed());
+			QVERIFY(command->fullOutput().contains("first"));
+			QVERIFY(!command->fullOutput().contains("second"));
+		});
+		// TODO: verify that calls to readline() and browser() are handled, correctly
+	}
+
 	void commandOrderAndOutputTest() {
 		// commands shall run in the order 1, 3, 2, 5, 4, but also, of course, all different types of output shall be captured
 		QStringList output;
diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index ed570ba9a..5cf354060 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -175,38 +175,6 @@ extern "C" void run_Rmainloop (void);
 extern SEXP RKWard_RData_Tag;
 
 // ############## R Standard callback overrides BEGIN ####################
-Rboolean RKToplevelStatementFinishedCallback (SEXP expr, SEXP value, Rboolean succeeded, Rboolean visible, void *) {
-	RK_TRACE (RBACKEND);
-	Q_UNUSED (expr);
-	Q_UNUSED (value);
-	Q_UNUSED (visible);
-
-	if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context)) {		// Yes, toplevel-handlers _do_ get called in a browser context!
-		RK_ASSERT (RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandRunning);
-		if (succeeded) {
-			RKRBackend::repl_status.user_command_successful_up_to = RKRBackend::repl_status.user_command_parsed_up_to;
-			if (RKRBackend::repl_status.user_command_completely_transmitted) {
-				RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::NoUserCommand;
-				RKRBackend::this_pointer->commandFinished ();
-			} else RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandTransmitted;
-		} else {
-			// well, this point of code is never reached with R up to 2.12.0. Instead failed user commands are handled in doError().
-			RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandFailed;
-		}
-	}
-	
-	return (Rboolean) true;
-}
-
-void RKInsertToplevelStatementFinishedCallback (void *) {
-	RK_TRACE (RBACKEND);
-
-	if (RKRBackend::this_pointer->r_running) {
-		int pos;
-		Rf_addTaskCallback (&RKToplevelStatementFinishedCallback, 0, &RKInsertToplevelStatementFinishedCallback, "_rkward_main_callback", &pos);
-	}
-}
-
 void RKTransmitNextUserCommandChunk (unsigned char* buf, int buflen) {
 	RK_TRACE (RBACKEND);
 
@@ -326,7 +294,7 @@ int RReadConsole (const char* prompt, unsigned char* buf, int buflen, int hist)
 				// This can mean three different things:
 				// 1) User called readline ()
 				// 2) User called browser ()
-				// 3) R jumped us back to toplevel behind our backs.
+				// 3) The user command has finished (successfully or not)
 				// Let's find out, which one it is.
 				if (hist && (RKRBackend::default_global_context != R_GlobalContext)) {
 					break;	// this looks like a call to browser(). Will be handled below.
@@ -338,13 +306,13 @@ int RReadConsole (const char* prompt, unsigned char* buf, int buflen, int hist)
 					n_frames = dummy->intVector ().at (0);
 				}
 				// What the ??? Why does this simple version always return 0?
-				//int n_frames = RKRSupport::SEXPToInt (RKRSupport::callSimpleFun0 (Rf_install ("sys.nframe"), R_GlobalEnv));
+				//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(), then, so probably R jumped us back to toplevel, behind our backs.
-					// For safety, let's reset and start over.
-					RKRBackend::this_pointer->current_command->status |= RCommand::Failed | RCommand::ErrorOther;
-					RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::ReplIterationKilled;
-					Rf_error("");	// to discard the buffer
+					// No active frames? This can't be a call to readline(), so the previous command must have finished.
+					if (RKRBackend::repl_status.user_command_completely_transmitted) {
+						RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::NoUserCommand;
+						RKRBackend::this_pointer->commandFinished ();
+					} else RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandTransmitted;
 				} else {
 					// A call to readline(). Will be handled below
 					break;
@@ -1165,9 +1133,14 @@ bool RKRBackend::startR () {
 	R_registerRoutines (R_getEmbeddingDllInfo(), NULL, callMethods, NULL, NULL);
 
 	connectCallbacks();
+<<<<<<< HEAD
 	RKInsertToplevelStatementFinishedCallback (0);
 	RKREventLoop::setRKEventHandler (doPendingPriorityCommands);
 	default_global_context = R_GlobalContext;
+=======
+	RKREventLoop::setRKEventHandler(doPendingPriorityCommands);
+	default_global_context = ROb(R_GlobalContext);
+>>>>>>> 11a555b04 (Adjust to the removal of Rf_addTaskCallback() in R (devel) 4.5)
 #ifdef Q_OS_WIN
 	// See the corresponding note in RWriteConsoleEx(). For auto-detecting UTF8 markers in console output.
 	win_do_detect_winutf8markers = true;



More information about the rkward-tracker mailing list