[rkward-cvs] SF.net SVN: rkward: [886] trunk/rkward/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu Oct 19 17:13:38 UTC 2006


Revision: 886
          http://svn.sourceforge.net/rkward/?rev=886&view=rev
Author:   tfry
Date:     2006-10-19 10:13:20 -0700 (Thu, 19 Oct 2006)

Log Message:
-----------
First go at code completion (tab in console). This is still very buggy, but works in principle.
Probably we can't use the katepart's completion infrastructure, but do our own

Modified Paths:
--------------
    trunk/rkward/rkward/core/rcontainerobject.cpp
    trunk/rkward/rkward/core/rcontainerobject.h
    trunk/rkward/rkward/core/renvironmentobject.cpp
    trunk/rkward/rkward/core/renvironmentobject.h
    trunk/rkward/rkward/core/robject.cpp
    trunk/rkward/rkward/core/robject.h
    trunk/rkward/rkward/core/robjectlist.cpp
    trunk/rkward/rkward/core/robjectlist.h
    trunk/rkward/rkward/khelpdlg.cpp
    trunk/rkward/rkward/misc/rkcommonfunctions.cpp
    trunk/rkward/rkward/misc/rkcommonfunctions.h
    trunk/rkward/rkward/rkconsole.cpp
    trunk/rkward/rkward/rkconsole.h

Modified: trunk/rkward/rkward/core/rcontainerobject.cpp
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/rcontainerobject.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -211,10 +211,7 @@
 	RK_TRACE (OBJECTS);
 
 	QString canonified = name;
-	if (!is_canonified) {
-		// yeah, ok, this could be made more efficient relatively easily ...
-		canonified = canonified.replace ("[\"", "$").replace ('[', "").replace ("\"]", "").replace (']', "");
-	}
+	if (!is_canonified) canonified = canonifyName (name);
 
 	// TODO: there could be objects with "$" in their names!
 	QString current_level = canonified.section (QChar ('$'), 0, 0);
@@ -229,6 +226,38 @@
 	return (found->findObject (remainder, true));
 }
 
+void RContainerObject::findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (current_list);
+
+	QString canonified = partial_name;
+	if (!name_is_canonified) canonified = canonifyName (partial_name);
+
+	// TODO: there could be objects with "$" in their names!
+	QString current_level = canonified.section (QChar ('$'), 0, 0);
+	QString remainder = canonified.section (QChar ('$'), 1);
+
+	if (remainder.isEmpty ()) {
+		for (RObjectMap::const_iterator it = childmap.constBegin (); it != childmap.constEnd (); ++it) {
+			if (it.key ().startsWith (current_level)) {
+				QString base_name = it.data ()->getBaseName ();
+				if (current_list->contains (base_name)) {
+					current_list->insert (it.data ()->getFullName (), it.data ());
+				} else {
+					current_list->insert (base_name, it.data ());
+				}
+			}
+		}
+	} else {
+		RObjectMap::iterator it = childmap.find (current_level);
+
+		if (it == childmap.end ()) return;
+
+		RObject *found = it.data ();
+		found->findObjectsMatching (remainder, current_list, true);
+	}
+}
+
 RObject *RContainerObject::createNewChild (const QString &name, RKEditor *creator, bool container, bool data_frame) {
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (childmap.find (name) == childmap.end ());

Modified: trunk/rkward/rkward/core/rcontainerobject.h
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/rcontainerobject.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -63,6 +63,9 @@
 
 	/** reimplemented from RObject to actually search for the object */
 	virtual RObject *findObject (const QString &name, bool is_canonified=false);
+
+	/** reimplemented from RObject to actually search for matching objects */
+	void findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified=false);
 protected:
 	void updateChildren (RData *new_children);
 	RObjectMap childmap;

Modified: trunk/rkward/rkward/core/renvironmentobject.cpp
===================================================================
--- trunk/rkward/rkward/core/renvironmentobject.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/renvironmentobject.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -63,6 +63,15 @@
 	return (name + "$" + short_child_name);
 }
 
