[rkward-cvs] SF.net SVN: rkward: [900] trunk/rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Mon Oct 30 12:29:37 UTC 2006
Revision: 900
http://svn.sourceforge.net/rkward/?rev=900&view=rev
Author: tfry
Date: 2006-10-30 04:29:26 -0800 (Mon, 30 Oct 2006)
Log Message:
-----------
some small improvements to completion and arg hinting
add argument hinting in script editor
console and editor use common mechanism for argument hinting
Modified Paths:
--------------
trunk/rkward/ChangeLog
trunk/rkward/rkward/core/renvironmentobject.h
trunk/rkward/rkward/core/robjectlist.cpp
trunk/rkward/rkward/misc/rkcommonfunctions.cpp
trunk/rkward/rkward/rkconsole.cpp
trunk/rkward/rkward/rkconsole.h
trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
trunk/rkward/rkward/windows/rkcommandeditorwindow.h
Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/ChangeLog 2006-10-30 12:29:26 UTC (rev 900)
@@ -5,8 +5,8 @@
- fix for compilation on 64bit architectures
- remove misleading "About KDE" dialog, and replace report Bug dialog with correct information
- don't crash when closing a detached window
+- function argument hinting in the console and script editor
- as you type completion of R symbol names in the script editor
-- function argument hinting in the console
- tab completion of R symbol names in the console
- added R function rk.edit (x) to open object x for editing in rkward
- fixed: an empty table created before the object list was updated (esp. at startup) would be thought to have been removed in the workspace
Modified: trunk/rkward/rkward/core/renvironmentobject.h
===================================================================
--- trunk/rkward/rkward/core/renvironmentobject.h 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/core/renvironmentobject.h 2006-10-30 12:29:26 UTC (rev 900)
@@ -39,6 +39,7 @@
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);
+ QString namespaceName () { return namespace_name; };
protected:
bool updateStructure (RData *new_data);
/** reimplemented from RContainerObject to raise an assert if this is not the isGlobalEnv (). Otherwise calls "remove (objectname)" instead of objectname <- NULL" */
Modified: trunk/rkward/rkward/core/robjectlist.cpp
===================================================================
--- trunk/rkward/rkward/core/robjectlist.cpp 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/core/robjectlist.cpp 2006-10-30 12:29:26 UTC (rev 900)
@@ -174,10 +174,15 @@
QString env = canonified.section ("::", 0, 0);
QString remainder = canonified.section ("::", 1);
- RObjectMap::iterator it = childmap.find (env);
- if (it == childmap.end ()) return 0;
+ RObject *found = 0;
+ for (unsigned int i = 0; i < num_toplevel_environments; ++i) {
+ if (toplevel_environments[i]->namespaceName () == env) {
+ found = toplevel_environments[i];
+ break;
+ }
+ }
+ if (!found) return 0;
- RObject *found = it.data ();
return (found->findObject (remainder, true));
}
@@ -201,10 +206,15 @@
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 ();
+ RObject *found = 0;
+ for (unsigned int i = 0; i < num_toplevel_environments; ++i) {
+ if (toplevel_environments[i]->namespaceName () == env) {
+ found = toplevel_environments[i];
+ break;
+ }
+ }
+ if (!found) return;
+
found->findObjectsMatching (remainder, current_list, true);
return;
}
Modified: trunk/rkward/rkward/misc/rkcommonfunctions.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkcommonfunctions.cpp 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/misc/rkcommonfunctions.cpp 2006-10-30 12:29:26 UTC (rev 900)
@@ -106,7 +106,7 @@
// 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));
}
Modified: trunk/rkward/rkward/rkconsole.cpp
===================================================================
--- trunk/rkward/rkward/rkconsole.cpp 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/rkconsole.cpp 2006-10-30 12:29:26 UTC (rev 900)
@@ -22,9 +22,6 @@
#include <qapplication.h>
#include <qobjectlist.h>
#include <qevent.h>
-#include <qregexp.h>
-#include <qvbox.h>
-#include <qlabel.h>
#include <qtimer.h>
#include <klocale.h>
@@ -120,6 +117,8 @@
view->installEventFilter(this);
doc->setModified (false);
+
+ hinter = new RKFunctionArgHinter (this, view);
setCaption (i18n ("R Console"));
@@ -137,19 +136,12 @@
current_command = 0;
tab_key_pressed_before = false;
-
- arghints_popup = new QVBox (0, 0, WType_Popup);
- arghints_popup->setFrameStyle (QFrame::Box | QFrame::Plain);
- arghints_popup->setLineWidth (1);
- arghints_popup_text = new QLabel (arghints_popup);
- arghints_popup->hide ();
- arghints_popup->setFocusProxy (this);
}
RKConsole::~RKConsole () {
RK_TRACE (APP);
- delete arghints_popup;
+ delete hinter;
RKSettingsModuleConsole::saveCommandHistory (commands_history);
}
@@ -203,12 +195,11 @@
}
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
- arghints_popup->hide ();
+ hinter->hideArgHint ();
submitCommand ();
return true;
}
else if (e->state () == Qt::ShiftButton && e->key () == Qt::Key_Home){
- arghints_popup->hide ();
if(hasSelectedText())
pos=selectionInterfaceExt(doc)->selEndCol (); //There is already a selection, we take it into account.
selectionInterface(doc)->setSelection(doc->numLines()-1,prefix.length (),doc->numLines()-1, pos);
@@ -216,7 +207,6 @@
return TRUE;
}
else if (e->state () == Qt::ShiftButton && e->key () == Qt::Key_Left){
- arghints_popup->hide ();
if(pos<=prefix.length ()){
return TRUE;
} else {
@@ -225,17 +215,14 @@
}
}
else if (e->key () == Qt::Key_Up) {
- arghints_popup->hide ();
commandsListUp ();
return true;
}
else if (e->key () == Qt::Key_Down) {
- arghints_popup->hide ();
commandsListDown ();
return true;
}
else if (e->key () == Qt::Key_Left){
- arghints_popup->hide ();
if(pos<=prefix.length ()){
return TRUE;
} else {
@@ -244,7 +231,6 @@
}
}
else if (e->key () == Qt::Key_Backspace){
- tryShowFunctionArgHints ();
if(pos<=prefix.length ()){
return TRUE;
} else {
@@ -257,87 +243,31 @@
return TRUE;
}
else if (e->key () == Qt::Key_Home){
- arghints_popup->hide ();
cursorAtTheBeginning ();
return TRUE;
}
else if (e->key() == Qt::Key_Delete) {
- tryShowFunctionArgHints ();
view->keyDelete();
return TRUE;
- } else {
- QString text = e->text ();
- if (text == "(") {
- tryShowFunctionArgHints ();
- } else if (text == ")") {
- tryShowFunctionArgHints ();
- }
}
return FALSE;
}
-void RKConsole::tryShowFunctionArgHints () {
- // wait for the keypress to become effective first
- QTimer::singleShot (0, this, SLOT (realTryShowFunctionArgHints ()));
-}
+bool RKConsole::provideContext (unsigned int line_rev, QString *context, int *cursor_position) {
+ RK_TRACE (COMMANDEDITOR);
-void RKConsole::realTryShowFunctionArgHints () {
- RK_TRACE (APP);
+ if (line_rev > 1) return false;
- QString current_context = currentCommand ();
- int cursor_pos = currentCursorPositionInCommand ();
- if (command_incomplete) {
- current_context.prepend (incomplete_command);
- cursor_pos += incomplete_command.length ();
+ if (line_rev == 0) {
+ *cursor_position = currentCursorPositionInCommand ();
+ *context = currentCommand ();
+ } else {
+ *cursor_position = -1;
+ *context = incomplete_command;
}
- int matching_left_brace_pos;
- // find the corrresponding opening brace
- int brace_level = 1;
- int i;
- for (i = cursor_pos; i >= 0; --i) {
- if (current_context.at (i) == QChar (')')) {
- brace_level++;
- } else if (current_context.at (i) == QChar ('(')) {
- brace_level--;
- if (!brace_level) break;
- }
- }
- if (!brace_level) matching_left_brace_pos = i;
- else {
- arghints_popup->hide ();
- return;
- }
-
- // now find where the symbol to the left ends
- int potential_symbol_end = matching_left_brace_pos - 1;
- while ((potential_symbol_end >= 0) && current_context.at (potential_symbol_end).isSpace ()) {
- --potential_symbol_end;
- }
- if (current_context.at (potential_symbol_end).isSpace ()) {
- arghints_popup->hide ();
- return;
- }
-
- // now identify the symbol and object (if any)
- QString effective_symbol = RKCommonFunctions::getCurrentSymbol (current_context, potential_symbol_end);
- if (effective_symbol.isEmpty ()) {
- arghints_popup->hide ();
- return;
- }
-
- RObject *object = RObjectList::getObjectList ()->findObject (effective_symbol);
- if ((!object) || (!object->isType (RObject::Function))) {
- arghints_popup->hide ();
- return;
- }
-
- // initialize and show popup
- arghints_popup_text->setText (effective_symbol + " (" + static_cast<RFunctionObject*> (object)->printArgs () + ")");
- arghints_popup->resize (arghints_popup_text->sizeHint () + QSize (2, 2));
- arghints_popup->move (mapToGlobal (view->cursorCoordinates () + QPoint (0, arghints_popup->height ())));
- arghints_popup->show ();
+ return true;
}
void RKConsole::doTabCompletion () {
Modified: trunk/rkward/rkward/rkconsole.h
===================================================================
--- trunk/rkward/rkward/rkconsole.h 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/rkconsole.h 2006-10-30 12:29:26 UTC (rev 900)
@@ -26,13 +26,11 @@
#include <qptrlist.h>
#include "rbackend/rcommandreceiver.h"
+#include "windows/rkcommandeditorwindow.h"
class QStringList;
-class QVBox;
-class QLabel;
class KAction;
class RCommand;
-class KateCodeCompletion;
/**
** \brief Provides an R-like console.
@@ -47,7 +45,7 @@
** @author Pierre Ecochard
**/
-class RKConsole : public QWidget, public RCommandReceiver {
+class RKConsole : public QWidget, public RCommandReceiver, public RKScriptContextProvider {
Q_OBJECT
public:
/** Submits a batch of commands, line by line.
@@ -64,6 +62,7 @@
/** interrupt the current incomplete command (if any) */
void resetIncompleteCommand ();
void doTabCompletion ();
+ bool provideContext (unsigned int line_rev, QString *context, int *cursor_position);
protected:
/** Constructor. Protected. Construct an RKConsolePart instead */
RKConsole ();
@@ -83,7 +82,7 @@
void fetchPopupMenu (QPopupMenu **menu);
private:
friend class RKConsolePart;
-bool eventFilter( QObject *o, QEvent *e );
+ bool eventFilter (QObject *o, QEvent *e);
/** set syntax-highlighting for R */
void setRHighlighting ();
QString incomplete_command;
@@ -127,23 +126,19 @@
\param ac the action collection from which to retrieve the KAction*/
void unplugAction (QString action, KActionCollection* ac);
- void tryShowFunctionArgHints ();
-
bool output_continuation;
RCommand *current_command;
Kate::Document *doc;
Kate::View *view;
+ RKFunctionArgHinter *hinter;
bool tab_key_pressed_before;
- QVBox *arghints_popup;
- QLabel *arghints_popup_text;
public slots:
/** We intercept paste commands and get them executed through submitBatch.
@sa submitBatch */
void paste ();
void copy ();
- void realTryShowFunctionArgHints ();
};
/** A part interface to RKConsole. Provides the context-help functionality
Modified: trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp 2006-10-30 12:29:26 UTC (rev 900)
@@ -87,13 +87,19 @@
completion_timer = new QTimer (this);
connect (completion_timer, SIGNAL (timeout ()), this, SLOT (tryCompletion()));
- if (use_r_highlighting) setRHighlighting ();
+ if (use_r_highlighting) {
+ setRHighlighting ();
+ hinter = new RKFunctionArgHinter (this, m_view);
+ } else {
+ hinter = 0;
+ }
updateCaption (); // initialize
}
RKCommandEditorWindow::~RKCommandEditorWindow () {
RK_TRACE (COMMANDEDITOR);
+ delete hinter;
delete m_doc;
}
@@ -236,9 +242,11 @@
}
}
-void RKCommandEditorWindow::fixCompletion (KTextEditor::CompletionEntry *, QString *) {
+void RKCommandEditorWindow::fixCompletion (KTextEditor::CompletionEntry *entry, QString *string) {
RK_TRACE (COMMANDEDITOR);
+ *string = entry->text; // why, oh, why, isn't this always the case?
+
uint current_line_num=0; uint cursor_pos=0;
m_view->cursorPosition (¤t_line_num, &cursor_pos);
QString current_line = getLine ();
@@ -251,4 +259,165 @@
m_doc->removeText (current_line_num, word_start, current_line_num, word_end);
}
+bool RKCommandEditorWindow::provideContext (unsigned int line_rev, QString *context, int *cursor_position) {
+ RK_TRACE (COMMANDEDITOR);
+
+ uint current_line_num=0; uint cursor_pos=0;
+ m_view->cursorPosition (¤t_line_num, &cursor_pos);
+
+ if (line_rev > current_line_num) return false;
+
+ if (line_rev == 0) {
+ *cursor_position = cursor_pos;
+ } else {
+ *cursor_position = -1;
+ }
+ *context = m_doc->textLine (current_line_num - line_rev);
+
+ return true;
+}
+
+//////////////////////// RKFunctionArgHinter //////////////////////////////
+
+#include <qobjectlist.h>
+#include <qvbox.h>
+
+#include "../core/rfunctionobject.h"
+
+RKFunctionArgHinter::RKFunctionArgHinter (RKScriptContextProvider *provider, Kate::View* view) {
+ RK_TRACE (COMMANDEDITOR);
+
+ RKFunctionArgHinter::provider = provider;
+ RKFunctionArgHinter::view = view;
+
+ const QObjectList *children = view->children ();
+ QObjectListIt it (*children);
+ QObject *obj;
+ while ((obj = it.current()) != 0) {
+ ++it;
+ obj->installEventFilter (this);
+ }
+
+ arghints_popup = new QVBox (0, 0, WType_Popup);
+ arghints_popup->setFrameStyle (QFrame::Box | QFrame::Plain);
+ arghints_popup->setLineWidth (1);
+ arghints_popup_text = new QLabel (arghints_popup);
+ arghints_popup->hide ();
+ arghints_popup->setFocusProxy (view);
+}
+
+RKFunctionArgHinter::~RKFunctionArgHinter () {
+ RK_TRACE (COMMANDEDITOR);
+}
+
+void RKFunctionArgHinter::tryArgHint () {
+ RK_TRACE (COMMANDEDITOR);
+
+ // do this in the next event cycle to make sure any inserted characters have truely been inserted
+ QTimer::singleShot (0, this, SLOT (tryArgHintNow ()));
+}
+
+void RKFunctionArgHinter::tryArgHintNow () {
+ RK_TRACE (COMMANDEDITOR);
+
+ int line_rev;
+ int cursor_pos;
+ QString current_context;
+ QString current_line;
+
+ // fetch the most immediate context line. More will be fetched later, if appropriate
+ bool have_context = provider->provideContext (line_rev = 0, ¤t_line, &cursor_pos);
+ RK_ASSERT (have_context);
+ RK_ASSERT (cursor_pos >= 0);
+ current_context = current_line;
+
+ // find the corrresponding opening brace
+ int matching_left_brace_pos;
+ int brace_level = 1;
+ int i = cursor_pos;
+
+ while (true) {
+ if (current_context.at (i) == QChar (')')) {
+ brace_level++;
+ } else if (current_context.at (i) == QChar ('(')) {
+ brace_level--;
+ if (!brace_level) break;
+ }
+
+ --i;
+ if (i < 0) {
+ bool have_context = provider->provideContext (++line_rev, ¤t_line, &cursor_pos);
+ if (!have_context) break;
+
+ RK_ASSERT (cursor_pos < 0);
+ current_context.prepend (current_line);
+ i = current_line.length () - 1;
+ }
+ }
+
+ if (!brace_level) matching_left_brace_pos = i;
+ else {
+ hideArgHint ();
+ return;
+ }
+
+ // now find where the symbol to the left ends
+ // there cannot be a line-break between the opening brace, and the symbol name (or can there?), so no need to fetch further context
+ int potential_symbol_end = matching_left_brace_pos - 1;
+ while ((potential_symbol_end > 0) && current_context.at (potential_symbol_end).isSpace ()) {
+ --potential_symbol_end;
+ }
+ if (current_context.at (potential_symbol_end).isSpace ()) {
+ hideArgHint ();
+ return;
+ }
+
+ // now identify the symbol and object (if any)
+ QString effective_symbol = RKCommonFunctions::getCurrentSymbol (current_context, potential_symbol_end+1);
+ if (effective_symbol.isEmpty ()) {
+ hideArgHint ();
+ return;
+ }
+
+ RObject *object = RObjectList::getObjectList ()->findObject (effective_symbol);
+ if ((!object) || (!object->isType (RObject::Function))) {
+ hideArgHint ();
+ return;
+ }
+
+ // initialize and show popup
+ arghints_popup_text->setText (effective_symbol + " (" + static_cast<RFunctionObject*> (object)->printArgs () + ")");
+ arghints_popup->resize (arghints_popup_text->sizeHint () + QSize (2, 2));
+ arghints_popup->move (view->mapToGlobal (view->cursorCoordinates () + QPoint (0, arghints_popup->height ())));
+ arghints_popup->show ();
+}
+
+void RKFunctionArgHinter::hideArgHint () {
+ RK_TRACE (COMMANDEDITOR);
+ arghints_popup->hide ();
+}
+
+bool RKFunctionArgHinter::eventFilter (QObject *, QEvent *e) {
+ RK_TRACE (COMMANDEDITOR);
+
+ if (e->type () == QEvent::KeyPress || e->type () == QEvent::AccelOverride) {
+ QKeyEvent *k = static_cast<QKeyEvent *> (e);
+
+ if (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return || k->key () == Qt::Key_Up || k->key () == Qt::Key_Down || k->key () == Qt::Key_Left || k->key () == Qt::Key_Right || k->key () == Qt::Key_Home || k->key () == Qt::Key_Tab) {
+ hideArgHint ();
+ } else if (k->key () == Qt::Key_Backspace || k->key () == Qt::Key_Delete){
+ tryArgHint ();
+ } else {
+ QString text = k->text ();
+ if (text == "(") {
+ tryArgHint ();
+ } else if (text == ")") {
+ tryArgHint ();
+ }
+ }
+ }
+
+ return FALSE;
+}
+
#include "rkcommandeditorwindow.moc"
Modified: trunk/rkward/rkward/windows/rkcommandeditorwindow.h
===================================================================
--- trunk/rkward/rkward/windows/rkcommandeditorwindow.h 2006-10-22 18:52:08 UTC (rev 899)
+++ trunk/rkward/rkward/windows/rkcommandeditorwindow.h 2006-10-30 12:29:26 UTC (rev 900)
@@ -26,16 +26,49 @@
#include "../windows/rkmdiwindow.h"
+class QVBox;
+class QLabel;
+
+/** classes wishing to use RKFunctionArgHinter should derive from this, and implement provideContext () */
+class RKScriptContextProvider {
+public:
+ RKScriptContextProvider () {};
+ ~RKScriptContextProvider () {};
+
+ virtual bool provideContext (unsigned int line_rev, QString *context, int *cursor_position) = 0;
+};
+
+/** function argument hinting for RKCommandEditorWindow and RKConsole */
+class RKFunctionArgHinter : public QObject {
+ Q_OBJECT
+public:
+ RKFunctionArgHinter (RKScriptContextProvider *provider, Kate::View* view);
+ ~RKFunctionArgHinter ();
+
+ void tryArgHint ();
+ void hideArgHint ();
+public slots:
+ void tryArgHintNow ();
+protected:
+ bool eventFilter (QObject *o, QEvent *e);
+private:
+ RKScriptContextProvider *provider;
+ Kate::View *view;
+
+ QVBox *arghints_popup;
+ QLabel *arghints_popup_text;
+};
+
class QTimer;
/**
\brief Provides an editor window for R-commands, as well as a text-editor window in general.
-While being called RKCommandEditorWindow, this class handles all sort of text-files, both read/write and read-only. It is an MDI child that is added to the main window, based on KatePart.
+While being called RKCommandEditorWindow, this class handles all sorts of text-files, both read/write and read-only. It is an MDI window that is added to the main window, based on KatePart.
@author Pierre Ecochard
*/
-class RKCommandEditorWindow : public RKMDIWindow {
+class RKCommandEditorWindow : public RKMDIWindow, public RKScriptContextProvider {
// we need the Q_OBJECT thing for some inherits ("RKCommandEditorWindow")-calls in rkward.cpp.
Q_OBJECT
public:
@@ -67,11 +100,16 @@
QString getRDescription ();
KParts::Part *getPart () { return m_doc; };
+
+ bool provideContext (unsigned int line_rev, QString *context, int *cursor_position);
public slots:
/** update Tab caption according to the current url. Display the filename-component of the URL, or - if not available - a more elaborate description of the url. Also appends a "[modified]" if approriate */
void updateCaption ();
+/** called whenever it might be appropriate to show a code completion box. The box is not shown immediately, but only after a timeout (if at all) */
void tryCompletionProxy ();
+/** show a code completion box if appropriate. Use tryCompletionProxy () instead, which will call this function after a timeout */
void tryCompletion ();
+/** called by the Kate part, if an entry was selected from the code completion box. Will remove the current symbol, as the kate part is about to re-add it (in completed form) */
void fixCompletion (KTextEditor::CompletionEntry *, QString *);
protected:
/** reimplemented from KMdiChildView: give the editor window a chance to object to being closed (if unsaved) */
@@ -79,6 +117,7 @@
private:
Kate::Document *m_doc;
Kate::View *m_view;
+ RKFunctionArgHinter *hinter;
QTimer *completion_timer;
/** set syntax highlighting-mode to R syntax */
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