[rkward/work/unified_hinting2] rkward/windows: Add file name completion to the new unified hinter.

Thomas Friedrichsmeier null at kde.org
Fri Feb 8 21:35:02 GMT 2019


Git commit 10a9d9b2b7cfdc82fc46be1024ecbffca60f56e8 by Thomas Friedrichsmeier.
Committed on 08/02/2019 at 21:32.
Pushed by tfry into branch 'work/unified_hinting2'.

Add file name completion to the new unified hinter.

(As before, when symbol starts with a quote). As contrary to the old completion in console, this gets invoked, automatically, move the actual work to a worker thread.

M  +98   -14   rkward/windows/rkcommandeditorwindow.cpp
M  +31   -1    rkward/windows/rkcommandeditorwindow.h

https://commits.kde.org/rkward/10a9d9b2b7cfdc82fc46be1024ecbffca60f56e8

diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkcommandeditorwindow.cpp
index 1f93905f..820094a6 100644
--- a/rkward/windows/rkcommandeditorwindow.cpp
+++ b/rkward/windows/rkcommandeditorwindow.cpp
@@ -1187,13 +1187,12 @@ RKCompletionManager::RKCompletionManager (KTextEditor::View* view) : QObject (vi
 	RK_TRACE (COMMANDEDITOR);
 
 	RKCompletionManager::view = view;
-	completion_model = 0;
-	kate_keyword_completion_model = 0;
 
 	cc_iface = qobject_cast<KTextEditor::CodeCompletionInterface*> (view);
 	if (cc_iface) {
 		cc_iface->setAutomaticInvocationEnabled (false);
 		completion_model = new RKCodeCompletionModel (this);
+		file_completion_model = new RKFileCompletionModel (this);
 		completion_timer = new QTimer (this);
 		completion_timer->setSingleShot (true);
 		connect (completion_timer, &QTimer::timeout, this, &RKCompletionManager::tryCompletion);
@@ -1220,6 +1219,7 @@ RKCompletionManager::~RKCompletionManager () {
 void RKCompletionManager::tryCompletionProxy () {
 	if (RKSettingsModuleCommandEditor::completionEnabled ()) {
 		if (cc_iface && cc_iface->isCompletionActive ()) {
+			// TODO: Actually, in this case we should try to _update_ the existing completion, i.e. try to save some CPU cycles.
 			tryCompletion ();
 		} else if (cc_iface) {
 			completion_timer->start (RKSettingsModuleCommandEditor::completionTimeout ());
@@ -1257,12 +1257,17 @@ void RKCompletionManager::tryCompletion () {
 
 	QString word = currentCompletionWord ();
 	if (word.length () >= RKSettingsModuleCommandEditor::completionMinChars ()) {
-		completion_model->updateCompletionList (word);
-		if (completion_model->isEmpty ()) {
+		// as a very simple heuristic: If the current symbol starts with a quote, we should probably attempt file name completion, instead of symbol name completion
+		bool filename_completion = (word.startsWith ('\"') || word.startsWith ('\'') || word.startsWith ('`'));
+
+		completion_model->updateCompletionList (filename_completion ? QString () : word);
+		file_completion_model->updateCompletionList (filename_completion ? word.mid (1) : QString ());
+		if (completion_model->isEmpty () && file_completion_model->isEmpty ()) {
 			if ((!kate_keyword_completion_model) || (kate_keyword_completion_model->rowCount () < 1)) cc_iface->abortCompletion ();
 		} else {
 			if (!cc_iface->isCompletionActive ()) {
 				cc_iface->startCompletion (symbol_range, completion_model);
+				cc_iface->startCompletion (symbol_range, file_completion_model);
 				if (kate_keyword_completion_model) cc_iface->startCompletion (symbol_range, kate_keyword_completion_model);
 			}
 		}
@@ -1374,16 +1379,6 @@ KTextEditor::Range RKCodeCompletionModel::completionRange (KTextEditor::View *vi
 	return KTextEditor::Range (position.line (), start, position.line (), end);
 }
 
-void RKCodeCompletionModel::completionInvoked (KTextEditor::View*, const KTextEditor::Range&, InvocationType) {
-	RK_TRACE (COMMANDEDITOR);
-
-	// we totally ignore whichever range the katepart thinks we should offer a completion on.
-	// it is often wrong, esp, when there are dots in the symbol
-// KDE4 TODO: This may no longer be needed, if the katepart gets fixed not to abort completions when the range
-// contains dots or other special characters
-	updateCompletionList (manager->currentCompletionWord ());
-}
-
 void RKCodeCompletionModel::executeCompletionItem (KTextEditor::View *view, const KTextEditor::Range &word, const QModelIndex &index) const {
 	RK_TRACE (COMMANDEDITOR);
 
@@ -1395,6 +1390,7 @@ void RKCodeCompletionModel::executeCompletionItem (KTextEditor::View *view, cons
 QVariant RKCodeCompletionModel::data (const QModelIndex& index, int role) const {
 	if (isHeaderItem (index)) {
 		if (role == Qt::DisplayRole) return i18n ("Objects on search path");
+		if (role == KTextEditor::CodeCompletionModel::GroupRole) return Qt::DisplayRole;
 		return QVariant ();
 	}
 
@@ -1418,7 +1414,95 @@ QVariant RKCodeCompletionModel::data (const QModelIndex& index, int role) const
 	return QVariant ();
 }
 
+//////////////////////// RKFileCompletionModel ////////////////////
+#include <KUrlCompletion>
+RKFileCompletionModelWorker::RKFileCompletionModelWorker (const QString &_string) : QThread () {
+	RK_TRACE (COMMANDEDITOR);
+	string = _string;
+	connect (this, &QThread::finished, this, &QObject::deleteLater);
+}
+
+void RKFileCompletionModelWorker::run () {
+	RK_TRACE (COMMANDEDITOR);
+
+	KUrlCompletion comp;
+	comp.setDir (QUrl::fromLocalFile (QDir::currentPath ()));
+	comp.makeCompletion (string);
+	QStringList files = comp.allMatches ();
+
+	comp.setMode (KUrlCompletion::ExeCompletion);
+	comp.makeCompletion (string);
+	QStringList exes = comp.allMatches ();
+
+	emit (completionsReady (string, exes, comp.allMatches ()));
+}
+
+RKFileCompletionModel::RKFileCompletionModel (RKCompletionManager* manager) : RKCompletionModelBase (manager) {
+	RK_TRACE (COMMANDEDITOR);
+	worker = 0;
+}
+
+RKFileCompletionModel::~RKFileCompletionModel () {
+	RK_TRACE (COMMANDEDITOR);
+}
+
+void RKFileCompletionModel::updateCompletionList(const QString& fragment) {
+	RK_TRACE (COMMANDEDITOR);
+
+	if (current_fragment == fragment) return;
+
+	current_fragment = fragment;
+	launchThread ();
+}
+
+void RKFileCompletionModel::launchThread () {
+	RK_TRACE (COMMANDEDITOR);
+
+	if (current_fragment.isEmpty ()) {
+		completionsReady (QString (), QStringList (), QStringList ());
+	} else if (!worker) {
+		RK_DEBUG (COMMANDEDITOR, DL_DEBUG, "Launching filename completion thread for '%s'", qPrintable (current_fragment));
+		worker = new RKFileCompletionModelWorker (current_fragment);
+		connect (worker, &RKFileCompletionModelWorker::completionsReady, this, &RKFileCompletionModel::completionsReady);
+		worker->start ();
+	}
+}
+
+void RKFileCompletionModel::completionsReady (const QString& string, const QStringList& exes, const QStringList& files) {
+	RK_TRACE (COMMANDEDITOR);
+
+	RK_DEBUG (COMMANDEDITOR, DL_DEBUG, "Filename completion finished for '%s': %d matches", qPrintable (string), files.size () + exes.size ());
+	worker = 0;
+	if (current_fragment == string) {
+		beginResetModel ();
+		names = files + exes; // TODO: This could be prettier
+		n_completions = names.size ();
+		endResetModel ();
+	} else {
+		launchThread ();
+	}
+}
+
+QVariant RKFileCompletionModel::data (const QModelIndex& index, int role) const {
+	if (isHeaderItem (index)) {
+		if (role == Qt::DisplayRole) return i18n ("Local file names");
+		if (role == KTextEditor::CodeCompletionModel::GroupRole) return Qt::DisplayRole;
+		return QVariant ();
+	}
 
+	int col = index.column ();
+	int row = index.row ();
+	if ((role == Qt::DisplayRole) || (role == KTextEditor::CodeCompletionModel::CompletionRole)) {
+		if (col == KTextEditor::CodeCompletionModel::Name) {
+			return (names.value (row));
+		}
+	} else if (role == KTextEditor::CodeCompletionModel::InheritanceDepth) {
+		return (row);  // disable sorting
+	} else if (role == KTextEditor::CodeCompletionModel::MatchQuality) {
+		return (10);
+	}
+	return QVariant ();
+}
 
 // static
 KTextEditor::Document* RKCommandHighlighter::_doc = 0;
diff --git a/rkward/windows/rkcommandeditorwindow.h b/rkward/windows/rkcommandeditorwindow.h
index 9d42c397..83cabcc8 100644
--- a/rkward/windows/rkcommandeditorwindow.h
+++ b/rkward/windows/rkcommandeditorwindow.h
@@ -105,6 +105,7 @@ private:
 };
 
 class RKCodeCompletionModel;
+class RKFileCompletionModel;
 class RKCompletionManager : public QObject {
 	Q_OBJECT
 public:
@@ -125,6 +126,7 @@ private:
 	void tryCompletionProxy ();
 	KTextEditor::CodeCompletionInterface *cc_iface;
 	RKCodeCompletionModel *completion_model;
+	RKFileCompletionModel *file_completion_model;
 	KTextEditor::CodeCompletionModel* kate_keyword_completion_model;
 	QTimer *completion_timer;
 
@@ -169,7 +171,6 @@ public:
 	KTextEditor::Range completionRange (KTextEditor::View *view, const KTextEditor::Cursor &position) override;
 
 	void updateCompletionList (const QString& symbol);
-	void completionInvoked (KTextEditor::View *, const KTextEditor::Range &, InvocationType) override;
 	void executeCompletionItem (KTextEditor::View *view, const KTextEditor::Range &word, const QModelIndex &index) const override;
 	QVariant data (const QModelIndex& index, int role=Qt::DisplayRole) const override;
 private:
@@ -178,6 +179,35 @@ private:
 	QString current_symbol;
 };
 
+#include <QThread>
+class RKFileCompletionModelWorker : public QThread {
+	Q_OBJECT
+public:
+	explicit RKFileCompletionModelWorker (const QString &string);
+signals:
+	void completionsReady (const QString &string, const QStringList &exes, const QStringList &files);
+private:
+	void run () override;
+	QString string;
+};
+
+class RKFileCompletionModel : public RKCompletionModelBase {
+	Q_OBJECT
+public:
+	explicit RKFileCompletionModel (RKCompletionManager *manager);
+	~RKFileCompletionModel ();
+
+	void updateCompletionList (const QString& fragment);
+	QVariant data (const QModelIndex& index, int role=Qt::DisplayRole) const override;
+private slots:
+	void completionsReady (const QString &string, const QStringList &exes, const QStringList &files);
+private:
+	void launchThread ();
+	QStringList names;
+	QString current_fragment;
+	RKFileCompletionModelWorker *worker;
+};
+
 class RKJobSequence;
 class RKXMLGUIPreviewArea;
 class RKPreviewManager;



More information about the rkward-tracker mailing list