[Geany-Devel] [FT-plugins] Proposed Design

Matthew Brush mbrush at xxxxx
Mon Aug 29 00:47:05 UTC 2016

Hi All,

After experimenting with a few different ideas and approaches, I think I 
have come up with a way to implement the core of "filetype plugins"[0] 
without too much effort or code.



"Filetype plugin" - or "ft-plugin"; at this point is just normal plugin 
that would call special API functions and implement any number of 
features for any number of filetypes.

"Feature" - one of the features an ft-plugin would want to override, for 
example syntax highlighting or auto-completion.

"Provider" - an ft-plugin that provides one or more features for one or 
more filetypes. For example if it can provide calltips, it could be 
referred to as a "Calltip Provider". Each ft-plugin can have a number of 
"providers" for the various features and filetypes.

"Registration" - the act (ie. function call) of an ft-plugin declaring 
its interest in providing a feature for a filetype. An ft-plugin can 
register to provide one or more features for one or more filetypes.


In this design, a new module (c/h file) would be added to manage the 
filetype plugins and which features they provide for which filetypes. A 
mapping (ex. GHashTable) could be used to map from Filetype to a list 
(ex. GQueue) of data describing the needed information for a registered 
provider. The list would be ordered in the same order as registration 
and could also be re-ordered by the user using a GUI (more on this below).

The order of the list of plugins registered to provide a feature for a 
given feature/filetype pair would determine the priority given when 
Geany asks the provider to perform its function. The callback functions 
could return a boolean telling Geany whether the provider performed its 
function or whether it should try the next provider in the list, similar 
to many GTK+ callbacks. If no provider performs its function, or there 
are no providers registered for a given feature/filetype, then Geany 
would take its existing code path to provide the feature itself.

When a plugin is unloaded, the mapping and lists of providers would be 
updated to remove any providers registered by that plugin so Geany 
doesn't call into an unloaded plugin. The next provider registered (if 
any) would have the first chance to now provide the feature.

When a plugin registers its intent to provide a feature (or perhaps 
after it has registered all the features it wishes to provide), Geany 
could check whether there is already another plugin providing this 
feature. Geany could ask the user if they would like to resolve the 
conflict, and if they would, then it could show a management dialog (see 
attachment for mockup), allowing the user to control the priority of the 
plugin's provider for a given feature/filetype by moving them up or down 
in a list, and possibly being able to completely disable a provider 
entirely (via a checkbox in the list or something).

To give an idea, the registration function called by plugins might look 
something like this:

     gboolean ftplugin_register_provider(GeanyPlugin*,
         GeanyFiletypeID, GeanyFiletypeFeature, GCallback, gpointer);

Or perhaps it could use varargs similar to many GTK+/GObject functions, 
terminated by a sentinel, to register many filetype feature providers in 
one call, making it easier to implement a less annoying conflict 
handling scheme - not nagging after each registration call.

The callback function would have an actual signature suitable for 
implementing the specific feature. For example, the callback for a 
syntax highlighting provider might be something like this:

     gboolean (*) (GeanyPlugin*, GeanyDocument*,
         guint start_pos, guint end_pos, gpointer user_data);

The document would be the document that needs highlighting, and allow 
the plugin to access Scintilla and its buffer. The start/end positions 
would indicate where to highlight. This is in-line with Scintilla's 
'style-needed' notification used to implement container lexers. I don't 
want to get bogged down on the actual specific signatures at this point, 
I just wanted to give an example.

To enable Geany to use the providers, in the existing code just before 
it's about to provide the feature itself as it does now, we could insert 
a check/call to try the ft-plugin providers. If nobody performed the 
feature, then it would continue to the existing code path. This should 
limit the number of changes needed to Geany. Some features would 
necessarily require more changes, for example syntax highlighting would 
require Geany to switch from the Scintilla lexer to the container lexer 
and back as plugins start/stop providing the feature. It will require 
care for features that are activated often to ensure minimal performance 
degradation when looking up and calling into the provider, as this would 
happen in the main code paths (unless someone has a better way).

Hopefully I have described enough details of my proposed design to allow 
everyone to understand what I mean. If there's any questions or 
suggestions, please let me know.

Matthew Brush

[0]: I'm still waiting for someone to propose a better name :)

-------------- next part --------------
A non-text attachment was scrubbed...
Name: ft_plugins_dialog.png
Type: image/png
Size: 10622 bytes
Desc: not available
URL: <http://lists.geany.org/pipermail/devel/attachments/20160828/7354f493/attachment-0001.png>

More information about the Devel mailing list