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

2016-08-28 Thread Matthew Brush

On 2016-08-28 08:17 PM, Lex Trotman wrote:

On 29 August 2016 at 12:30, Matthew Brush  wrote:

[...]

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.


Actually, after more thought it doesn't make sense to me.

If a more specific provider wants to build on a more general one, it
wants the general one to run before it, so it has to be ordered after
the general provider, which has to return FALSE to allow the more
specific one to run.  But if the more specific provider isn't loaded
the general provider has to return TRUE to stop the geany built-in
functionality from running.  This means the general provider has to
know about the specific providers and if they are loaded, which is the
wrong way around.

Also a more specific provider that does it all itself and doesn't want
the general one to muck stuff up has to be ordered before the general
one to return TRUE so the general one doesn't run.  So providers have
to be able to re-order themselves or to specify an order.

I think if a provider depends on another it should be ordered first
and directly call the other, then it can return TRUE so the other
isn't called twice.



It's a good point. I think at first just using the activation and manual 
user-customized order will likely suffice. I expect the common case to 
be activating a single plugin (ex. my CDK plugin) to cover a set of 
features/filetypes and no other plugins conflicting or dependent. In the 
future it will probably be useful to make this more automatic by adding 
some kind of inter-plugin dependency manager and GUIs whatnot.


Cheers,
Matthew Brush
___
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel


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

2016-08-28 Thread Lex Trotman
On 29 August 2016 at 12:30, Matthew Brush  wrote:
> On 2016-08-28 06:59 PM, Lex Trotman wrote:
>>
>> On 29 August 2016 at 10:47, Matthew Brush  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.

Ok, as noted below, may need to be a separate mechanism anyway.

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

Actually, after more thought it doesn't make sense to me.

If a more specific provider wants to build on a more general one, it
wants the general one to run before it, so it has to be ordered after
the general provider, which has to return FALSE to allow the more
specific one to run.  But if the more specific provider isn't loaded
the general provider has to return TRUE to stop the geany built-in
functionality from running.  This means the general provider has to
know about the specific providers and if they are loaded, which is the
wrong way around.

Also a more specific provider that does it all itself and doesn't want
the general one to muck stuff up has to be ordered before the general
one to return TRUE so the general one doesn't run.  So providers have
to be able to re-order themselves or to specify an order.

I think if a provider depends on another it should be ordered first
and directly call the other, then it can return TRUE so the other
isn't called twice.

And Geany should make its fallback functionality available to call, so
a provider that wants to just make a small adjustment doesn't have to
re-implement the default (right Colomban).  Or the Geany default can
be removed and added to core plugins :)

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

Yes, thats where we want to get to, but I suspect that its not allways
the reality now.  Untangling spaghetti is a GOOD thing, its just more
work :)

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

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

2016-08-28 Thread Matthew Brush

On 2016-08-28 06:59 PM, Lex Trotman wrote:

On 29 August 2016 at 10:47, Matthew Brush  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 

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

2016-08-28 Thread Matthew Brush

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.


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

Re: [Geany-Devel] [FT-plugins] Allowing plugins to supply filetype specific functionality

2016-08-28 Thread Matthew Brush

On 2016-08-28 08:47 AM, Jiří Techet wrote:

Hi Matthew,

some random thoughts.

I'm not sure I agree with doing lots of changes on a separate branch
basically without any review. While you will be able to commit things fast
to the branch, the most probable outcome will be the branch will get never
merged because either nobody will be able to review the changes during
merge or there will be some disagreement about something that could have
been caught early. And then it's just lost effort.



A branch can be merged into master more than once (or we could use 
multiple-branches). No reason it has to happen in a single merge, or 
without any review.



The individual points here

https://github.com/geany/geany/issues/1195

look like they should be able to do one by one. The most useful seems to be
the code completion so this might be the one to start with. In parallel it


That or highlighting, not sure.


would be good to develop a plugin that uses the new API and get it to a
really usable state - you won't be able to tell what exactly you need for
the plugin unless you have some working code. In parallel you can get some
feedback from users and they will have something useful rather than lots of
half-finished prototype features that aren't really usable.



I have previously started writing the CDK plugin[0] but gave up for the 
time being since most of what I wanted to implement either a) wasn't 
possible b) wasn't possible without ugly hacks or c) wasn't possible 
without the user manually disabling stuff in the prefs dialog and 
completely replacing the feature from the ground up.


I would probably like to use this as a proof of concept, although only 
having one plugin for one family of statically typed languages using one 
support library might not give the fullest view of what's needed.



My other question is who wants to work on this? The issue mentions only
those providing patches should be involved but is there anyone except you
who will contribute patches? I confess this isn't very interesting for me -


We'll see. I know Columban has expressed interest (or at least stated 
that it's probably the best approach) in the past, not that that means 
he's interested in actively contributing to the effort. Anyone is 
welcome to contribute.



I'm not so terribly tied to Geany and if I wanted e.g. a dedicated C++
editor, I'd grab something else - you always get better language support if
the editor is made specifically for your needs. I use Geany as a general


