Geany dev
Plugin Extension HowTo

Introduction

Originally the Geany plugin API only allowed plugins to add to Geany functionality, plugins could not modify Geany built-in functionality, but since Geany 2.1 the PluginExtension API allows plugins to take over some of the core Geany functionality: autocopletion, calltip display, symbol goto, and typename highlighting inside document.

Initialization and cleanup

Plugins using the PluginExtension API are just normal plugins and behave as described in Plugin HowTo.

First, any plugin interested in using this interface has to register its PluginExtension structure pointer using plugin_extension_register(). This typically happens in the init() function of the plugin. Registered PluginExtension pointers have to be unregistered before the plugin is unloaded using plugin_extension_unregister(), typically inside the cleanup() function of the plugin.

Implementing extensions

Inside the PluginExtension struct, the plugin fills-in the pointers of the functions it wishes to implement. Typically, these functions come in pairs:

  • functions assigned to members ending with _provided are used by Geany to query the plugin whether it implements the particular feature for the passed document
  • functions assigned to members ending with _perform are used by Geany to pass control to the plugin to perform the feature instead of performing the Geany built-in functionality.

When the plugin returns TRUE from the function assigned to the _provided member of PluginExtension, it indicates it wants to take control of the particular feature and disable Geany's implementation. However, returning TRUE does not automatically guarantee that the plugin's implementation is executed - if there are multiple plugins competing for implementing a feature, the extension with the highest priority passed into the plugin_extension_register() function gets executed.

A plugin can perform a check if it gets executed for the particular feature; e.g. for autocompletion the plugin can use plugin_extension_autocomplete_provided() which returns TRUE if the passed extension is executed, taking into account all registered extension priorities and the return values of all functions assigned to autocomplete_provided members of the registered extensions. This can be used if the plugin needs to perform auxiliary actions outside the function assigned to autocomplete_perform to verify it is actually active for this feature.

Example

Below you will find an example of a plugin implementing autocompletion for Python. The full version of this code can be found under plugins/demopluginext.c inside the Geany repository.

/* License blob */
#include <geanyplugin.h>
static gboolean autocomplete_provided(GeanyDocument *doc, gpointer data)
{
/* Check whether the plugin provides the feature for the passed document */
return doc->file_type->id == GEANY_FILETYPES_PYTHON;
}
static void autocomplete_perform(GeanyDocument *doc, gboolean force, gpointer data)
{
/* The autocompletion logic comes here, including the autocompletion UI
* display (either using some custom widget or using Scintilla's
* SCI_AUTOCSHOW) */
}
/* The PluginExtension struct - we only implement autocompletion here. */
static PluginExtension extension = {
.autocomplete_provided = autocomplete_provided,
.autocomplete_perform = autocomplete_perform
};
static gboolean on_editor_notify(G_GNUC_UNUSED GObject *obj, GeanyEditor *editor, SCNotification *nt,
G_GNUC_UNUSED gpointer user_data)
{
if (nt->nmhdr.code == SCN_AUTOCSELECTION)
{
{
/* This is an example of using plugin_extension_autocomplete_provided()
* to detect whether this plugin extension was used to perform
* autocompletion. */
msgwin_status_add("PluginExtensionDemo autocompleted '%s'", nt->text);
}
}
return FALSE;
}
{"editor-notify", (GCallback) &on_editor_notify, FALSE, NULL},
{NULL, NULL, FALSE, NULL}
};
static gboolean init_func(GeanyPlugin *plugin, gpointer pdata)
{
/* Extension registration */
plugin_extension_register(&extension, "Python keyword autocompletion", 450, NULL);
return TRUE;
}
static void cleanup_func(GeanyPlugin *plugin, gpointer pdata)
{
/* Extension unregistration */
}
G_MODULE_EXPORT
{
plugin->info->name = "PluginExtensionDemo";
plugin->info->description = "Demo performing simple Python keyword autocompletion";
plugin->info->version = "1.0";
plugin->info->author = "John Doe <john.doe@example.org>";
plugin->funcs->init = init_func;
plugin->funcs->cleanup = cleanup_func;
GEANY_PLUGIN_REGISTER(plugin, 248);
}
Single include for plugins.
void msgwin_status_add(const gchar *format,...)
Logs a formatted status message without setting the status bar.
Definition: msgwindow.c:520
void geany_load_module(GeanyPlugin *plugin)
Called by Geany when a plugin library is loaded.
#define GEANY_PLUGIN_REGISTER(plugin, min_api_version)
Convenience macro to register a plugin.
Definition: plugindata.h:323
gboolean plugin_extension_autocomplete_provided(GeanyDocument *doc, PluginExtension *ext)
Plugins can call this function to check whether, based on the extensions registered and the provided ...
Definition: pluginextension.c:219
void plugin_extension_unregister(PluginExtension *extension)
Plugins are responsible for calling this function when they no longer provide the extension,...
Definition: pluginextension.c:119
void plugin_extension_register(PluginExtension *extension, const gchar *ext_name, gint priority, gpointer data)
Registers the provided extension in Geany.
Definition: pluginextension.c:91
PluginCallback plugin_callbacks[]
An array for connecting GeanyObject events, which should be terminated with {NULL,...
Definition: pluginsymbols.c:75
Structure for representing an open tab with all its properties.
Definition: document.h:81
GeanyFiletype * file_type
The filetype for this document, it's only a reference to one of the elements of the global filetypes ...
Definition: document.h:101
Editor-owned fields for each document.
Definition: editor.h:154
struct GeanyDocument * document
The document associated with the editor.
Definition: editor.h:155
GeanyFiletypeID id
Index in filetypes.
Definition: filetypes.h:156
gboolean(* init)(GeanyPlugin *plugin, gpointer pdata)
Called to initialize the plugin, when the user activates it (must not be NULL)
Definition: plugindata.h:299
PluginCallback * callbacks
Array of plugin-provided signal handlers.
Definition: plugindata.h:297
void(* cleanup)(GeanyPlugin *plugin, gpointer pdata)
Called when the plugin is disabled or when Geany exits (must not be NULL)
Definition: plugindata.h:305
Basic information for the plugin and identification.
Definition: plugindata.h:232
PluginInfo * info
Fields set in plugin_set_info().
Definition: plugindata.h:233
GeanyPluginFuncs * funcs
Functions implemented by the plugin, set in geany_load_module()
Definition: plugindata.h:235
Callback array entry type used with the plugin_callbacks symbol.
Definition: plugindata.h:147
Structure serving as an interface between plugins and Geany allowing plugins to inform Geany about wh...
Definition: pluginextension.h:63
gboolean(* autocomplete_provided)(GeanyDocument *doc, gpointer data)
Pointer to function called by Geany to check whether the plugin implements autocompletion for the pro...
Definition: pluginextension.h:80
const gchar * version
The version of the plugin.
Definition: plugindata.h:100
const gchar * description
The description of the plugin.
Definition: plugindata.h:98
const gchar * name
The name of the plugin.
Definition: plugindata.h:96
const gchar * author
The author of the plugin.
Definition: plugindata.h:102