Hi All,
Related to my previous mail, and assuming it is somewhat reasonable, I
would like to propose a list of initial features that will be useful to
allow plugins to provide, in no particular order:
----
Syntax Highlighting
-------------------
Most likely using an API based on/similar to Scintilla's "container lexers".
At the minimum, it could have a callback something like:
gboolean (*highlight)(GeanyPlugin*, GeanyDocument*,
guint start_pos, guint end_pos, gpointer user_data);
As with Scintilla's "container lexer", it would just tell the provider
what and where to highlight. It might be pointless providing `end_pos`
it could probably just highlight a whole line at time (maybe like
Scintilla's 'style-needed' notification).
If the providers are to setup their own colour schemes and such, then it
may be required to add a callback such as:
gboolean (*init_styles)(GeanyPlugin*, GeanyDocument*,
gpointer user_data);
for the plugin to configure all the Scintilla styles as it wishes. This
will probably require some kind of conflict avoidance scheme if it is to
support multiple providers providing the same feature. Perhaps it could
also pass the start style ID the provider can use, and it could tell
Geany the maximum style that it ended up using.
Sidebar Symbol Tree
-------------------
Could provide some API functions to populate the tree by plugins
providing the needed information. The nesting could be handled by
passing a scope path similar to GtkTreePath or TagManager's `::`
delimited scope string, which would be parsed/expanded to apply to the
right tree node.
The callback function for the provider might be like:
gboolean (*populate_symbols_tree)(GeanyPlugin*, GeanyDocument*,
guint cursor_pos, gchar **current_node_path /* out */,
gpointer user_data);
When the providers are called in to, they could use a function something
like this:
void tagbar_add_node(const gchar *name, guint line,
const gchar *signature, const gchar *scope_path,
GeanySidebarIcon icon);
I haven't looked closely at the existing sidebar/symbols code yet, maybe
it already provides such a function that could be used. It has also been
mentioned that this could be done using the TagManager API. Plugins
would walk their own internal ASTs or tag lists and build up the TM tag
array, and Geany would use it for updating the symbols tree as it
currently does (IIUC). I don't know much about TM so I can't really give
an example callback for such an API.
Auto-Completion/Intellisense
----------------------------
This could be triggered at the exact same time in the same way it is now
(and re-using the same preferences). It could call a callback function
in the ft-plugins like:
gboolean (*complete_at)(GeanyPlugin *, GeanyDocument *,
guint position, const gchar *partial_word,
GPtrArray completion_list /* out */, gpointer user_data);
The `completion_list` would be filled in with whatever the provider
thinks could be completed at `position`. It could be made more advanced
in the future like allowing plugins to give icons, argument lists,
documentation comment text, etc. For now it could just give strings to
directly populate Scintilla's auto-complete listbox.
Calltips
--------
To provide calltips, a provider could be called into like:
gboolean (*provide_calltips)(GeanyPlugin*, GeanyDocument*,
guint position, const gchar *symbol,
GPtrArray *overloads /* out */, gpointer user_data);
The `overloads` array would populated by the provider with the various
overloads for the given `symbol` (function). As with auto-completion, at
first this could just be a list of overloads represented as strings
which directly populate Scintilla's calltip infos. This could be
enhanced in the future to provide documentation comment text and
placeholder insertion points into the editor in the future, but for now
should be kept simple (see GtkSourceView, XCode, etc).
Go To Declaration/Definition
----------------------------
This could be either single callback passing a parameter to tell whether
declaration or definition, or two separate callbacks. An example of the
callbacks could be:
struct SourceLocation { gchar *filename; guint position; };
gboolean (*get_declaration_location)(GeanyPlugin*, GeanyDocument*,
guint position, const gchar *symbol,
GPtrArray *results, gpointer user_data);
and likewise for `get_definition_location`. The `results` array could be
populated with `SourceLocation`s for each possible
definition/declaration. For example there might be multiple declarations
in different `#if` blocks you could jump to, for C-like languages. Geany
already provides a UI popup list to pick where to jump, this should be
re-used.
Build/Run Support
-----------------
I haven't thought much on this yet, but in general there should be a way
for ft-plugins to get called into when a the build/run features are
activated.
Diagnostics
-----------
I also haven't thought much on this yet. It needs to be possible for
ft-plugins, after getting notified of build/run events, to be able to
update diagnostics information.
Some of the diagnostics display might include:
- Scintilla marker margin icons, indicating the type of diagnostic info
present for each line (could be more than one per line).
- Scintilla indicators (little coloured squigglies) showing the specific
range(s) of code where the diagnostics apply.
- Scintilla annotations giving further details on request.
- Tooltip messages when hovering over the marker margins or squigglied
text giving further details.
- Putting lines of diagnostics info in the msgwin compiler tab (already
supported to some extent IIUC).
Refactoring
-----------
This is just an idea that is probably long in the future, but ft-plugins
could provide some common re-factorings (ex. rename, generate definition
code, etc). I haven't thought on this much at all yet.
----
Almost surely I have left some out. What do you think?
Cheers,
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. If there's any questions or
suggestions, please let me know.
Thanks,
Matthew Brush
[0]: I'm still waiting for someone to propose a better name :)
Not sure I agree that Github is bad for *development* discussions, for
users, sure, the ML is likely to find the audience better, but most
developers will also be githubians. Also github supports markup that
mail doesn't. But anyway lets try mailing it in for this issue, and
see how it goes.
But everybody, please DO NOT EDIT THE SUBJECT LINE IF ON THREAD some
mail agents thread by subject, and DO NOT REPLY IF YOU WANT ANOTHER
THREAD some mail agents thread by previous ID. We should not dictate
what sort of mail agent people must use to contribute, please respect
individual or enforced choices and follow this procedure (codebrainz
this should go on the issue guidelines).
I agree with the approach in general, but for some major items (about
the process):
> rather than endless discussions we let the code do a lot of the talking
No, not yet, we need to agree what we are going to code. This is a
major change to Geany's design, and it should be designed, not just
jump into coding it. Geany suffers from too much "heres some code I
made earlier".
codebrainz, you clearly have some design in mind, please *describe*
(not code) it to get the ball rolling.
> Code reviews are always welcome but should be accompanied by the appropriate patches/PRs/commits
Too draconian. Just because someone has
questions/doubts/misunderstandings about some proposed code or design
doesn't mean they have the knowledge or time to immediately propose an
alternative. If comments that don't have corrections/alternatives
proposed are ignored, nobody will review.
Using a branch is good, but, as PRs cannot be layered on PRs, what
process do you suggest for corrections to be proposed? And how will
alternatives be compared? More than one PR cannot be committed at the
same time, and "first PR gets committed" is a bad recipe for new
designs, the first is often the worst. Having later PRs have to
revert previous PRs just makes them more complex and harder to review
so better proposals tend to be rejected.
On the requirements, not much to say, agree in principle. Minor
comments/suggestions:
> Allow plugins to provide syntax highlight.
Probably sufficient for Geany to support "container lexers" and
flick-pass it to plugins. But then the plugins probably have to have
a way to define styles similar to how `highlightmappings.h` is used
for included lexers.
> Allow plugins to provide the symbols for the tagbar tree...
Do you mean the symbols pane? Or do you mean to inject symbols into
tagmanager so all existing functionality also sees them?
> provide the auto-complete list, given the current location in the document and the part of the word already typed.
Location in document is probably enough, the plugin probably has to
check for preceeding context `aaa.bbb.ccc` anyway, so the partially
typed name is no issue, and it can then be language specific, like
lisp can include *s and -s and other things that C doesn't allow in
names.
> plugins to hook into the build system runner
Plugins can now get and set any build command, not sure what else is
needed, except maybe a way of telling Geany to not save the plugin set
values, since the plugin is handling them.
> plugins to provide diagnostics when build commands are run.
Allowing the plugin to parse the command response *before* it goes in
the message window would be good.
General:
I used to have a prototype of a change to load filetype specific
plugins specified in the filetype file. I can't find it now (backups,
whats that?) but it actually was so simple that it doesn't matter.
Finally despite some disagreements on detail, the general idea and
process is good (IMNSHO), thanks to codebrainz for starting the
process.
Cheers
Lex
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.
Cheers,
Matthew Brush
[0]: https://github.com/geany/geany/issues/1195
Am 28. August 2016 01:09:36 MESZ, schrieb Matthew Brush <mbrush(a)codebrainz.ca>:
>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?
The classbuilder plugin (shipped with geany) can also generate the boilerplate, bit much prettier with less noise.
If you suggest to continue working on the vala code that's ok with me but not everyone is fluent with vala.
Best regards
Hello,
more than two years after my initial message "RFC: Proxy plugins" I've
finally
reached the point that I envisioned back then. As a result, I can now
release
Peasy, which is my first personal proxy plugin, which I'm taking seriously.
Please give me feedback or even contribute to this project.
Peasy[1] is a proxy plugin which uses libpeas[2] to enable running
plugins in
other languages, most notably python [4]. Peasy also makes heavy use of
gobject-introspection to automatically create bindings to Geany's (and
Peasy's
own) APIs.
Short recap, what are proxy plugins: proxy plugins are ones which act as a
proxy to "second tier" plugins. The proxy use a specific Geany API to
register
themselves as a proxy and they provide methods to bridge Geany's core
and the
other plugins. The other plugins then become first class plugins.
Of course the point is, that those other plugins are not written in
C/C++ but
some other language. And the proxy plugin contains an interpreter or
some other
runtime to execute those foreign language plugins.
Back to Peasy, it provides methods to run Python plugins within Geany.
It also
ships a VAPI files for writing plugins in Vala.
I release version 0.2. I'm sure there hide plenty of bugs but it seems
relatively stable to me. The build process has some rough edge, though.
I support Peasy on my github, feel free to file bugs or send patches/PRs.
Q: What's the difference to GeanyPy
A: Peasy and GeanyPy have a lot in common, most prominently that they enable
Python plugins. But key differences are:
1) Peasy supports python3 only, GeanyPy only python2.
3) Peasy works gtk and gtk3, GeanyPy only gtk2.
3) Peasy automatically generates bindings for Python using
object-introspection
whereas GeanyPy contains hard-coded
4) Peasy reads plugin metadata from a different file no code runs
before the
plugin is truly activated.
5) Peasy isn't part for geany-plugins yet.
Peasy ships some plugins, some of which are not just for testing/playground:
- modeline-py: Parses vim modeline and applies them to Geany on a
per-file basis.
- console-python.py: This plugins opens a console window in which you can
explore the Geany APIs and run arbitrary python code. Heavily based on
console.py for GeanyPy.
- quickswitch.py: Adds a dialog that allows to quckly switch tabs. Also
supports
going to tags / symbols directly.
[1] https://github.com/kugel-/peasy
[2] https://wiki.gnome.org/Projects/Libpeas
[3] lua functionality is completely untested so not really supported at
this point
Best reards.
Hi!
I'd like to use ESLint <http://eslint.org> inside Geany. I've seen many
integrations with differents editors in their website. Are you aware of any
current implementation for this lint or any similar? Do you think that it
would be possible to integrate it with Geany (as a plugin of course)? How
much effort would it need? And, the final question, which languages did
Geany support to develop plugins again?
Greetings,
* Abel.*