[rkward] rkward: Separate object search, and completion name generation. Now all we still need is a UI for configuration.

Thomas Friedrichsmeier null at kde.org
Fri Jan 18 15:20:01 GMT 2019


Git commit bb1c5b0cc662bbee001d31d2657cc9f51a6e1215 by Thomas Friedrichsmeier.
Committed on 18/01/2019 at 15:18.
Pushed by tfry into branch 'master'.

Separate object search, and completion name generation. Now all we still need is a UI for configuration.

M  +18   -16   rkward/core/rcontainerobject.cpp
M  +2    -2    rkward/core/rcontainerobject.h
M  +3    -3    rkward/core/renvironmentobject.cpp
M  +4    -4    rkward/core/robject.cpp
M  +13   -9    rkward/core/robject.h
M  +35   -28   rkward/core/robjectlist.cpp
M  +2    -2    rkward/core/robjectlist.h
M  +5    -4    rkward/rkconsole.cpp
M  +9    -12   rkward/windows/rkcommandeditorwindow.cpp

https://commits.kde.org/rkward/bb1c5b0cc662bbee001d31d2657cc9f51a6e1215

diff --git a/rkward/core/rcontainerobject.cpp b/rkward/core/rcontainerobject.cpp
index 52a322c7..8c5d45d5 100644
--- a/rkward/core/rcontainerobject.cpp
+++ b/rkward/core/rcontainerobject.cpp
@@ -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 at 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) {
diff --git a/rkward/core/rcontainerobject.h b/rkward/core/rcontainerobject.h
index 9e9f5839..c3bfb5dc 100644
--- a/rkward/core/rcontainerobject.h
+++ b/rkward/core/rcontainerobject.h
@@ -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 at 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;
diff --git a/rkward/core/renvironmentobject.cpp b/rkward/core/renvironmentobject.cpp
index a808914d..4acf9462 100644
--- a/rkward/core/renvironmentobject.cpp
+++ b/rkward/core/renvironmentobject.cpp
@@ -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 at 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) {
diff --git a/rkward/core/robject.cpp b/rkward/core/robject.cpp
index 81a435d1..d6807e60 100644
--- a/rkward/core/robject.cpp
+++ b/rkward/core/robject.cpp
@@ -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 at 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 {
diff --git a/rkward/core/robject.h b/rkward/core/robject.h
index f69e19a4..91d1fe46 100644
--- a/rkward/core/robject.h
+++ b/rkward/core/robject.h
@@ -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 at 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
- at param partial_name The partial name to look up
- at 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
+ at 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  */
diff --git a/rkward/core/robjectlist.cpp b/rkward/core/robjectlist.cpp
index b22b582f..48165710 100644
--- a/rkward/core/robjectlist.cpp
+++ b/rkward/core/robjectlist.cpp
@@ -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 at 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 {
diff --git a/rkward/core/robjectlist.h b/rkward/core/robjectlist.h
index 5f60a2d0..0d77be95 100644
--- a/rkward/core/robjectlist.h
+++ b/rkward/core/robjectlist.h
@@ -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 at 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;
diff --git a/rkward/rkconsole.cpp b/rkward/rkconsole.cpp
index 368eca95..943aeea2 100644
--- a/rkward/rkconsole.cpp
+++ b/rkward/rkconsole.cpp
@@ -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 at 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
diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkcommandeditorwindow.cpp
index 30a5a3b6..577fabfc 100644
--- a/rkward/windows/rkcommandeditorwindow.cpp
+++ b/rkward/windows/rkcommandeditorwindow.cpp
@@ -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 at 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);



More information about the rkward-tracker mailing list