+QString REnvironmentObject::makeChildBaseName (const QString &short_child_name) {
+	RK_TRACE (OBJECTS);
+
+	if (type & ToplevelEnv) {
+		return (short_child_name);
+	}
+	return (name + "$" + short_child_name);
+}
+
 void REnvironmentObject::writeMetaData (RCommandChain *chain) {
 	RK_TRACE (OBJECTS);
 

Modified: trunk/rkward/rkward/core/renvironmentobject.h
===================================================================
--- trunk/rkward/rkward/core/renvironmentobject.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/renvironmentobject.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -36,6 +36,7 @@
 
 	QString getFullName ();
 	QString makeChildName (const QString &short_child_name, bool misplaced=false);
+	QString makeChildBaseName (const QString &short_child_name);
 /** reimplemented from RContainerObject: If this is an environment var, call RContainerObject::writeMetaData (). Else, do nothing. An environment has no meta data. */
 	void writeMetaData (RCommandChain *chain);
 protected:

Modified: trunk/rkward/rkward/core/robject.cpp
===================================================================
--- trunk/rkward/rkward/core/robject.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/robject.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -67,6 +67,11 @@
 	return parent->makeChildName (RObject::name, type & Misplaced);
 }
 
+QString RObject::getBaseName () {
+	RK_TRACE (OBJECTS);
+	return parent->makeChildBaseName (RObject::name);
+}
+
 QString RObject::getLabel () {
 	RK_TRACE (OBJECTS);
 	return getMetaProperty ("label");
@@ -77,6 +82,11 @@
 	return 0;
 }
 
+void RObject::findObjectsMatching (const QString &, RObjectMap *, bool) {
+	RK_TRACE (OBJECTS);
+	return;
+}
+
 QString RObject::getMetaProperty (const QString &id) {
 	RK_TRACE (OBJECTS);
 	if (meta_map) {
@@ -208,6 +218,11 @@
 	return (getFullName () + "[[" + rQuote (short_child_name) + "]]");
 }
 
+QString RObject::makeChildBaseName (const QString &short_child_name){
+	RK_TRACE (OBJECTS);
+	return (getBaseName () + "[[" + rQuote (short_child_name) + "]]");
+}
+
 void RObject::writeMetaData (RCommandChain *chain) {
 	RK_TRACE (OBJECTS);
 	
@@ -512,6 +527,14 @@
 	return ("\"" + copy.replace (QRegExp ("\""), "\\\"") + "\"");
 }
 
+// static
+QString RObject::canonifyName (const QString &from) {
+	RK_TRACE (OBJECTS);
+
+	QString copy = from;
+	return (copy.replace ("[\"", "$").replace ('[', "").replace ("\"]", "").replace (']', ""));
+}
+
 RKEditor *RObject::objectOpened () {
 	RK_TRACE (OBJECTS);
 

Modified: trunk/rkward/rkward/core/robject.h
===================================================================
--- trunk/rkward/rkward/core/robject.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/robject.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -79,6 +79,7 @@
 	
 	QString getShortName ();
 	virtual QString getFullName ();
+	virtual QString getBaseName ();
 	virtual QString getLabel ();
 	virtual QString getMetaProperty (const QString &id);
 	virtual QString getDescription ();
@@ -153,18 +154,15 @@
 	static QString rQuote (const QString &string);
 /** Returns a pretty description of the object, and its most important properties. TODO should this be virtual or not? I suppose, it's a close call. For now, we do all work here with casts */
 	QString getObjectDescription ();
-// UNIMPLEMENTED
 /** Returns a canonified name given a non-canoified name. Warning! This is not (necessarily) suitable for submission to
 R, only for internal lookup. For submission to R, always use RObject::getFullName (), as it will apply more complicated (and correct) rules depending on object type */
-//	static QString canonifyName (const QString &from);
+	static QString canonifyName (const QString &from);
 /** 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
 @param name_is_canonified internal parameter. Set to true, if the name to match is already canonfied (else it will be canonified internally) */
-//	virtual void findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified=false);
-// UNIMPLEMENTED END
+	virtual void findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified=false);
 
-
 /** If the object is being edited, returns that editor (in the future probably a list of editors). Else returns 0 */
 	RKEditor *objectOpened ();
 /** Tells the object it has been opened (opened=true) or closed (opened=false) by the given editor. If the object is opened by the first editor, it will
@@ -199,6 +197,7 @@
 
 /** generates a (full) name for a child of this object with the given name. */
 	virtual QString makeChildName (const QString &short_child_name, bool misplaced=false);
+	virtual QString makeChildBaseName (const QString &short_child_name);
 
 /** 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  */

Modified: trunk/rkward/rkward/core/robjectlist.cpp
===================================================================
--- trunk/rkward/rkward/core/robjectlist.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/robjectlist.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -167,9 +167,7 @@
 	RK_TRACE (OBJECTS);
 
 	QString canonified = name;
-	if (!is_canonified) {
-		canonified = canonified.replace ("[\"", "$").replace ('[', "").replace ("\"]", "").replace (']', "");
-	}
+	if (!is_canonified) canonified = canonifyName (name);
 
 	// TODO: there could be objects with "::" in their names!
 	if (canonified.contains ("::")) {
@@ -183,21 +181,40 @@
 		return (found->findObject (remainder, true));
 	}
 
-	// no environment specified, do regular search:
-	// TODO: there could be objects with "$" in their names!
-	QString current_level = canonified.section (QChar ('$'), 0, 0);
-	QString remainder = canonified.section (QChar ('$'), 1);
-
+	// no "::"-qualification given, do normal search in all environments, return first match
 	for (unsigned int i = 0; i < num_toplevel_environments; ++i) {
-		RObject *found = toplevel_environments[i]->findObject (current_level, true);
-		if (found) {
-			if (remainder.isEmpty ()) return (found);
-			return (found->findObject (remainder, true));
-		}
+		RObject *found = toplevel_environments[i]->findObject (canonified, true);
+		if (found) return found;
 	}
 	return 0;
 }
 
