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

Lex Trotman elextr at xxxxx
Mon Aug 29 01:59:32 UTC 2016


On 29 August 2016 at 10:47, Matthew Brush <mbrush at codebrainz.ca> wrote:
> 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.
>
> ----
>
> Terminology:
>
> "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.

Good idea to keep the relationship between features and plugins open.
More adaptable to languages with different features and could allow
common solutions for a feature by re-using a plugin ({} indentations
for eg to keep Colomban happy).

>
> "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.

I think the registration data should go in the plugin data file that
Thomas added, not require plugins to be loaded to register, otherwise
all language plugins will be loaded at all times just so they can call
the function to be registered.

>
> ----
>
> 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).

Would need to ensure plugin loading will re-load in the
original/specified order, IIRC it currently re-loads in alpha order.

>
> 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.

This makes sense, but so does Colombans desire for plugins to be able
to improve on the work of other plugins so you don't have to have all
plugins re-implement the basic functionality.  Not immediately sure
how to reconcile these two options, unless Colombans desire is
provided by having the dependent plugin have to call the basic plugin
function directly, so its not Geany's problem.

>
> 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.

Agree (thats just how lists work anyway :)

>
> 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).

Not sure about this dialog happening automatically, think it would
need a "Shut TF up" option, and also be quiet at re-load.  But
certainly providing the advanced user control of the providers is
fine.

>
> 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.

Seems fine in general, the devil will be in the details :)

>
> 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.

This may require some unwinding of the spaghetti to clearly identify
the beginning of a "feature" and ensure it happens in one place.  Some
places there is stuff split between different callbacks depending on
how the feature was triggered.


 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).

It is always a requirement for plugins to not hog or block the main
thread, they can do that by other threads or separate processes, but
its their problem and not unique to FT plugins.

>
> 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.

What is missing is how the FT plugins get loaded in the first place so
they can register, if the user can control that from the PM GUI, or if
these plugins are controlled from your GUI only (my preference).  If
the FT plugins are loaded via a different path and don't appear in the
PM that may solve the order issue as well.

Cheers
Lex

>
> Thanks,
> Matthew Brush
>
> [0]: I'm still waiting for someone to propose a better name :)
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> _______________________________________________
> Devel mailing list
> Devel at lists.geany.org
> https://lists.geany.org/cgi-bin/mailman/listinfo/devel
>


More information about the Devel mailing list