[Geany-Devel] [FT-plugins] Proposed Design
mbrush at xxxxx
Mon Aug 29 00:47:05 UTC 2016
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"
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:
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.
: I'm still waiting for someone to propose a better name :)
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 10622 bytes
Desc: not available
More information about the Devel