+void RObjectList::findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (current_list);
+
+	QString canonified = partial_name;
+	if (!name_is_canonified) canonified = canonifyName (partial_name);
+
+	// TODO: there could be objects with "::" in their names!
+	if (canonified.contains ("::")) {
+		QString env = canonified.section ("::", 0, 0);
+		QString remainder = canonified.section ("::", 1);
+
+		RObjectMap::iterator it = childmap.find (env);
+		if (it == childmap.end ()) return;
+
+		RObject *found = it.data ();
+		found->findObjectsMatching (remainder, current_list, true);
+		return;
+	}
+
+	// no "::"-qualification given, do normal search in all environments.
+	for (unsigned int i = 0; i < num_toplevel_environments; ++i) {
+		toplevel_environments[i]->findObjectsMatching (canonified, current_list, true);
+	}
+}
+
 RObject *RObjectList::createNewChild (const QString &name, RKEditor *creator, bool container, bool data_frame) {
 	RK_TRACE (OBJECTS);
 

Modified: trunk/rkward/rkward/core/robjectlist.h
===================================================================
--- trunk/rkward/rkward/core/robjectlist.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/core/robjectlist.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -55,6 +55,9 @@
 	/** reimplemented from RContainerObject to search the environments in search order */
 	RObject *findObject (const QString &name, bool canonified=false);
 
+	/** reimplemented from RContainerObject to search the environments in search order */
+	void findObjectsMatching (const QString &partial_name, RObjectMap *current_list, bool name_is_canonified=false);
+
 	/** reimplemented from RContainerObject to create the child in the .GlobalEnv */
 	RObject *createNewChild (const QString &name, RKEditor *creator=0, bool container=false, bool data_frame=false);
 

Modified: trunk/rkward/rkward/khelpdlg.cpp
===================================================================
--- trunk/rkward/rkward/khelpdlg.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/khelpdlg.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -25,7 +25,6 @@
 #include <qcombobox.h>
 #include <qlistview.h>
 #include <qlineedit.h>
-#include <qregexp.h>
 #include <qlayout.h>
 #include <qlabel.h>
 
@@ -34,6 +33,7 @@
 #include "debug.h"
 #include "rkglobals.h"
 #include "rkward.h"
+#include "misc/rkcommonfunctions.h"
 
 #define GET_HELP_URL 1
 #define HELP_SEARCH 2
@@ -106,23 +106,10 @@
 }
 
 void KHelpDlg::getContextHelp (const QString &context_line, int cursor_pos) {
-	if (context_line.isEmpty () || context_line.isNull ()) return;
+	QString result = RKCommonFunctions::getCurrentSymbol (context_line, cursor_pos);
+	if (result.isEmpty ()) return;
 
-	// step 1: find out word under cursor
-	// We want to match any valid R name, that is, everything composed of letters, 0-9, '.'s and '_'s..
-	QRegExp rx_no_word ("[^A-Za-z0-9\\._]");
-
-	// find out the next non-word stuff left and right of the current cursor position
-	int current_word_start = context_line.findRev (rx_no_word, cursor_pos-1) + 1;
-	int current_word_end = context_line.find (rx_no_word, cursor_pos);
-
-	// if both return the same position, we're on a non-word.
-	if (current_word_start == current_word_end) return;
-
-	QString result = context_line.mid (current_word_start, current_word_end - current_word_start);
-
-	// step 2: retrieve help
-	RKGlobals::rInterface ()->issueCommand ("help(\"" + result + "\", htmlhelp=TRUE)[1]", RCommand::App | RCommand::GetStringVector, QString::null, this, GET_HELP_URL, 0);
+	getFunctionHelp (result);
 }
 
 void KHelpDlg::getFunctionHelp (const QString &function_name) {

Modified: trunk/rkward/rkward/misc/rkcommonfunctions.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkcommonfunctions.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/misc/rkcommonfunctions.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -18,6 +18,7 @@
 
 #include <qstringlist.h>
 #include <qdom.h>
+#include <qregexp.h>
 
 #include <kxmlguiclient.h>
 
@@ -96,4 +97,38 @@
 		}
 	}
 
