[education/rkward] rkward/rbackend: Do not rely on options(error) for error detection

Thomas Friedrichsmeier null at kde.org
Wed Sep 3 06:48:52 BST 2025


Git commit e4331458589b1eb37a48dba72520543031258a5c by Thomas Friedrichsmeier.
Committed on 01/09/2025 at 15:41.
Pushed by tfry into branch 'master'.

Do not rely on options(error) for error detection

M  +1    -1    rkward/rbackend/rkrapi.h
M  +33   -38   rkward/rbackend/rkrbackend.cpp

https://invent.kde.org/education/rkward/-/commit/e4331458589b1eb37a48dba72520543031258a5c

diff --git a/rkward/rbackend/rkrapi.h b/rkward/rbackend/rkrapi.h
index c9fbe82ae..0095c4cd2 100644
--- a/rkward/rbackend/rkrapi.h
+++ b/rkward/rbackend/rkrapi.h
@@ -341,7 +341,7 @@ class RFn : public QObject {
 	IMPORT_R_API(R_Outputfile);
 #else
 	IMPORT_R_API(R_ProcessEvents);
-	IMPORT_R_API(R_DefParams);
+	IMPORT_R_API(R_DefParamsEx);
 	IMPORT_R_API(R_SetParams);
 	IMPORT_R_API(R_setStartTime);
 	IMPORT_R_API(R_set_command_line_arguments);
diff --git a/rkward/rbackend/rkrbackend.cpp b/rkward/rbackend/rkrbackend.cpp
index b4e51548c..c6f2700b8 100644
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@ -735,6 +735,33 @@ void RBusy(int busy) {
 	}
 }
 
+void RResetConsole() {
+	RK_TRACE(RBACKEND);
+
+	if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context) && (!RKRBackend::this_pointer->isKilled()) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::NoUserCommand)) {
+		RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandFailed;
+	}
+	if (RKRBackend::repl_status.interrupted) {
+		// it is unlikely, but possible, that an interrupt signal was received, but the current command failed for some other reason, before processing was actually interrupted. In this case, R_interrupts_pending is not yet cleared.
+		// NOTE: if R_interrupts_pending stops being exported one day, we might be able to use R_CheckUserInterrupt() inside an R_ToplevelExec() to find out, whether an interrupt was still pending.
+#ifdef Q_OS_WIN
+		if (!ROb(UserBreak)) {
+#else
+		if (!ROb(R_interrupts_pending)) {
+#endif
+			RKRBackend::repl_status.interrupted = false;
+			if (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) { // was interrupted only to step out of the repl iteration
+				QMutexLocker lock(&(RKRBackend::this_pointer->all_current_commands_mutex));
+				for (RCommandProxy *command : std::as_const(RKRBackend::this_pointer->all_current_commands))
+					command->status |= RCommand::Canceled;
+				RK_DEBUG(RBACKEND, DL_DEBUG, "interrupted");
+			}
+		}
+	} else if (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) {
+		RK_DEBUG(RBACKEND, DL_DEBUG, "error in user command");
+	}
+}
+
 // ############## R Standard callback overrides END ####################
 
 SEXP doUpdateLocale();
