[rkward/work/consolecompletion] rkward: WIP: Start merging the improved script window hinting into the console.

Thomas Friedrichsmeier null at kde.org
Sun Jan 26 09:51:21 GMT 2020


Git commit 1af9c145e858fb4805e079c90b1702d4edcef1f5 by Thomas Friedrichsmeier.
Committed on 26/01/2020 at 09:50.
Pushed by tfry into branch 'work/consolecompletion'.

WIP: Start merging the improved script window hinting into the console.

M  +5    -6    rkward/rkconsole.cpp
M  +1    -2    rkward/rkconsole.h
M  +5    -5    rkward/windows/rkcodecompletion.cpp
M  +7    -2    rkward/windows/rkcodecompletion.h
M  +0    -162  rkward/windows/rkcommandeditorwindow.cpp
M  +0    -31   rkward/windows/rkcommandeditorwindow.h

https://commits.kde.org/rkward/1af9c145e858fb4805e079c90b1702d4edcef1f5

diff --git a/rkward/rkconsole.cpp b/rkward/rkconsole.cpp
index 2a37f154..b12c9f6e 100644
--- a/rkward/rkconsole.cpp
+++ b/rkward/rkconsole.cpp
@@ -2,7 +2,7 @@
                           rkconsole  -  description
                              -------------------
     begin                : Thu Aug 19 2004
-    copyright            : (C) 2004-2019 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2020 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -54,6 +54,7 @@
 #include "rkglobals.h"
 #include "rkward.h"
 #include "windows/rkhelpsearchwindow.h"
+#include "windows/rkcodecompletion.h"
 #include "rbackend/rkrinterface.h"
 #include "rbackend/rcommand.h"
 #include "settings/rksettings.h"
@@ -63,7 +64,6 @@
 #include "misc/rkstandardicons.h"
 #include "misc/rkstandardactions.h"
 #include "core/robjectlist.h"
-#include "core/rfunctionobject.h"
 
 #include "debug.h"
 
@@ -143,7 +143,7 @@ RKConsole::RKConsole (QWidget *parent, bool tool_window, const char *name) : RKM
 
 	doc->setModified (false);
 
-	hinter = new RKFunctionArgHinter (this, view);
+	new RKCompletionManager (view);
 	
 	setCaption (i18n ("R Console"));
 	console_part = new RKConsolePart (this);
@@ -175,7 +175,6 @@ RKConsole::RKConsole (QWidget *parent, bool tool_window, const char *name) : RKM
 RKConsole::~RKConsole () {
 	RK_TRACE (APP);
 
-	delete hinter;
 	RKSettingsModuleConsole::saveCommandHistory (commands_history.getHistory ());
 }
 
@@ -332,8 +331,8 @@ bool RKConsole::handleKeyPress (QKeyEvent *e) {
 			iface->forceCompletion ();
 			return true;
 		}
-
-		hinter->hideArgHint ();
+#warning TODO
+//		hinter->hideArgHint ();
 		commands_history.append (currentEditingLine ());
 		submitCommand ();
 		return true;
diff --git a/rkward/rkconsole.h b/rkward/rkconsole.h
index 5b7f20de..d68765c7 100644
--- a/rkward/rkconsole.h
+++ b/rkward/rkconsole.h
@@ -2,7 +2,7 @@
                           rkconsole  -  description
                              -------------------
     begin                : Thu Aug 19 2004
-    copyright            : (C) 2004, 2006, 2007, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2020 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -130,7 +130,6 @@ friend class RKConsolePart;
 	RCommand *current_command;
 	KTextEditor::Document *doc;
 	KTextEditor::View *view;
-	RKFunctionArgHinter *hinter;
 
 	static RKConsole *main_console;
 
diff --git a/rkward/windows/rkcodecompletion.cpp b/rkward/windows/rkcodecompletion.cpp
index 6db3aa4f..837a0e10 100644
--- a/rkward/windows/rkcodecompletion.cpp
+++ b/rkward/windows/rkcodecompletion.cpp
@@ -2,7 +2,7 @@
                           rkcodecompletion  -  description
                              -------------------
     begin                : Thu Feb 21 2019
-    copyright            : (C) 2004-2019 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2020 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -58,10 +58,11 @@ public:
 
 //////////////////////// RKCompletionManager //////////////////////
 