+	QString getCurrentSymbol (const QString &context_line, int cursor_pos, bool strict) {
+		if (context_line.isEmpty ()) return (QString ());
+
+		int current_word_start;
+		int current_word_end;
+		getCurrentSymbolOffset (context_line, cursor_pos, strict, &current_word_start, &current_word_end);
+	
+		// if both return the same position, we're on a non-word.
+		if (current_word_start == current_word_end) return (QString ());
+	
+		return (context_line.mid (current_word_start, current_word_end - current_word_start));
+	}
+
+	void getCurrentSymbolOffset (const QString &context_line, int cursor_pos, bool strict, int *start, int *end) {
+		if (context_line.isEmpty ()) {
+			*start = 0;
+			*end = 0;
+			return;
+		}
+
+		// step 1: find out word under cursor
+		// We want to match any valid R name, that is, everything composed of letters, 0-9, '.'s and '_'s..
+		QRegExp rx_no_word;
+		if (strict) {
+			rx_no_word = QRegExp ("[^A-Za-z0-9\\._]");
+		} else {
+			rx_no_word = QRegExp ("[^A-Za-z0-9\\._\\$\\:\\[\"\\]]");
+		}
+
+		// find out the next non-word stuff left and right of the current cursor position
+		*start = context_line.findRev (rx_no_word, cursor_pos-1) + 1;
+		*end = context_line.find (rx_no_word, cursor_pos);
+	}
+
 }	// namespace

Modified: trunk/rkward/rkward/misc/rkcommonfunctions.h
===================================================================
--- trunk/rkward/rkward/misc/rkcommonfunctions.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/misc/rkcommonfunctions.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -34,6 +34,11 @@
 	void removeContainers (KXMLGUIClient *from, const QStringList &names, bool recursive);
 /** move container (action, menu, etc.) with tagname "tagname" and attribute 'name="..."' to be a child node of the tag with tagname=tagname and attribute name=to_name. Can be used to make a top-level menu a sub-menu of another menu instead */
 	void moveContainer (KXMLGUIClient *client, const QString &tagname, const QString &name, const QString &to_name, bool recursive);
