[education/rkward] /: Allow to _not_ be notified about certain symbol changes (those that originated in the frontend, and should not be synced both ways).
Thomas Friedrichsmeier
null at kde.org
Thu May 26 10:06:45 BST 2022
Git commit ba67120e52297f32a379fcf67fac25c761feac79 by Thomas Friedrichsmeier.
Committed on 22/05/2022 at 07:41.
Pushed by tfry into branch 'master'.
Allow to _not_ be notified about certain symbol changes (those that originated in the frontend, and should not be synced both ways).
Also merge master. (Accidentally in the same commit, and to difficult to sort out)
M +3 -0 ChangeLog
M +1 -1 VERSION.cmake
M +1 -0 rkward/core/rcontainerobject.cpp
M +7 -2 rkward/core/rkrownames.cpp
M +16 -6 rkward/core/rkvariable.cpp
M +12 -0 rkward/core/robject.cpp
M +2 -0 rkward/core/robject.h
M +13 -4 rkward/dataeditor/rkvareditmodel.cpp
M +7 -0 rkward/rbackend/rcommand.cpp
M +7 -0 rkward/rbackend/rcommand.h
M +5 -1 rkward/rbackend/rkrbackend.cpp
M +1 -0 rkward/rbackend/rkrbackendprotocol_shared.h
M +26 -19 rkward/rbackend/rkrinterface.h
M +17 -0 rkward/rbackend/rkrsupport.cpp
M +2 -0 rkward/rbackend/rkrsupport.h
M +3 -1 rkward/rbackend/rktransmitter.cpp
M +2 -2 rkward/rbackend/rpackages/rkward/DESCRIPTION
https://invent.kde.org/education/rkward/commit/ba67120e52297f32a379fcf67fac25c761feac79
diff --cc ChangeLog
index d3228980,d3228980..2b8ccab1
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,3 -1,3 +1,6 @@@
++- Cache based modification detection
++ - TODO: more testing, check performance impact (while editing data.frame)
++
--- Version 0.7.4 - May-30-2022
- Support "step into" and "finish current" modes in the R debugger window
- When directly upgrading from very old versions (pre 0.6.3, currently), discard existing config settings
diff --cc VERSION.cmake
index 35521b43,8990e133..c5638183
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@@ -1,3 -1,3 +1,3 @@@
# DO NOT CHANGE THIS FILE MANUALLY!
# It will be overwritten by scripts/set_dist_version.sh
- SET(RKVERSION_NUMBER 0.7.3z+0.7.4+devel2)
-SET(RKVERSION_NUMBER 0.7.4z+0.7.5+devel1)
++SET(RKVERSION_NUMBER 0.7.4z+0.7.5+devel2)
diff --cc rkward/core/rcontainerobject.cpp
index 6e5e15d0,6e5e15d0..774142bc
--- a/rkward/core/rcontainerobject.cpp
+++ b/rkward/core/rcontainerobject.cpp
@@@ -316,6 -316,6 +316,7 @@@ void RContainerObject::renameChild (ROb
}
RCommand *command = new RCommand (renameChildCommand (object, new_name), RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
RInterface::issueCommand (command, 0);
object->name = new_name;
diff --cc rkward/core/rkrownames.cpp
index 4b0c95a1,4b0c95a1..23eaaa37
--- a/rkward/core/rkrownames.cpp
+++ b/rkward/core/rkrownames.cpp
@@@ -61,7 -61,7 +61,9 @@@ void RKRowNames::writeData (int from_ro
RK_TRACE (OBJECTS);
if (isSequential ()) {
-- RInterface::issueCommand (getFullName (DefaultObjectNameOptions) + " <- NULL", RCommand::App | RCommand::Sync, QString (), 0,0, chain);
++ RCommand *command = new RCommand(getFullName(DefaultObjectNameOptions) + " <- NULL", RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
} else {
// unfortunately, we always need to write the whole data, as row.names<- does not support indexing.
QString data_string = "c (";
@@@ -73,7 -73,7 +75,10 @@@
}
}
data_string.append (")");
-- RInterface::issueCommand (getFullName (DefaultObjectNameOptions) + " <- " + data_string, RCommand::App | RCommand::Sync, QString (), 0, 0, chain);
++
++ RCommand* command = new RCommand(getFullName(DefaultObjectNameOptions) + " <- " + data_string, RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
}
ChangeSet *set = new ChangeSet;
diff --cc rkward/core/rkvariable.cpp
index 055402dd,055402dd..1b85e8ee
--- a/rkward/core/rkvariable.cpp
+++ b/rkward/core/rkvariable.cpp
@@@ -1,6 -1,6 +1,6 @@@
/*
rkvariable - This file is part of RKWard (https://rkward.kde.org). Created: Thu Aug 12 2004
--SPDX-FileCopyrightText: 2004-2012 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
++SPDX-FileCopyrightText: 2004-2022 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@@ -85,7 -85,7 +85,9 @@@ void RKVariable::setVarType (RObject::R
else if (new_type == RObject::DataLogical) command += "as.logical";
else if (new_type == RObject::DataFactor) command += "as.factor";
command += ')';
-- RInterface::issueCommand (command, RCommand::App | RCommand::Sync, QString ());
++ RCommand *rcommand = new RCommand(command, RCommand::App | RCommand::Sync);
++ rcommand->setUpdatesObject(this);
++ RInterface::issueCommand(rcommand);
if (new_type == RObject::DataFactor) updateValueLabels (); // as.factor resets the "levels"-attribute!
syncDataToR ();
@@@ -364,7 -364,7 +366,9 @@@ void RKVariable::writeInvalidFields (QL
if (!values.isEmpty ()) values.append (",");
}
-- RInterface::issueCommand (".rk.set.invalid.fields (" + getFullName () + ", " + set + values + clear + ')', RCommand::App | RCommand::Sync, QString (), 0,0, chain);
++ RCommand *command = new RCommand(".rk.set.invalid.fields (" + getFullName () + ", " + set + values + clear + ')', RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
if (data->previously_valid != data->invalid_fields.isEmpty ()) {
data->previously_valid = data->invalid_fields.isEmpty ();
@@@ -380,7 -380,7 +384,9 @@@ void RKVariable::writeData (int from_ro
// TODO: try to sync in correct storage mode
if (from_row == to_row) {
-- RInterface::issueCommand (getFullName () + '[' + QString::number (from_row+1) + "] <- " + getRText (from_row), RCommand::App | RCommand::Sync, QString (), 0,0, chain);
++ RCommand *command = new RCommand(getFullName() + '[' + QString::number(from_row+1) + "] <- " + getRText(from_row), RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
if (data->cell_states[from_row] & RKVarEditData::UnsyncedInvalidState) changed_invalids.append (from_row);
} else {
QString data_string = "c (";
@@@ -393,7 -393,7 +399,9 @@@
if (data->cell_states[row] & RKVarEditData::UnsyncedInvalidState) changed_invalids.append (row);
}
data_string.append (")");
-- RInterface::issueCommand (getFullName () + '[' + QString::number (from_row + 1) + ':' + QString::number (to_row + 1) + "] <- " + data_string, RCommand::App | RCommand::Sync, QString (), 0,0, chain);
++ RCommand* command = new RCommand(getFullName() + '[' + QString::number(from_row + 1) + ':' + QString::number(to_row + 1) + "] <- " + data_string, RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
}
if (!changed_invalids.isEmpty ()) writeInvalidFields (changed_invalids, chain);
@@@ -758,7 -758,7 +766,9 @@@ void RKVariable::writeValueLabels (RCom
level_string = "NULL";
}
-- RInterface::issueCommand (".rk.set.levels (" + getFullName () + ", " + level_string + ')', RCommand::App | RCommand::Sync, QString (), 0, 0, chain);
++ RCommand* command = new RCommand(".rk.set.levels(" + getFullName() + ", " + level_string + ')', RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
++ RInterface::issueCommand(command, chain);
}
QString RKVariable::getValueLabelString () const {
diff --cc rkward/core/robject.cpp
index 028b8d7b,028b8d7b..f7e2d6eb
--- a/rkward/core/robject.cpp
+++ b/rkward/core/robject.cpp
@@@ -202,6 -202,6 +202,7 @@@ void RObject::writeMetaData (RCommandCh
}
RCommand *command = new RCommand (".rk.set.meta (" + getFullName () + ", " + map_string + ')', RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(this);
RInterface::issueCommand (command, chain);
}
@@@ -780,6 -780,6 +781,17 @@@ REnvironmentObject* RObject::toplevelEn
return static_cast<REnvironmentObject*> (o);
}
++RObject *RObject::globalEnvSymbol() const {
++ RK_TRACE (OBJECTS);
++ RObject *o = const_cast<RObject*>(this); // it's ok, all we need to do is find the toplevel parent
++ while (o->parent) {
++ if (o->parent == RObjectList::getGlobalEnv()) return o;
++ o = o->parent;
++ }
++ RK_ASSERT(false);
++ return nullptr;
++}
++
bool RObject::isInGlobalEnv () const {
RK_TRACE (OBJECTS);
diff --cc rkward/core/robject.h
index 37ba6554,37ba6554..12135a80
--- a/rkward/core/robject.h
+++ b/rkward/core/robject.h
@@@ -152,6 -152,6 +152,8 @@@ public
bool isInGlobalEnv () const;
/** returns the toplevel environment that this object is in. May the same as the object. */
REnvironmentObject *toplevelEnvironment () const;
++/** returns the R symbol this object belongs to. E.g. for mylist$sublist$vector returns mylist. May be the same as the object. Behavior should be assumed undefined for object outside of globalenv() */
++ RObject *globalEnvSymbol() const;
void rename (const QString &new_short_name);
void remove (bool removed_in_workspace);
diff --cc rkward/dataeditor/rkvareditmodel.cpp
index ef719692,ef719692..657736bb
--- a/rkward/dataeditor/rkvareditmodel.cpp
+++ b/rkward/dataeditor/rkvareditmodel.cpp
@@@ -847,7 -847,7 +847,9 @@@ bool RKVarEditDataFrameModel::insertCol
RK_ASSERT (obj->isVariable ());
// addObject (col, obj); // the object will be added via RKModificationTracker::addObject -> this::childAdded. That will also take care of calling beginInsertColumns()/endInsertColumns()
-- RInterface::issueCommand (new RCommand (".rk.data.frame.insert.column (" + dataframe->getFullName () + ", \"" + obj->getShortName () + "\", " + QString::number (col+1-var_col_offset) + ")", RCommand::App | RCommand::Sync));
++ RCommand* command = new RCommand(".rk.data.frame.insert.column (" + dataframe->getFullName() + ", \"" + obj->getShortName() + "\", " + QString::number(col+1-var_col_offset) + ")", RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(dataframe);
++ RInterface::issueCommand(command);
}
return true;
@@@ -879,7 -879,7 +881,9 @@@ void RKVarEditDataFrameModel::doInsertR
// TODO: most of the time we're only adding one row at a time, still we should have a function to add multiple rows at once.
for (int i = row; i < row + count; ++i) {
-- RInterface::issueCommand (new RCommand (".rk.data.frame.insert.row (" + dataframe->getFullName () + ", " + QString::number (i+1) + ')', RCommand::App | RCommand::Sync));
++ RCommand* command = new RCommand(".rk.data.frame.insert.row(" + dataframe->getFullName() + ", " + QString::number(i+1) + ')', RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(dataframe);
++ RInterface::issueCommand(command);
}
}
@@@ -887,7 -887,7 +891,9 @@@ void RKVarEditDataFrameModel::doRemoveR
RK_TRACE (EDITOR);
for (int i = row + count - 1; i >= row; --i) {
-- RInterface::issueCommand (new RCommand (".rk.data.frame.delete.row (" + dataframe->getFullName () + ", " + QString::number (i+1) + ')', RCommand::App | RCommand::Sync));
++ RCommand* command = new RCommand(".rk.data.frame.delete.row(" + dataframe->getFullName() + ", " + QString::number(i+1) + ')', RCommand::App | RCommand::Sync);
++ command->setUpdatesObject(dataframe);
++ RInterface::issueCommand(command);
}
}
@@@ -962,7 -962,7 +968,10 @@@ void RKVarEditDataFrameModel::pushTabl
command.append (")");
// push all children
-- RInterface::issueCommand (new RCommand (command, RCommand::Sync), sync_chain);
++ RCommand* rcommand = new RCommand(command, RCommand::Sync);
++ rcommand->setUpdatesObject(dataframe);
++ RInterface::issueCommand(rcommand, sync_chain);
++
for (int col=0; col < objects.size (); ++col) {
objects[col]->restore (sync_chain);
}
diff --cc rkward/rbackend/rcommand.cpp
index 36961fa8,36961fa8..fc275039
--- a/rkward/rbackend/rcommand.cpp
+++ b/rkward/rbackend/rcommand.cpp
@@@ -181,6 -181,6 +181,12 @@@ QString RCommand::fullOutput () const
return ret;
}
++void RCommand::setUpdatesObject(const RObject *object) {
++ RK_TRACE(RBACKEND);
++ RK_ASSERT(_updated_object.isNull());
++ _updated_object = object->globalEnvSymbol()->getShortName();
++}
++
QString RCommand::remainingCommand () const {
RK_TRACE (RBACKEND);
RK_ASSERT (_type & User); // not a grave problem, if it's not, but not useful, either
@@@ -208,6 -208,6 +214,7 @@@ RCommandProxy* RCommand::makeProxy () c
RK_ASSERT (getDataType () == RData::NoData);
RCommandProxy *ret = new RCommandProxy (_command, _type);
++ ret->updates_object = _updated_object;
ret->id = _id,
ret->status = status;
ret->has_been_run_up_to = has_been_run_up_to;
diff --cc rkward/rbackend/rcommand.h
index fa6d29e9,acbea540..617f0ec8
--- a/rkward/rbackend/rcommand.h
+++ b/rkward/rbackend/rcommand.h
@@@ -19,6 -19,6 +19,7 @@@ SPDX-License-Identifier: GPL-2.0-or-lat
class RCommandReceiver;
class RCommand;
class RCommandProxy;
++class RObject;
/** R Commands can be arranged in a simple chain to make sure they are not interrupted by other commands.
* Also, command may need to run sub-commands.
@@@ -193,6 -193,6 +194,7 @@@ public
ROutputList &getOutput () { return output_list; };
/** modify the command string. DO NOT CALL THIS after the command has been submitted! */
void setCommand (const QString &command) { _command = command; };
++ void setUpdatesObject(const RObject *object);
/** creates a proxy for this RCommand */
RCommandProxy* makeProxy () const;
@@@ -219,6 -223,6 +225,7 @@@ friend class RCommandStackModel
int status;
int has_been_run_up_to;
QString _rk_equiv;
++ QString _updated_object;
int _id;
static int next_id;
RCommandReceiver *receivers[MAX_RECEIVERS_PER_RCOMMAND];
diff --cc rkward/rbackend/rkrbackend.cpp
index 33a4f648,1f819bf7..9934a800
--- a/rkward/rbackend/rkrbackend.cpp
+++ b/rkward/rbackend/rkrbackend.cpp
@@@ -1056,13 -1063,9 +1056,13 @@@ SEXP doCaptureOutput (SEXP mode, SEXP c
SEXP RKStartGraphicsDevice (SEXP width, SEXP height, SEXP pointsize, SEXP family, SEXP bg, SEXP title, SEXP antialias);
SEXP RKD_AdjustSize (SEXP devnum, SEXP id);
-SEXP doWs (SEXP name);
void doPendingPriorityCommands ();
+SEXP checkEnv(SEXP a) {
+ auto res = RKRShadowEnvironment::diffAndUpdate(a);
- return RKRSupport::StringListToSEXP(res.added + res.changed + res.removed);
++ return Rf_list3(RKRSupport::StringListToSEXP(res.added), RKRSupport::StringListToSEXP(res.removed), RKRSupport::StringListToSEXP(res.changed));
+}
+
bool RKRBackend::startR () {
RK_TRACE (RBACKEND);
@@@ -1541,6 -1544,6 +1541,10 @@@ void RKRBackend::commandFinished (bool
current_command->has_been_run_up_to = current_command->command.length () - remainder.length ();
}
++ if (!current_command->updates_object.isEmpty()) {
++ // Update cached value for objects that are known to have been modified, so as to not trigger an additional change notification.
++ RKRShadowEnvironment::updateCacheForGlobalenvSymbol(current_command->updates_object);
++ }
if (check_object_updates_needed || (current_command->type & RCommand::ObjectListUpdate)) {
checkObjectUpdatesNeeded (current_command->type & (RCommand::User | RCommand::ObjectListUpdate));
}
diff --cc rkward/rbackend/rkrbackendprotocol_shared.h
index 750398e7,750398e7..9b1780d2
--- a/rkward/rbackend/rkrbackendprotocol_shared.h
+++ b/rkward/rbackend/rkrbackendprotocol_shared.h
@@@ -123,6 -123,6 +123,7 @@@ friend class RBackendRequest
public: // all these are public for technical reasons, only.
~RCommandProxy ();
QString command;
++ QString updates_object;
int type;
int id;
int status;
diff --cc rkward/rbackend/rkrsupport.cpp
index 1e2190f1,65942829..d13614c5
--- a/rkward/rbackend/rkrsupport.cpp
+++ b/rkward/rbackend/rkrsupport.cpp
@@@ -269,82 -269,3 +269,99 @@@ RData *RKRSupport::SEXPToRData (SEXP fr
return data;
}
+
+SEXP RKRShadowEnvironment::shadowenvbase = nullptr;
+QMap<SEXP, RKRShadowEnvironment*> RKRShadowEnvironment::environments;
+RKRShadowEnvironment* RKRShadowEnvironment::environmentFor(SEXP baseenvir) {
++ RK_TRACE(RBACKEND);
+ // TODO: probably R_GlobalEnv should be special-cased, as this is what we'll check most often (or exclusively?)
+ if (!environments.contains(baseenvir)) {
+ RK_DEBUG(RBACKEND, DL_DEBUG, "creating new shadow environment for %p\n", baseenvir);
+ if (!shadowenvbase) {
+ SEXP rkn = Rf_allocVector(STRSXP, 1);
+ SET_STRING_ELT(rkn, 0, Rf_mkChar("package:rkward"));
+ SEXP rkwardenv = RKRSupport::callSimpleFun(Rf_install("as.environment"), rkn, R_GlobalEnv);
+ RK_ASSERT(Rf_isEnvironment(rkwardenv));
+ SEXP rkwardvars = Rf_eval(Rf_findVar(Rf_install(".rk.variables"), rkwardenv), R_BaseEnv); // NOTE: Rf_eval to resolve promise
+ RK_ASSERT(Rf_isEnvironment(rkwardvars));
+ shadowenvbase = Rf_findVar(Rf_install(".rk.shadow.envs"), rkwardvars);
+ RK_ASSERT(Rf_isEnvironment(shadowenvbase));
+ }
+
+ char name[sizeof(void*)*2+3];
+ sprintf(name, "%p", baseenvir);
+ SEXP tr = Rf_allocVector(LGLSXP, 1);
+ LOGICAL(tr)[0] = true;
+ Rf_defineVar(Rf_install(name), RKRSupport::callSimpleFun2(Rf_install("new.env"), tr, R_EmptyEnv, R_GlobalEnv), shadowenvbase);
+ SEXP shadowenvir = Rf_findVar(Rf_install(name), shadowenvbase);
+ environments.insert(baseenvir, new RKRShadowEnvironment(baseenvir, shadowenvir));
+ }
+ return environments[baseenvir];
+}
+
+static bool nameInList(SEXP needle, SEXP haystack) {
+ int count = Rf_length(haystack);
+ for (int i = 0; i < count; ++i) {
+ if (!strcmp(R_CHAR(needle), R_CHAR(STRING_ELT(haystack, i)))) return true;
+ }
+ return false;
+}
+
++void RKRShadowEnvironment::updateCacheForGlobalenvSymbol(const QString& name) {
++ RK_DEBUG(RBACKEND, DL_DEBUG, "updating cached value for symbol %s", qPrintable(name));
++ environmentFor(R_GlobalEnv)->updateSymbolCache(name);
++}
++
++void RKRShadowEnvironment::updateSymbolCache(const QString& name) {
++ RK_TRACE(RBACKEND);
++ SEXP rname = Rf_installChar(Rf_mkCharCE(name.toUtf8(), CE_UTF8));
++ PROTECT(rname);
++ SEXP symbol_g = Rf_findVar(rname, R_GlobalEnv);
++ PROTECT(symbol_g);
++ Rf_defineVar(rname, symbol_g, shadowenvir);
++ UNPROTECT(2);
++}
++
+RKRShadowEnvironment::Result RKRShadowEnvironment::diffAndUpdate() {
++ RK_TRACE (RBACKEND);
+ Result res;
+
+ SEXP symbols = R_lsInternal(baseenvir, TRUE);
+ PROTECT(symbols);
+ int count = Rf_length(symbols);
+ SEXP symbols2 = R_lsInternal(shadowenvir, TRUE);
+ PROTECT(symbols2);
+ int count2 = Rf_length (symbols2);
+
+ // find the changed symbols, and copy them to the shadow environment
+ for (int i = 0; i < count; ++i) {
+ SEXP name = Rf_installChar(STRING_ELT(symbols, i));
+ PROTECT(name);
+ SEXP main = Rf_findVar(name, baseenvir);
+ SEXP cached = Rf_findVar(name, shadowenvir);
+ if (main != cached) {
+ Rf_defineVar(name, main, shadowenvir);
+ if (/*Rf_isNull(cached) && */ !Rf_isNull(main) && !nameInList(STRING_ELT(symbols, i), symbols2)) {
+ res.added.append(RKRSupport::SEXPToString(name));
+ } else {
+ res.changed.append(RKRSupport::SEXPToString(name));
+ }
+ }
+ UNPROTECT(1);
+ }
+
+ // find the symbols only in the shadow environment (those that were removed)
+ for (int i = 0; i < count2; ++i) {
+ if (!nameInList(STRING_ELT(symbols2, i), symbols)) {
+ res.removed.append(RKRSupport::SEXPToString(Rf_installChar(STRING_ELT(symbols2, i))));
+ R_removeVarFromFrame(Rf_installChar(STRING_ELT(symbols2, i)), shadowenvir);
+ }
+ }
+
+ UNPROTECT(2); // symbols, symbols2
+
+ RK_DEBUG(RBACKEND, DL_DEBUG, "added %s\n", qPrintable(res.added.join(", ")));
+ RK_DEBUG(RBACKEND, DL_DEBUG, "changed %s\n", qPrintable(res.changed.join(", ")));
+ RK_DEBUG(RBACKEND, DL_DEBUG, "removed %s\n", qPrintable(res.removed.join(", ")));
+ return res;
+}
diff --cc rkward/rbackend/rkrsupport.h
index 177d296d,976d387a..84090727
--- a/rkward/rbackend/rkrsupport.h
+++ b/rkward/rbackend/rkrsupport.h
@@@ -35,24 -35,4 +35,26 @@@ namespace RKRSupport
RData* SEXPToRData (SEXP from_exp);
};
+class RKRShadowEnvironment {
+public:
+ struct Result {
+ QStringList added;
+ QStringList removed;
+ QStringList changed;
+ bool isEmpty() const { return added.isEmpty() && removed.isEmpty() && changed.isEmpty(); };
+ };
+ Result diffAndUpdate();
+ static Result diffAndUpdate(SEXP envir) { return environmentFor(envir)->diffAndUpdate(); };
++ static void updateCacheForGlobalenvSymbol(const QString &name);
+private:
+ RKRShadowEnvironment(SEXP baseenvir, SEXP shadowenvir) : baseenvir(baseenvir), shadowenvir(shadowenvir) {};
+ ~RKRShadowEnvironment();
+ static RKRShadowEnvironment* environmentFor(SEXP baseenvir);
++ void updateSymbolCache(const QString &name);
+ SEXP baseenvir;
+ SEXP shadowenvir;
+ static QMap<SEXP, RKRShadowEnvironment*> environments;
+ static SEXP shadowenvbase;
+};
+
#endif
diff --cc rkward/rbackend/rktransmitter.cpp
index 2bed158c,2bed158c..0d9c2960
--- a/rkward/rbackend/rktransmitter.cpp
+++ b/rkward/rbackend/rktransmitter.cpp
@@@ -1,6 -1,6 +1,6 @@@
/*
rktransmitter - This file is part of RKWard (https://rkward.kde.org). Created: Thu Nov 18 2010
--SPDX-FileCopyrightText: 2010-2013 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
++SPDX-FileCopyrightText: 2010-2022 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@@ -159,6 -159,6 +159,7 @@@ void RKRBackendSerializer::serializePro
stream << (qint32) proxy.id;
stream << (qint32) proxy.status;
stream << (qint32) proxy.has_been_run_up_to;
++ stream << proxy.updates_object;
serializeData (proxy, stream);
}
@@@ -179,6 -179,6 +180,7 @@@ RCommandProxy* RKRBackendSerializer::un
ret->status = dummy32;
stream >> dummy32;
ret->has_been_run_up_to = dummy32;
++ stream >> (ret->updates_object);
RData *data = unserializeData (stream);
ret->swallowData (*data);
diff --cc rkward/rbackend/rpackages/rkward/DESCRIPTION
index 8f498d00,0525e70e..5cdb6c31
--- a/rkward/rbackend/rpackages/rkward/DESCRIPTION
+++ b/rkward/rbackend/rpackages/rkward/DESCRIPTION
@@@ -17,8 -17,8 +17,8 @@@ Authors at R: c(person(given="Thomas", fam
email="thomas.friedrichsmeier at ruhr-uni-bochum.de",
role=c("aut")), person(given="the RKWard team",
email="rkward-devel at kde.org", role=c("cre","ctb")))
- Version: 0.7.4
- Date: 2022-05-19
+ Version: 0.7.5
-Date: 2022-05-20
++Date: 2022-05-22
RoxygenNote: 7.1.2
Collate:
'base_overrides.R'
More information about the rkward-tracker
mailing list