-RKCompletionManager::RKCompletionManager (KTextEditor::View* view) : QObject (view) {
+RKCompletionManager::RKCompletionManager (KTextEditor::View* view, Mode _mode) : QObject (view) {
 	RK_TRACE (COMMANDEDITOR);
 
 	_view = view;
+	mode = _mode;
 	keep_active = false;
 	user_triggered = false;
 	ignore_next_trigger = false;
@@ -89,12 +90,11 @@ RKCompletionManager::RKCompletionManager (KTextEditor::View* view) : QObject (vi
 			(*it)->installEventFilter (this);  // to handle Tab-key; installing on the view, alone, is not enough.
 		}
 
-		// HACK: I just can't see to make the object name completion model play nice with automatic invocation.
+		// HACK: I just can't seem to make the object name completion model play nice with automatic invocation.
 		//       However, there is no official way to invoke all registered models, manually. So we try to hack our way
 		//       to a pointer to the default kate keyword completion model
 		kate_keyword_completion_model = KTextEditor::Editor::instance ()->findChild<KTextEditor::CodeCompletionModel *> ();
 		if (!kate_keyword_completion_model) kate_keyword_completion_model = view->findChild<KTextEditor::CodeCompletionModel *> (QString());
-
 	} else {
 		RK_ASSERT (false);  // Not a katepart?
 	}
@@ -222,7 +222,7 @@ void RKCompletionManager::updateCallHint () {
 	while (potential_symbol_end < -1 && line >= 0) {
 		--line;
 		QString context_line = doc->line (line);
-		if (context_line.startsWith ('>')) continue; // For console: TODO limit to console
+		if (mode == Console && !context_line.startsWith ('>')) continue; // skip output lines
 		full_context.prepend (context_line);
 
 		int pos = context_line.length () - 1;
diff --git a/rkward/windows/rkcodecompletion.h b/rkward/windows/rkcodecompletion.h
index c9857c6a..131480bf 100644
--- a/rkward/windows/rkcodecompletion.h
+++ b/rkward/windows/rkcodecompletion.h
@@ -2,7 +2,7 @@
                           rkcodecompletion  -  description
                              -------------------
     begin                : Thu Feb 21 2019
-    copyright            : (C) 2004-2019 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2020 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -37,7 +37,11 @@ class RKArgumentHintModel;
 class RKCompletionManager : public QObject {
 	Q_OBJECT
 public:
-	RKCompletionManager (KTextEditor::View *view);
+	enum Mode {
+		Script,
+		Console
+	};
+	RKCompletionManager (KTextEditor::View *view, Mode=Script);
 	~RKCompletionManager ();
 
 	QString currentCompletionWord () const;
@@ -71,6 +75,7 @@ private:
 
 	KTextEditor::View *_view;
 	KTextEditor::Cursor cached_position;
+	Mode mode;
 
 	KTextEditor::Range symbol_range;
 	KTextEditor::Cursor call_opening;
diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkcommandeditorwindow.cpp
index fe4d5091..5c9269e1 100644
--- a/rkward/windows/rkcommandeditorwindow.cpp
+++ b/rkward/windows/rkcommandeditorwindow.cpp
@@ -242,12 +242,10 @@ RKCommandEditorWindow::RKCommandEditorWindow (QWidget *parent, const QUrl _url,
 	// somehow the katepart loses the context menu each time it loses focus
 	connect (m_view, &KTextEditor::View::focusIn, this, &RKCommandEditorWindow::focusIn);
 
-	hinter = 0;
 	if (use_r_highlighting) {
 		RKCommandHighlighter::setHighlighting (m_doc, RKCommandHighlighter::RScript);
 		if (flags & RKCommandEditorFlags::UseCodeHinting) {
 			new RKCompletionManager (m_view);
-			//hinter = new RKFunctionArgHinter (this, m_view);
 		}
 	} else {
 		RKCommandHighlighter::setHighlighting (m_doc, RKCommandHighlighter::Automatic);
@@ -276,7 +274,6 @@ RKCommandEditorWindow::~RKCommandEditorWindow () {
 		m_view->writeSessionConfig (viewconf);
 	}
 
-	delete hinter;
 	discardPreview ();
 	delete m_view;
 	QList<KTextEditor::View*> views = m_doc->views ();
@@ -1050,165 +1047,6 @@ void RKCommandEditorWindow::selectionChanged (KTextEditor::View* view) {
 	}
 }
 
-//////////////////////// RKFunctionArgHinter //////////////////////////////
-
-#include <QToolTip>
-#include <QStyle>
-
-#include "../core/rfunctionobject.h"
-
-RKFunctionArgHinter::RKFunctionArgHinter (RKScriptContextProvider *provider, KTextEditor::View* view) {
-	RK_TRACE (COMMANDEDITOR);
-
-	RKFunctionArgHinter::provider = provider;
-	RKFunctionArgHinter::view = view;
-
-	const QObjectList children = view->children ();
-	for (QObjectList::const_iterator it = children.constBegin(); it != children.constEnd (); ++it) {
-		QObject *obj = *it;
-		obj->installEventFilter (this);
-	}
-
-	arghints_popup = new QLabel (0, Qt::ToolTip);
-	arghints_popup->setMargin (2);
-	// HACK trying hard to trick the style into using the correct color
-	// ... and sometimes we still get white on yellow in some styles. Sigh...
-	// A simple heuristic tries to detect the worst cases of unreasonably low contrast, and forces black on light blue, then.
-	QPalette p = QToolTip::palette ();
-	QColor b = p.color (QPalette::Inactive, QPalette::ToolTipBase);
-	QColor f = p.color (QPalette::Inactive, QPalette::ToolTipText);
-	if ((qAbs (f.greenF () - b.greenF ()) + qAbs (f.redF () -  b.redF ()) + qAbs (f.yellowF () - b.yellowF ())) < .6) {
-		f = Qt::black;
-		b = QColor (192, 219, 255);
-	}
-	p.setColor (QPalette::Inactive, QPalette::WindowText, f);
-	p.setColor (QPalette::Inactive, QPalette::Window, b);
-	p.setColor (QPalette::Inactive, QPalette::ToolTipText, f);
-	p.setColor (QPalette::Inactive, QPalette::ToolTipBase, b);
-	arghints_popup->setForegroundRole (QPalette::ToolTipText);
-	arghints_popup->setBackgroundRole (QPalette::ToolTipBase);
-	arghints_popup->setPalette (p);
-	arghints_popup->setFrameStyle (QFrame::Box);
-	arghints_popup->setLineWidth (1);
-	arghints_popup->setWordWrap (true);
-	arghints_popup->setWindowOpacity (arghints_popup->style ()->styleHint (QStyle::SH_ToolTipLabel_Opacity, 0, arghints_popup) / 255.0);
-	arghints_popup->hide ();
-	active = false;
-
-	connect (&updater, &QTimer::timeout, this, &RKFunctionArgHinter::updateArgHintWindow);
-}
-
-RKFunctionArgHinter::~RKFunctionArgHinter () {
-	RK_TRACE (COMMANDEDITOR);
-	delete arghints_popup;
-}
-
-void RKFunctionArgHinter::tryArgHint () {
-	RK_TRACE (COMMANDEDITOR);
-
-	if (!RKSettingsModuleCommandEditor::argHintingEnabled ()) return;
-
-	// do this in the next event cycle to make sure any inserted characters have truly been inserted
-	QTimer::singleShot (0, this, SLOT (tryArgHintNow()));
-}
-
-void RKFunctionArgHinter::tryArgHintNow () {
-	RK_TRACE (COMMANDEDITOR);
-
-	// find the active opening brace
-	int line_rev = -1;
-	QList<int> unclosed_braces;
-	QString full_context;
-	while (unclosed_braces.isEmpty ()) {
-		QString context_line = provider->provideContext (++line_rev);
-		if (context_line.isNull ()) break;
-		full_context.prepend (context_line);
-		for (int i = 0; i < context_line.length (); ++i) {
-			QChar c = context_line.at (i);
-			if (c == '"' || c == '\'' || c == '`') {  // NOTE: this algo does not produce good results on string constants spanning newlines.
-				i = RKCommonFunctions::quoteEndPosition (c, context_line, i + 1);
-				if (i < 0) break;
-				continue;
-			} else if (c == '\\') {
-				++i;
-				continue;
-			} else if (c == '(') {
-				unclosed_braces.append (i);
-			} else if (c == ')') {
-				if (!unclosed_braces.isEmpty()) unclosed_braces.pop_back ();
-			}
-		}
-	}
-
-	int potential_symbol_end = unclosed_braces.isEmpty () ? -1 : unclosed_braces.last () - 1;
-
-	// now find out where the symbol to the left of the opening brace 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
-	while ((potential_symbol_end >= 0) && full_context.at (potential_symbol_end).isSpace ()) {
-		--potential_symbol_end;
-	}
-	if (potential_symbol_end <= 0) {
-		hideArgHint ();
-		return;
-	}
-
-	// now identify the symbol and object (if any)
-	QString effective_symbol = RKCommonFunctions::getCurrentSymbol (full_context, potential_symbol_end);
-	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->setText (effective_symbol + " (" + static_cast<RFunctionObject*> (object)->printArgs () + ')');
-	arghints_popup->resize (arghints_popup->sizeHint () + QSize (2, 2));
-	active = true;
-	updater.start (50);
-	updateArgHintWindow ();
-}
-
-void RKFunctionArgHinter::updateArgHintWindow () {
-	RK_TRACE (COMMANDEDITOR);
-
-	if (!active) return;
-
-	arghints_popup->move (view->mapToGlobal (view->cursorPositionCoordinates () + QPoint (0, arghints_popup->fontMetrics ().lineSpacing () + arghints_popup->margin ()*2)));
-	if (view->hasFocus ()) arghints_popup->show ();
-	else arghints_popup->hide ();
-}
-
-void RKFunctionArgHinter::hideArgHint () {
-	RK_TRACE (COMMANDEDITOR);
-	arghints_popup->hide ();
-	active = false;
-	updater.stop ();
-}
-
-bool RKFunctionArgHinter::eventFilter (QObject *, QEvent *e) {
-	if (e->type () == QEvent::KeyPress || e->type () == QEvent::ShortcutOverride) {
-		RK_TRACE (COMMANDEDITOR);	// avoid loads of empty traces, putting this here
-		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 == "(") || (text == ")") || (text == ",")) {
-				tryArgHint ();
-			}
-		}
-	}
-
-	return false;
-}
 
 // static
 KTextEditor::Document* RKCommandHighlighter::_doc = 0;
diff --git a/rkward/windows/rkcommandeditorwindow.h b/rkward/windows/rkcommandeditorwindow.h
index 21876b55..ebe53893 100644
--- a/rkward/windows/rkcommandeditorwindow.h
+++ b/rkward/windows/rkcommandeditorwindow.h
@@ -72,36 +72,6 @@ public:
 	virtual void currentHelpContext (QString *symbol, QString *package) = 0;
 };
 
-class RObject;
-/** function argument hinting for RKCommandEditorWindow and RKConsole */
-class RKFunctionArgHinter : public QObject {
-	Q_OBJECT
-public:
-	RKFunctionArgHinter (RKScriptContextProvider *provider, KTextEditor::View* view);
-	~RKFunctionArgHinter ();
-
-	/** Try to show an arg hint now */
-	void tryArgHint ();
-	/** Hide the arg hint (if shown) */
-	void hideArgHint ();
-public slots:
-	/** Internal worker function for tryArgHint () */
-	void tryArgHintNow ();
-
-	void updateArgHintWindow ();
-protected:
-	/** The (keypress) events of the view are filtered to determine, when to show / hide an argument hint */
-	bool eventFilter (QObject *, QEvent *e) override;
-private:
-	RKScriptContextProvider *provider;
-	KTextEditor::View *view;
-
-	/** A timer to refresh the hint window periodically. This is a bit sorry, but it's really hard to find out, when the view has been moved, or gains/loses focus. While possible, this approach uses much less code. */
-	QTimer updater;
-	bool active;
-	QLabel *arghints_popup;
-};
-
 class RKJobSequence;
 class RKXMLGUIPreviewArea;
 class RKPreviewManager;
@@ -207,7 +177,6 @@ private:
 	KTextEditor::Document *m_doc;
 	KTextEditor::View *m_view;
 	KTextEditor::MovingInterface *smart_iface;
-	RKFunctionArgHinter *hinter;
 
 	void initializeActions (KActionCollection* ac);
 



More information about the rkward-tracker mailing list