[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