+
+/** given the context line, find what looks like an R symbol */
+	QString getCurrentSymbol (const QString &context_line, int cursor_pos, bool strict=true);
+/** like get current symbol, but merely returns the start and end position of the current symbol */
+	void getCurrentSymbolOffset (const QString &context_line, int cursor_pos, bool strict, int *start, int *end);
 };
 
 #endif

Modified: trunk/rkward/rkward/rkconsole.cpp
===================================================================
--- trunk/rkward/rkward/rkconsole.cpp	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/rkconsole.cpp	2006-10-19 17:13:20 UTC (rev 886)
@@ -28,7 +28,6 @@
 #include <kactioncollection.h>
 #include <kconfig.h>
 
-
 #include "rkglobals.h"
 #include "rkward.h"
 #include "khelpdlg.h"
@@ -36,10 +35,9 @@
 #include "rbackend/rinterface.h"
 #include "rbackend/rcommand.h"
 #include "settings/rksettingsmoduleconsole.h"
+#include "misc/rkcommonfunctions.h"
+#include "core/robjectlist.h"
 
-
-
-
 RKConsole::RKConsole () : QWidget (0) {
 	RK_TRACE (APP);
 
@@ -59,7 +57,6 @@
 
 	view->setDynWordWrap (false);
 
-	
 	setFocusProxy (view);
 	setFocusPolicy (QWidget::WheelFocus);
 	
@@ -74,7 +71,6 @@
 	KActionCollection* ac=0;
 	QWidget* Kvi=0; //here we store the KateViewInternal of the view, so we can uplug actions from it
 	
-
 	while ((obj = it.current()) != 0) {
 		++it;
 		obj->installEventFilter (this);
@@ -84,7 +80,6 @@
 			Kvi= (QWidget*) obj;
 		}
 	}
-	
 
 	if (ac) {
 		unplugAction("move_line_up", ac);
@@ -236,6 +231,10 @@
 			return TRUE;
 		}
 	}
+	else if (e->key () == Qt::Key_Tab){
+		doTabCompletion ();
+		return TRUE;
+	}
 	else if (e->key () == Qt::Key_Home){
 		cursorAtTheBeginning ();
 		return TRUE;
@@ -248,8 +247,24 @@
 	return FALSE;
 }
 
-bool RKConsole::eventFilter( QObject *o, QEvent *e )
-{
+void RKConsole::doTabCompletion () {
+	RK_TRACE (APP);
+
+	QString current_symbol = RKCommonFunctions::getCurrentSymbol (currentCommand (), currentCursorPositionInCommand (), false);
+	if (!current_symbol.isEmpty ()) {
+		RObject::RObjectMap map;
+		RObjectList::getObjectList ()->findObjectsMatching (current_symbol, &map);
+		QValueList<KTextEditor::CompletionEntry> list;
+		for (RObject::RObjectMap::const_iterator it = map.constBegin (); it != map.constEnd (); ++it) {
+			KTextEditor::CompletionEntry entry;
+			entry.text = it.key ();
+			list.append (entry);
+		}
+		view->showCompletionBox (list);
+	}
+}
+
+bool RKConsole::eventFilter (QObject *, QEvent *e) {
 	if (e->type () == QEvent::KeyPress) {
 		QKeyEvent *k = (QKeyEvent *)e;
 		return handleKeyPress (k);

Modified: trunk/rkward/rkward/rkconsole.h
===================================================================
--- trunk/rkward/rkward/rkconsole.h	2006-10-19 15:25:41 UTC (rev 885)
+++ trunk/rkward/rkward/rkconsole.h	2006-10-19 17:13:20 UTC (rev 886)
@@ -61,6 +61,7 @@
 	bool hasSelectedText ();
 /** interrupt the current incomplete command (if any) */
 	void resetIncompleteCommand ();
+	void doTabCompletion ();
 protected:
 /** Constructor. Protected. Construct an RKConsolePart instead */
 	RKConsole ();


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list