[Geany-Devel] RFC: Proxy plugins

Matthew Brush mbrush at xxxxx
Thu May 8 00:33:17 UTC 2014

Hi Thomas,

If the goal is really to enable loading plugins written in other 
languages, we should take a really extensive look at LibPeas before 
ruling it out and duplicating it ourselves. It seems especially 
appropriate since you want to eventually get multi-language support into 
core, and it provides a small library we can have a hard dependency on 
that (IIUC) itself has soft-dependencies on all the stuff we don't want 
to require for Geany (language runtimes, interpreters, etc.).

Disclaimer: I'm not a LibPeas expert or even user but from what I've 
read about it (the docs, tutorials) it sounds like pretty much exactly 
the end-goal we want for Geany plugins.

My $0.02.

Matthew Brush

On 14-05-06 11:40 PM, Thomas Martitz wrote:
> Hello,
> I'm (as of now) motivated to implement proxy plugins (to my amusement,
> until splitwindow2 gets finally reviewed...). Therefore I would like to
> receive comments on my proposed concept and APIs (further below).
> I would also love to discuss about better terms for proxy and "the
> proxied plugins". I think some adorable internal code/nick names could
> help us to not get confused in this business.
> Note that I have implemented very little yet, so there might be unknown
> roadblocks and things can easily change. Please also note that I intend
> to achieve the goals without breaking plugin API/ABI.
> The concept:
> The basic idea is that proxy plugins initially call a Geany API to
> register themselves as proxies, providing criterias to select potential
> plugins (for now, this is only a list of file extensions) and a few
> hooks to call into the plugin when Geany needs it.
> Geany will match files against these criterias and, on match, call into
> the plugin for the first time. This call should probe whether or not the
> plugin can actually handle the plugin. I think this is needed because a)
> criterias/file extensions might be ambiguous and b) the plugin might be
> written against an incompatible version of the proxy (think python 2 vs 3).
> Then when Geany generates the plugin list (i.e. when the user opens
> plugin manager (PM) dialog) it'll call a second time into the proxy.
> This time the purpose is to load the actual plugin, and install
> plugin-specific init(), configure(), help() and cleanup() hooks. Unlike
> in classic plugins these hooks must call into proxy, where they have to
> be dispatched to call the actual plugin code (this is why we call them
> proxy right?).
> Once loaded, Geany generally doesn't know/care about the difference
> between classic plugins and proxied plugins. This achieves the ultimate
> goal: That proxied plugins transparently integrate into the PM dialog
> and become first-class citizens.
> Part of the proposed concept is to add a "fake proxy" for the builtin
> .so-file support. This enables to use the same code for all plugins
> (proxied or not). This should greatly reduce the maintenance effort. The
> fake proxy naturally must be compiled in but otherwise exposes the same
> APIs as actual proxies.
> The APIs:
> This propsal adds 3 major functions and alters the 4 existing plugin hooks.
> plugin_register_proxy(GeanyPlugin *proxy_plugin, ProxyPluginInfo *info,
> gpointer user_data);
> This is initially called by the proxy and lets Geany know about it.
> ProxyPluginInfo contains the criterias and pointers to the probe() and
> load() functions. user_data is proxy-specific and passed to probe().
> gboolean (*probe)(const gchar *file, gpointer user_data, gpointer
> *plugin_data);
> This is implemented in the proxy and should return true when it can
> handle the plugin, it basically replaces the existing
> utils_str_casecmp(G_MODULE_SUFFIX, ...) call. There is a catch though,
> while probe() should be as fast as possible, I expect that some proxies
> still need to load the file half-way or even in full to make that
> decision. In order to maintain that state, it can set the plugin_data
> pointer. This will be passed to the load function. This way loading the
> plugin again can be avoided.
> gboolean (*load)(const gchar *file, gpointer user_data, gpointer
> *plugin_data);
> The same function signature, but a different purpose. The proxy should
> now fully load the plugin specified with file such that is ready to run
> (it has the same signature in case it needs to load in probe() already,
> then this function can be the same as probe()).
> As for the existing hooks, these need gain a parameter (gpointer
> plugin_data). Because the hooks can be indirect now, the proxy needs
> plugin_data to be able to properly dispatch the hooks on a per-plugin
> basis. I.e. the hooks become:
> void (*init) (GeanyData *data, gpointer plugin_data);
> GtkWidget* (*configure) (GtkDialog *dialog, gpointer plugin_data);
> void (*configure_single) (GtkWidget *parent, gpointer plugin_data);
> void (*help) (gpointer plugin_data);
> void (*cleanup) (gpointer plugin_data);
> Because the plugin_data parameter is exclusively for the proxy, the
> actual plugins do not receive it. They still implement the
> non-plugin_data variant. The parameter is added to the end so that these
> can still point to the module symbols for .so file plugins.
> That's it so far. I think this proposal should allow to reach our goal
> (first class plugin scripts) while avoiding to break plugins ABI/API.
> Best regards.
> _______________________________________________
> Devel mailing list
> Devel at lists.geany.org
> https://lists.geany.org/cgi-bin/mailman/listinfo/devel

More information about the Devel mailing list