Commit bb1c5b0c authored by Thomas Friedrichsmeier's avatar Thomas Friedrichsmeier
Browse files

Separate object search, and completion name generation. Now all we still need...

Separate object search, and completion name generation. Now all we still need is a UI for configuration.
parent 3853d1ff
......@@ -2,7 +2,7 @@
rcontainerobject - description
-------------------
begin : Thu Aug 19 2004
copyright : (C) 2004-2013 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -260,33 +260,35 @@ void RContainerObject::updateRowNamesObject () {
}
}
RObject *RContainerObject::findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) {
RObject::ObjectList RContainerObject::findObjects (const QStringList &path, bool partial, const QString &op) {
RK_TRACE (OBJECTS);
fetchMoreIfNeeded ();
if (op != "$") return RObject::findObjects (path, matches, op);
if (op != "$") return RObject::findObjects (path, partial, op);
if (path.length () > 1) {
RObject* found = findChildByName (path.value (0));
if (found) return found->findObjects (path.mid (2), matches, path.value (1));
if (found) return found->findObjects (path.mid (2), partial, path.value (1));
} else {
if (!matches) return findChildByName (path.value (0));
QString partial = path.value (0);
for (int i = 0; i < childmap.size (); ++i) {
RObject* child = childmap[i];
if (partial.isEmpty () || child->getShortName ().startsWith (partial)) {
QString base_name = child->getFullName (DefaultObjectNameOptions - (DefaultObjectNameOptions & IncludeEnvirIfNotGlobalEnv));
if (matches->contains (base_name) || irregularShortName (base_name)) {
matches->insert (child->getFullName (), child);
} else {
matches->insert (base_name, child);
RObject::ObjectList ret;
if (!partial) {
RObject* found = findChildByName (path.value (0));
if (found) ret.append (found);
} else {
QString partial_name = path.value (0);
if (partial_name.isEmpty ()) {
ret = childmap;
} else {
for (int i = 0; i < childmap.size (); ++i) {
RObject* child = childmap[i];
if (child->getShortName ().startsWith (partial_name)) ret.append (child);
}
}
}
return ret;
}
return 0;
return RObject::ObjectList();
}
RObject *RContainerObject::createPendingChild (const QString &name, int position, bool container, bool data_frame) {
......
......@@ -2,7 +2,7 @@
rcontainerobject - description
-------------------
begin : Thu Aug 19 2004
copyright : (C) 2004-2013 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -72,7 +72,7 @@ private:
void updateRowNamesObject ();
protected:
/** reimplemented from RObject to actually search for matching objects among the children */
RObject *findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) override;
RObject::ObjectList findObjects (const QStringList &path, bool partial, const QString &op) override;
void updateChildren (RData *new_children);
RObjectMap childmap;
......
......@@ -2,7 +2,7 @@
renvironmentobject - description
-------------------
begin : Wed Sep 27 2006
copyright : (C) 2006, 2009, 2010, 2011, 2015 by Thomas Friedrichsmeier
copyright : (C) 2006-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -79,8 +79,8 @@ QString REnvironmentObject::makeChildName (const QString &short_child_name, bool
safe_name = rQuote (short_child_name);
} else safe_name = short_child_name;
if (type & GlobalEnv) { // don't print as ".GlobalEnv$something" unless childname needs fixing
if (irregular) return (getShortName () + '$' + safe_name);
if (type & GlobalEnv) { // don't print as ".GlobalEnv$something" unless asked to, or childname needs fixing
if (irregular || (options & IncludeEnvirForGlobalEnv)) return (getShortName () + '$' + safe_name);
return (safe_name);
}
if (type & ToplevelEnv) {
......
......@@ -2,7 +2,7 @@
robject - description
-------------------
begin : Thu Aug 19 2004
copyright : (C) 2004-2016 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -81,13 +81,13 @@ QString RObject::getLabel () const {
return getMetaProperty ("label");
}
RObject* RObject::findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) {
RObject::ObjectList RObject::findObjects (const QStringList &path, bool partial, const QString &op) {
RK_TRACE (OBJECTS);
// not a container
if (op == "@") {
if (slotsPseudoObject ()) return (slotsPseudoObject ()->findObjects (path, matches, "$"));
if (slotsPseudoObject ()) return (slotsPseudoObject ()->findObjects (path, partial, "$"));
}
return 0;
return ObjectList();
}
QString RObject::getMetaProperty (const QString &id) const {
......
......@@ -2,7 +2,7 @@
robject - description
-------------------
begin : Thu Aug 19 2004
copyright : (C) 2004-2016 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -117,6 +117,9 @@ public:
enum ObjectNameOptions {
DollarExpansion = 1, /**< Return list members as list$member, instead of list[["member"]] */
IncludeEnvirIfNotGlobalEnv = 2, /**< Include package name for objects on the search path */
IncludeEnvirForGlobalEnv = 4, /**< Include ".GlobalEnv" for objects inside globalenv */
IncludeEnvirIfMasked = 8, /**< Include package name for objects that are masked (only applicable for object lists, i.e. getFullNames()) */
NoIncludeEnvir = 0, /**< Label for missing include-envirs */
DefaultObjectNameOptions = IncludeEnvirIfNotGlobalEnv
};
virtual QString getFullName (int name_options = DefaultObjectNameOptions) const;
......@@ -180,7 +183,6 @@ public:
/** A QList of RObjects. Internally the same as RObjectMap, but can be considered "public" */
typedef QList<RObject*> ObjectList;
typedef QMap<QString, RObject*> RObjectSearchMap;
/** A map of values to labels. This is used both in regular objects, in which it just represents a map of named values, if any. The more important use is in factors, where it represents the factor levels. Here, the key is always a string representation of a positive integer. */
typedef QMap<QString, QString> ValueLabels;
......@@ -213,11 +215,12 @@ public:
/** try to find the object as a child object of this object.
@param name of the object (relative to this object)
@returns a pointer to the object (if found) or 0 if not found */
RObject *findObject (const QString &name) { return findObjects (parseObjectPath (name), 0, "$"); };
/** Function for code completion: given the partial name, find all objects matching this partial name
@param partial_name The partial name to look up
@param current_list A pointer to a valid (but probably initially empty) RObjectMap. Matches will be added to this list */
void findObjectsMatching (const QString &partial_name, RObjectSearchMap *current_list) { findObjects (parseObjectPath (partial_name), current_list, "$"); };
RObject *findObject (const QString &name) { return findObjects (parseObjectPath (name), false, "$").value (0); };
/** Function for code completion: given the partial name, find all objects matching this partial name
@param partial_name The partial name to look up */
RObject::ObjectList findObjectsMatching (const QString &partial_name) { return findObjects (parseObjectPath (partial_name), true, "$"); };
/** Get full-qualified object names for a list of objects as returned by findObjectsMatching */
static QStringList getFullNames (const RObject::ObjectList &objects, int options);
/** Fetch more levels of object representation (if needed). Note: Data is fetched asynchronously.
@param levels levels to recurse (0 = only direct children). */
......@@ -255,8 +258,9 @@ protected:
REnvironmentObject* namespaceEnvironment () const { return (hasPseudoObject (NamespaceObject) ? namespace_objects.value (this) : 0); };
void setSpecialChildObject (RObject *special, PseudoObjectType special_type);
/** Worker function for findObject() and findObjectsMatching(). If matches != 0, look for partial matches, and store them in the map (findObjectsMatching()). Else look for exact matches and return the first match (findObject()). */
virtual RObject *findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op);
/** Worker function for findObject() and findObjectsMatching().
* @If partial true: Look for partial matches (objects starting with the given pattern), false: look for exact matches, only. */
virtual ObjectList findObjects (const QStringList &path, bool partial, const QString &op);
/** Update object to reflect the structure passed in the new_data argument. If the data is mismatching (i.e. can not be accommodated by this type of object) false is returned (calls canAccommodateStructure () internally). In this case you should delete the object, and create a new one.
@returns true if the changes could be done, false if this */
......
......@@ -2,7 +2,7 @@
robjectlist - description
-------------------
begin : Wed Aug 18 2004
copyright : (C) 2004-2015 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -235,51 +235,58 @@ REnvironmentObject *RObjectList::createTopLevelEnvironment (const QString &name)
return envobj;
}
RObject *RObjectList::findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) {
RObject::ObjectList RObjectList::findObjects (const QStringList &path, bool partial, const QString &op) {
RK_TRACE (OBJECTS);
RK_ASSERT (op == "$");
RObject::ObjectList ret;
if (path.value (1) == "::") {
RObject *environment = findPackage (path[0]);
if (!environment) return 0;
return environment->findObjects (path.mid (2), matches, "$");
if (environment) return (environment->findObjects (path.mid (2), partial, "$"));
return ret;
} else if (path.value (1) == ":::") {
RObject *environment = findPackage (path[0]);
if (environment) environment = static_cast<REnvironmentObject*> (environment)->namespaceEnvironment ();
if (!environment) environment = orphan_namespaces->findOrphanNamespace (path[0]);
if (!environment) return 0;
return environment->findObjects (path.mid (2), matches, "$");
if (environment) return (environment->findObjects (path.mid (2), partial, "$"));
return ret;
} else if (path.value (0) == ".GlobalEnv") {
if (path.length () > 1) return getGlobalEnv ()->findObjects (path.mid (2), matches, "$");
else if (matches) matches->insert (path.value (0), getGlobalEnv ()); // no return, here: At least one more match will be found in base
else return getGlobalEnv ();
if (path.length () > 1) return getGlobalEnv ()->findObjects (path.mid (2), partial, "$");
// else we'll find base::.GlobalEnv, below
}
// no namespace given. Search all environments for matches
RObject *found = getGlobalEnv ()->findObjects (path, matches, "$");
if (found && !matches) return found;
// no namespace given. Search all environments for matches, .GlobalEnv, first
ret = getGlobalEnv ()->findObjects (path, partial, "$");
for (int i = 0; i < childmap.size (); ++i) {
if (!matches) {
found = childmap[i]->findObjects (path, 0, "$");
if (found) return found;
} else {
RObjectSearchMap pmatches;
childmap[i]->findObjects (path, &pmatches, "$");
// For matches in environments on the search path:
if (!(partial || ret.isEmpty ())) return ret;
ret.append (childmap[i]->findObjects (path, partial, "$"));
}
return ret;
}
QStringList RObject::getFullNames (const RObject::ObjectList &matches, int options) {
RK_TRACE (OBJECTS);
QStringList ret;
QSet<QString> unique_names;
for (int i = 0; i < matches.count (); ++i) {
if (options & IncludeEnvirIfMasked) {
// - If the name is *not* masked (yet), return the plain name.
// - If the name *is* masked, return the full qualitfied name.
for (RObjectSearchMap::const_iterator it = pmatches.constBegin (); it != pmatches.constEnd (); ++it) {
if (matches->contains (it.key ())) {
matches->insert (it.value ()->getFullName (), it.value ());
} else {
matches->insert (it.key (), it.value ());
}
// NOTE: This assumes objects are given in search order!
QString base_name = matches[i]->getFullName (options);
if (unique_names.contains (base_name)) {
base_name = matches[i]->getFullName (options | IncludeEnvirIfNotGlobalEnv | IncludeEnvirForGlobalEnv);
}
RK_ASSERT (!unique_names.contains (base_name));
unique_names.insert (base_name);
ret.append (base_name);
} else {
ret.append (matches[i]->getFullName (options));
}
}
return 0;
return ret;
}
REnvironmentObject* RObjectList::findPackage (const QString &namespacename) const {
......
......@@ -2,7 +2,7 @@
robjectlist - description
-------------------
begin : Wed Aug 18 2004
copyright : (C) 2004-2015 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -76,7 +76,7 @@ signals:
void updateComplete ();
protected:
/** reimplemented from RContainerObject to search the environments in search order */
RObject *findObjects (const QStringList &path, RObjectSearchMap *matches, const QString &op) override;
RObject::ObjectList findObjects (const QStringList &path, bool partial, const QString &op) override;
/// reimplemented from RContainerObject to call "remove (objectname)" instead of "objectname <- NULL"
QString removeChildCommand (RObject *object) const override;
......
......@@ -2,7 +2,7 @@
rkconsole - description
-------------------
begin : Thu Aug 19 2004
copyright : (C) 2004-2018 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -490,9 +490,10 @@ void RKConsole::doTabCompletion () {
if (doTabCompletionHelper (current_line_num, current_line, word_start + 1, word_end, comp.allMatches ())) return;
} else if (!current_symbol.isEmpty ()) {
RObject::RObjectSearchMap map;
RObjectList::getObjectList ()->findObjectsMatching (current_symbol, &map);
if (doTabCompletionHelper (current_line_num, current_line, word_start, word_end, map.keys ())) return;
RObject::ObjectList matches;
matches = RObjectList::getObjectList ()->findObjectsMatching (current_symbol);
QStringList match_names = RObject::getFullNames (matches, RObject::IncludeEnvirIfMasked);
if (doTabCompletionHelper (current_line_num, current_line, word_start, word_end, match_names)) return;
}
// no completion was possible
......
......@@ -2,7 +2,7 @@
rkcommandeditorwindow - description
-------------------
begin : Mon Aug 30 2004
copyright : (C) 2004-2018 by Thomas Friedrichsmeier
copyright : (C) 2004-2019 by Thomas Friedrichsmeier
email : thomas.friedrichsmeier@kdemail.net
***************************************************************************/
......@@ -1280,23 +1280,20 @@ void RKCodeCompletionModel::updateCompletionList (const QString& symbol) {
if (current_symbol == symbol) return; // already up to date
beginResetModel ();
RObject::RObjectSearchMap map;
RObject::ObjectList matches;
QStringList objectpath = RObject::parseObjectPath (symbol);
if (!objectpath.isEmpty () && !objectpath[0].isEmpty ()) { // Skip completion, if the current symbol is '""' (or another empty quote), for instance
RObjectList::getObjectList ()->findObjectsMatching (symbol, &map);
matches = RObjectList::getObjectList ()->findObjectsMatching (symbol);
}
int count = map.size ();
icons.clear ();
names.clear ();
icons.reserve (count);
names.reserve (count);
// copy the map to two lists. For one thing, we need an int indexable storage, for another, caching this information is safer
// in case objects are removed while the completion mode is active.
for (RObject::RObjectSearchMap::const_iterator it = map.constBegin (); it != map.constEnd (); ++it) {
icons.append (RKStandardIcons::iconForObject (it.value ()));
names.append (it.key ());
int count = matches.size ();
icons.clear ();
icons.reserve (count);
names = RObject::getFullNames (matches, RObject::IncludeEnvirIfMasked);
for (int i = 0; i < count; ++i) {
icons.append (RKStandardIcons::iconForObject (matches[i]));
}
setRowCount (count);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment