Commits

Anonymous committed b0e5ce5

Add API for event handling

- This commit defines the API for handling Neovim events,
providing two ways to receive events
- New method setNeovimEventHandler to define QObject whose slots
are called on events
- New signal notification() catches ALL notifications however the
arguments are passed as a QVariant - this is more usefull for
debugging or internal use since you still have to decapsulate
the varuant.
- Updated example

Comments (0)

Files changed (3)

examples/example4.cpp

 	qDebug() << s.waitForConnected();
 
 	NeovimQt::NeovimConnector c(&s);
+	/**
+	 * This is a terrible idea, but works well as an example the "quit"
+	 * event will be handled by the QCoreApplication::quit() slot :D
+	 */
+	c.setNeovimEventHandler(&app);
+
+	QObject::connect(&c, &NeovimQt::NeovimConnector::notification,
+			[](const QByteArray& name, const QVariant& args) {
+				qDebug() << name << args;
+			});
 
 	// You must wait for the ready signal before trying to use the neovim object
 	// otherwise funky things will happen, like all your calls being dropped
 			c.neovimObject()->vim_command(QString("call send_event(%1, \"test-event\", [1,2,3])").arg(c.channel()));
 			c.neovimObject()->vim_command(QString("call send_event(%1, \"test-event2\", [1,2,\"WAT\"])").arg(c.channel()));
 
+			c.neovimObject()->vim_command(QString("call send_event(%1, \"quit\", [])").arg(c.channel()));
 			});
 
 

src/neovimconnector.cpp

 #include "neovimconnector.h"
 #include <QtGlobal>
+#include <QMetaMethod>
 
 namespace NeovimQt {
 
 NeovimConnector::NeovimConnector(QIODevice *s)
-:QObject(), reqid(0), m_socket(s), m_error(NoError), m_neovimobj(NULL), m_channel(0)
+:QObject(), reqid(0), m_socket(s), m_error(NoError), m_neovimobj(NULL), 
+	m_eventHandler(NULL), m_channel(0)
 {
 	qRegisterMetaType<NeovimError>("NeovimError");
 
 	req->deleteLater();
 }
 
-void NeovimConnector::dispatchNotification(msgpack_object& req)
+/**
+ * [type(2), method, params]
+ *
+ */
+void NeovimConnector::dispatchNotification(msgpack_object& nt)
 {
-	// TODO: call notification handler ...
-	qWarning() << "We do not support notifications (yet)" << req;
+	QByteArray methodName = to_QByteArray(nt.via.array.ptr[1]);
+	bool convfail;
+	QVariant args = to_Object(nt.via.array.ptr[2], &convfail);
+	if ( convfail ) {
+		qDebug() << "Unable to unpack notification parameter list";
+		return;
+	}
+	emit notification(methodName, args);
+
+	if ( !m_eventHandler ) {
+		return;
+	}
+
+	const QMetaObject *meta = m_eventHandler->metaObject();
+	for (int i=0; i<meta->methodCount(); i++) {
+		QMetaMethod meth = meta->method(i);
+		if ( meth.access() != QMetaMethod::Public ||
+				meth.methodType() != QMetaMethod::Slot) {
+			// Only call public slots
+			continue;
+		}
+
+		if ( meth.name() != methodName ) {
+			continue;
+		}
+		
+		bool match=true;
+		QList<QGenericArgument> slotArgs;
+		for ( int argidx=0; argidx < args.toList().size(); argidx++ ) {
+			const QVariant& v = args.toList().at(argidx);
+			// This cast should be safe (See docs for QVariant::type)
+			if ( meth.parameterType(argidx) != (QMetaType::Type)v.type() ) {
+				match=false;
+				break;
+			}
+			slotArgs << QGenericArgument(QMetaType::typeName(v.type()), const_cast<void*>(v.constData()));
+		}
+		if ( !match ) {
+			continue;
+		}
+
+		// 10 arguments is our limit
+		bool ok = meth.invoke(m_eventHandler,
+				slotArgs.value(0),
+				slotArgs.value(1),
+				slotArgs.value(2),
+				slotArgs.value(3),
+				slotArgs.value(4),
+				slotArgs.value(5),
+				slotArgs.value(6),
+				slotArgs.value(7),
+				slotArgs.value(8),
+				slotArgs.value(9)
+				);
+		if ( ok ) {
+			return;
+		}
+	}
 }
 
 Neovim* NeovimConnector::neovimObject()

src/neovimconnector.h

 
 	Neovim* neovimObject();
 	uint64_t channel() {return m_channel;}
+	void setNeovimEventHandler(QObject* h) { m_eventHandler = h; }
 
 signals:
 	void ready();
 	void error(NeovimError);
+	void notification(const QByteArray &name, const QVariant& args);
 
 protected:
 	void setError(NeovimError err, const QString& msg);
 	QHash<Function::FunctionId, uint64_t> m_functionToId;
 	QHash<uint64_t, Function::FunctionId> m_idToFunction;
 	Neovim *m_neovimobj;
+	QObject *m_eventHandler;
 	uint64_t m_channel;
 };
 } // namespace NeovimQt