[education/rkward] rkward/rbackend: Merge commandFinished() and fetchNextCommand()

Thomas Friedrichsmeier null at kde.org
Sun Sep 14 19:26:16 BST 2025


Git commit 73c0da297e71dd2fb84269fb5e9c696bde13964a by Thomas Friedrichsmeier.
Committed on 12/09/2025 at 19:43.
Pushed by tfry into branch 'master'.

Merge commandFinished() and fetchNextCommand()

M  +21   -31   rkward/rbackend/rkrbackend.cpp
M  +5    -4    rkward/rbackend/rkrbackend.h

https://invent.kde.org/education/rkward/-/commit/73c0da297e71dd2fb84269fb5e9c696bde13964a

diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index 4fdab9673..b9b227b4b 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -250,8 +250,7 @@ void RBusy(int);
 
 static void replCommandFinished() {
 	RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::NoUserCommand;
-	RKRBackend::this_pointer->commandFinished();
-	RKRBackend::this_pointer->handleDeferredInterrupts();
+	RKRBackend::this_pointer->commandFinished(RKRBackend::FetchNextCommand, RKRBackend::CheckObjectUpdatesNeeded);
 }
 
 int RReadConsole(const char *prompt, unsigned char *buf, int buflen, int hist) {
@@ -270,7 +269,7 @@ int RReadConsole(const char *prompt, unsigned char *buf, int buflen, int hist) {
 	if ((!RKRBackend::repl_status.browser_context) && (RKRBackend::repl_status.eval_depth == 0)) {
 		while (true) {
 			if (RKRBackend::this_pointer->isKilled() || (RKRBackend::repl_status.user_command_status == RKRBackend::RKReplStatus::NoUserCommand)) {
-				RCommandProxy *command = RKRBackend::this_pointer->fetchNextCommand();
+				RCommandProxy *command = RKRBackend::this_pointer->current_command;
 				if (!command) {
 					RK_DEBUG(RBACKEND, DL_DEBUG, "returning from REPL");
 					return 0; // jumps out of the event loop!
@@ -278,8 +277,7 @@ int RReadConsole(const char *prompt, unsigned char *buf, int buflen, int hist) {
 
 				if (!(command->type & RCommand::User)) {
 					RKRBackend::this_pointer->runCommand(command);
-					RKRBackend::this_pointer->commandFinished();
-					RKRBackend::this_pointer->handleDeferredInterrupts();
+					RKRBackend::this_pointer->commandFinished(RKRBackend::FetchNextCommand, RKRBackend::CheckObjectUpdatesNeeded);
 				} else {
 					// so, we are about to transmit a new user command, which is quite a complex endeavor...
 					/* Some words about running user commands:
@@ -1323,6 +1321,7 @@ void doPendingPriorityCommands() {
 	RCommandProxy *command = RKRBackend::this_pointer->pending_priority_command;
 	RKRBackend::this_pointer->pending_priority_command = nullptr;
 	if (command) {
+		auto prev_command = RKRBackend::this_pointer->current_command;
 		RK_DEBUG(RBACKEND, DL_DEBUG, "running priority command %s", qPrintable(command->command));
 		{
 			QMutexLocker lock(&RKRBackend::this_pointer->command_flow_mutex);
@@ -1331,15 +1330,11 @@ void doPendingPriorityCommands() {
 		}
 
 		RKRBackend::this_pointer->runCommand(command);
-		// TODO: Oh boy, what a mess. Sending notifications should be split from fetchNextCommand() (which is not appropriate, here)
-		RCommandProxy *previous_command_backup = RKRBackend::this_pointer->previous_command;
-		RKRBackend::this_pointer->commandFinished(false);
-		RKRBackend::this_pointer->previous_command = previous_command_backup;
+		RKRBackend::this_pointer->commandFinished(RKRBackend::NoFetchNextCommand, RKRBackend::NoCheckObjectUpdatesNeeded);
+		RKRBackend::this_pointer->current_command = prev_command;
 		{
-			RBackendRequest req(false, RBackendRequest::CommandOut); // NOTE: We do *NOT* want a reply to this one, and in particular, we do *NOT* want to do
-			                                                         // (recursive) event processing while handling this.
-			req.command = command;
-			RKRBackend::this_pointer->handleRequest(&req);
+			QMutexLocker lock(&RKRBackend::this_pointer->command_flow_mutex);
+			RKRBackend::this_pointer->current_command = prev_command;
 		}
 	}
 }
@@ -1389,14 +1384,13 @@ void RKRBackend::printAndClearCapturedMessages(bool with_header) {
 void RKRBackend::run(const QString &locale_dir, bool setup) {
 	RK_TRACE(RBACKEND);
 	killed = NotKilled;
-	previous_command = nullptr;
 
 	initialize(locale_dir, setup);
 
 	enterEventLoop();
 }
 
-void RKRBackend::commandFinished(bool check_object_updates_needed) {
+RCommandProxy *RKRBackend::commandFinished(FetchCommandMode fetch_next, ObjectUpdateMode check_object_updates_needed) {
 	RK_TRACE(RBACKEND);
 	RK_DEBUG(RBACKEND, DL_DEBUG, "done running command %s, status: %d", qPrintable(current_command->command), current_command->status);
 
@@ -1422,7 +1416,7 @@ void RKRBackend::commandFinished(bool check_object_updates_needed) {
 		checkObjectUpdatesNeeded(current_command->type & (RCommand::User | RCommand::ObjectListUpdate));
 	}
 
-	previous_command = current_command;
+	auto previous_command = current_command;
 
 	{
 		QMutexLocker lock(&command_flow_mutex);
@@ -1432,7 +1426,12 @@ void RKRBackend::commandFinished(bool check_object_updates_needed) {
 		}
 		all_current_commands.pop_back();
 		if (!all_current_commands.isEmpty()) current_command = all_current_commands.last();
+		else current_command = nullptr;
 	}
+
+	RBackendRequest req(fetch_next && !isKilled(), RBackendRequest::CommandOut);
+	req.command = previous_command;
+	return RKRBackend::this_pointer->handleRequest(&req, false);
 }
 
 RCommandProxy *RKRBackend::handleRequest(RBackendRequest *request, bool mayHandleSubstack) {
@@ -1483,9 +1482,7 @@ RCommandProxy *RKRBackend::handleRequest2(RBackendRequest *request, bool mayHand
 
 	while (command) {
 		runCommand(command);
-		commandFinished(false);
-
-		command = fetchNextCommand();
+		command = commandFinished(FetchNextCommand, NoCheckObjectUpdatesNeeded);
 	};
 
 	handleDeferredInterrupts();
@@ -1493,16 +1490,6 @@ RCommandProxy *RKRBackend::handleRequest2(RBackendRequest *request, bool mayHand
 	return nullptr;
 }
 
-RCommandProxy *RKRBackend::fetchNextCommand() {
-	RK_TRACE(RBACKEND);
-
-	RBackendRequest req(!isKilled(), RBackendRequest::CommandOut); // when killed, we do *not* actually wait for the reply, before the request is deleted.
-	req.command = previous_command;
-	previous_command = nullptr;
-
-	return (handleRequest(&req, false));
-}
-
 GenericRRequestResult RKRBackend::doRCallRequest(const QString &call, const QVariant &params, RequestFlags flags) {
 	RK_TRACE(RBACKEND);
 
@@ -1524,7 +1511,10 @@ void RKRBackend::initialize(const QString &locale_dir, bool setup) {
 
 	// in RInterface::RInterface() we have created a fake RCommand to capture all the output/errors during startup. Fetch it
 	repl_status.eval_depth++;
-	fetchNextCommand();
+	{
+		RBackendRequest req(true, RBackendRequest::CommandOut); // fetch the first command (a dummy)
+		handleRequest(&req, false);
+	}
 	RK_ASSERT(current_command);
 
 	startR();
@@ -1573,7 +1563,7 @@ void RKRBackend::initialize(const QString &locale_dir, bool setup) {
 	handleRequest(&req);
 
 	RK_ASSERT(current_command);
-	commandFinished(); // the fake startup command
+	commandFinished(FetchNextCommand, CheckObjectUpdatesNeeded); // the fake startup command
 	repl_status.eval_depth--;
 }
 
diff --git a/rkward/rbackend/rkrbackend.h b/rkward/rbackend/rkrbackend.h
index a7f683bce..9b9f77027 100644
--- a/rkward/rbackend/rkrbackend.h
+++ b/rkward/rbackend/rkrbackend.h
@@ -96,7 +96,6 @@ class RKRBackend : public RKROutputBuffer {
 
 	/** Sends a request to the frontend and returns the result (empty in case of asynchronous requests). */
 	GenericRRequestResult doRCallRequest(const QString &call, const QVariant &args, RequestFlags flags);
-	RCommandProxy *fetchNextCommand();
 
 	/** The command currently being executed. */
 	RCommandProxy *current_command;
@@ -149,7 +148,11 @@ class RKRBackend : public RKROutputBuffer {
 	/** holds a copy of the default R_GlobalContext. Needed to find out, when a browser context has been left. */
 	static void *default_global_context;
 
-	void commandFinished(bool check_object_updates_needed = true);
+	enum FetchCommandMode { NoFetchNextCommand,
+		                    FetchNextCommand };
+	enum ObjectUpdateMode { NoCheckObjectUpdatesNeeded,
+		                    CheckObjectUpdatesNeeded };
+	RCommandProxy *commandFinished(FetchCommandMode fetch_next, ObjectUpdateMode check_object_updates_needed = CheckObjectUpdatesNeeded);
 	/** A list of symbols that have been assigned new values during the current command */
 	QStringList changed_symbol_names;
 	/** the main loop. See \ref RKRBackend for a more detailed description */
@@ -202,8 +205,6 @@ class RKRBackend : public RKROutputBuffer {
 	/** check whether the object list / global environment / individual symbols have changed, and updates them, if needed */
 	void checkObjectUpdatesNeeded(bool check_list);
 	friend void doPendingPriorityCommands();
-	/** The previously executed command. Only non-zero until a new command has been requested. */
-	RCommandProxy *previous_command;
 };
 
 #endif



More information about the rkward-tracker mailing list