This isn't necessarily true, there's lots of language-agnostic 
editors/IDEs that people use that allow customized language support 
(vim, eclipse, emacs, etc). The problem with Geany is it doesn't allow 
any filetype customization besides what you can set in the filetypes.* 
files, it doesn't allow extension of any of the built-in features.



purpose editor but otherwise use also Android Studio and XCode when writing


I sometimes use QtCreator when I need proper C/C++ support but it's 
annoying having to use an editor I don't like when I know that Geany can 
(and does now, just not well) do the same things with the assistance of 
language-specific support libraries.



for Android or iOS. So no patches from me I'm afraid :-(. Apart from that
this is a huge amount of work and I'm just lazy, sorry ;-)



That's fine. I don't expect it to be a _huge_ amount of work, but 
probably not a simple one-off PR. I expect it to be similar in scope and 
size to the proxy plugin improvements, most likely.


Cheers,
Matthew Brush

[0] https://github.com/codebrainz/cdk-plugin
___
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel


Re: [Geany-Devel] [FT-plugins] Allowing plugins to supply filetype specific functionality

2016-08-28 Thread Jiří Techet
Hi Matthew,

some random thoughts.

I'm not sure I agree with doing lots of changes on a separate branch
basically without any review. While you will be able to commit things fast
to the branch, the most probable outcome will be the branch will get never
merged because either nobody will be able to review the changes during
merge or there will be some disagreement about something that could have
been caught early. And then it's just lost effort.

The individual points here

https://github.com/geany/geany/issues/1195

look like they should be able to do one by one. The most useful seems to be
the code completion so this might be the one to start with. In parallel it
would be good to develop a plugin that uses the new API and get it to a
really usable state - you won't be able to tell what exactly you need for
the plugin unless you have some working code. In parallel you can get some
feedback from users and they will have something useful rather than lots of
half-finished prototype features that aren't really usable.

My other question is who wants to work on this? The issue mentions only
those providing patches should be involved but is there anyone except you
who will contribute patches? I confess this isn't very interesting for me -
I'm not so terribly tied to Geany and if I wanted e.g. a dedicated C++
editor, I'd grab something else - you always get better language support if
the editor is made specifically for your needs. I use Geany as a general
purpose editor but otherwise use also Android Studio and XCode when writing
for Android or iOS. So no patches from me I'm afraid :-(. Apart from that
this is a huge amount of work and I'm just lazy, sorry ;-)

Cheers,

Jiri
___
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel


Re: [Geany-Devel] [FT-plugins] Vala for prototyping

2016-08-28 Thread Matthew Brush

On 2016-08-27 04:09 PM, Matthew Brush wrote:

Hi All,

With respect to the efforts described in PR #1195[0] is anyone opposed
to using Vala as a GObject code generator?

I propose we use Vala as a way to generate GObject boilerplate while we
hammer out the design of FT-plugins, and later once the design is more
concrete, that we port the GObjects generated by valac to their
hand-written C equivalents (after they won't be changed as much).

It amounts to a few lines of code in `configure.ac` and `src/Makefile.am`.

Is OK?

P.S. This is only for the proposed 'ft-plugins' branch, not in
master/release code.



Nevermind, I can just use it locally for prototyping. Don't want to get 
too sidetracked on something that's not strictly required and/or turn 
off anyone who doesn't want to use Vala.


Sorry for the noise.

Cheers,
Matthew Brush

___
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel


Re: [Geany-Devel] [FT-plugins] Vala for prototyping

2016-08-28 Thread Matthew Brush

On 2016-08-28 01:51 AM, Thomas Martitz wrote:

Am 28. August 2016 01:09:36 MESZ, schrieb Matthew Brush :

Hi All,

With respect to the efforts described in PR #1195[0] is anyone opposed
to using Vala as a GObject code generator?

I propose we use Vala as a way to generate GObject boilerplate while we

hammer out the design of FT-plugins, and later once the design is more
concrete, that we port the GObjects generated by valac to their
hand-written C equivalents (after they won't be changed as much).


Do you suggest to use it only initially, and then continue working on the C 
code? In that case the vala code doesn't need to be checked in does it?



I suggest to use Vala to write any GObject stuff for prototyping 
purposes in order to avoid writing and re-writing gobs of boilerplate. 
The Vala code would have to be checked-in in order to modify it until a 
design is hammered out then the code could be converted to plain C 
boilerplate once it's not changing often (before merging back to master 
branch).



The classbuilder plugin (shipped with geany) can also generate the boilerplate, 
bit much prettier with less noise.



The classbuilder plugin only generates basic GObject boilerplate, it has 
no concept of interfaces, abstract base classes, properties, signals, etc.



If you suggest to continue working on the vala code that's ok with me but not 
everyone is fluent with vala.



It would be OK with me too, but I suspect not everyone.

Cheers,
Matthew Brush
___
Devel mailing list
Devel@lists.geany.org
https://lists.geany.org/cgi-bin/mailman/listinfo/devel