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

Matthew Brush mbrush at xxxxx
Mon Aug 29 02:30:20 UTC 2016

On 2016-08-28 06:59 PM, Lex Trotman wrote:
> On 29 August 2016 at 10:47, Matthew Brush <mbrush at codebrainz.ca> wrote:
>> [...]
>> "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.

That's a thought. I think the plugin data file you refer to may only be 
for the libpeas proxy plugin which is not part of Geany (yet).

IIUC, at least when the plugin manager is opened, Geany loads all of the 
plugin DLLs anyway. Plugins could register their providers at 
`geany_load_module()`-time before they're actually initialized. Needs 
more consideration.

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

Yeah, possibly storing this info in separate ftplugin-specific keys in 
the config file.

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

That's the idea with boolean results, a plugin could actually provide 
the feature but return `FALSE` and Geany would call the next provider to 
perform the feature as well. It's kind of like a poor-man's inheritance.

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

Yeah, I thought it might be annoying too. Will need experimentation.

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

Most likely yeah. In some cases though, it might be as simple as 
sticking an "if" statement at the beginning of a single function with an 
early return.

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

I meant in Geany's code. The way I was thinking will require at least to 
perform a hash lookup, walk one or more elements of a linked list, 
perform an indirect function call, etc. I don't think there's any point 
in prematurely optimizing it, I just wanted to point out that it might 
come with some cost, especially where done frequently.

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

At least initially, I think when the plugins are activated they could 
register their providers. The user would just check the plugin in the 
plugin manager dialog as usual. In the future it could be at 
`geany_load_module()`-time, some separate GUI, or a plugin data file, 
statically as you mentioned above. It could even be done using the 
filetype.* configuration files. IMO, we should start with what's as 
simple as possible to perform the function.

Matthew Brush

More information about the Devel mailing list