@@ -758,30 +785,27 @@ void RKRBackend::setupCallbacks() {
 	RK_TRACE(RBACKEND);
 
 	RFn::R_setStartTime();
-	RFn::R_DefParams(&RK_R_Params);
+	RFn::R_DefParamsEx(&RK_R_Params, /* RSTART_VERSION */ 1);
 
 	// IMPORTANT: see also the #ifndef QS_WS_WIN-portion!
 	RK_R_Params.rhome = RFn::get_R_HOME();
 	RK_R_Params.home = RFn::getRUser();
 	RK_R_Params.CharacterMode = RGui;
 	RK_R_Params.ShowMessage = RShowMessage;
-#	if R_VERSION < R_Version(4, 2, 0)
-	RK_R_Params.ReadConsole = RReadConsoleWin;
-#	else
 	RK_R_Params.ReadConsole = RReadConsole;
-#	endif
 	RK_R_Params.WriteConsoleEx = RWriteConsoleEx;
-	RK_R_Params.WriteConsole = 0;
+	RK_R_Params.WriteConsole = nullptr;
 	RK_R_Params.CallBack = RKREventLoop::winRKEventHandlerWrapper;
 	RK_R_Params.YesNoCancel = RAskYesNoCancel;
 	RK_R_Params.Busy = RBusy;
+	RK_R_Params.ResetConsole = RResetConsole;
 
 	// TODO: callback mechanism(s) for ChosseFile, ShowFiles, EditFiles
 	// TODO: also for RSuicide (Less important, obviously, since this should not be triggered, in normal operation).
 	// NOTE: For RCleanUp see RReadConsole RCleanup?
 
-	RK_R_Params.R_Quiet = (Rboolean)0;
-	RK_R_Params.R_Interactive = (Rboolean)1;
+	RK_R_Params.R_Quiet = 0;
+	RK_R_Params.R_Interactive = 1;
 }
 
 void RKRBackend::connectCallbacks() {
@@ -810,7 +834,7 @@ void RKRBackend::connectCallbacks() {
 	ROb(ptr_R_ReadConsole) = RReadConsole;
 	ROb(ptr_R_WriteConsoleEx) = RWriteConsoleEx;
 	ROb(ptr_R_WriteConsole) = nullptr;
-	ROb(ptr_R_ResetConsole) = RDoNothing;
+	ROb(ptr_R_ResetConsole) = RResetConsole;
 	ROb(ptr_R_FlushConsole) = RDoNothing;
 	ROb(ptr_R_ClearerrConsole) = RDoNothing;
 	ROb(ptr_R_Busy) = RBusy;
@@ -833,35 +857,6 @@ RKRBackend::~RKRBackend() {
 	RK_TRACE(RBACKEND);
 }
 
-void doError(const QString &callstring) {
-	RK_TRACE(RBACKEND);
-
-	if ((RKRBackend::repl_status.eval_depth == 0) && (!RKRBackend::repl_status.browser_context) && (!RKRBackend::this_pointer->isKilled()) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) && (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::NoUserCommand)) {
-		RKRBackend::repl_status.user_command_status = RKRBackend::RKReplStatus::UserCommandFailed;
-		RK_DEBUG(RBACKEND, DL_DEBUG, "user command failed");
-	}
-	if (RKRBackend::repl_status.interrupted) {
-		// it is unlikely, but possible, that an interrupt signal was received, but the current command failed for some other reason, before processing was actually interrupted. In this case, R_interrupts_pending is not yet cleared.
-		// NOTE: if R_interrupts_pending stops being exported one day, we might be able to use R_CheckUserInterrupt() inside an R_ToplevelExec() to find out, whether an interrupt was still pending.
-#ifdef Q_OS_WIN
-		if (!ROb(UserBreak)) {
-#else
-		if (!ROb(R_interrupts_pending)) {
-#endif
-			RKRBackend::repl_status.interrupted = false;
-			if (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) { // was interrupted only to step out of the repl iteration
-				QMutexLocker lock(&(RKRBackend::this_pointer->all_current_commands_mutex));
-				for (RCommandProxy *command : std::as_const(RKRBackend::this_pointer->all_current_commands))
-					command->status |= RCommand::Canceled;
-				RK_DEBUG(RBACKEND, DL_DEBUG, "interrupted");
-			}
-		}
-	} else if (RKRBackend::repl_status.user_command_status != RKRBackend::RKReplStatus::ReplIterationKilled) {
-		RKRBackend::this_pointer->handleOutput(callstring, callstring.length(), ROutput::Error);
-		RK_DEBUG(RBACKEND, DL_DEBUG, "error '%s'", qPrintable(callstring));
-	}
-}
-
 // TODO: Pass nested/sync as a single enum value, in the first place
 SEXP doRCall(SEXP _call, SEXP _args, SEXP _sync, SEXP _nested) {
 	RK_TRACE(RBACKEND);



More information about the rkward-tracker mailing list