Fix handling of scopes starting with a non-ASCII character.
Actually, just drop the check on the first byte of the scope, as it
doesn't seem to serve any purpose as it only checks the first byte (so
isn't any kind of real validation; and as it predates Geany it's
impossible to know the real reason behind this check), and breaks
support for non-ASCII scopes.
In the future we might want to enable calling it again to set new supported
plugin types/extensions. This is not implemented yet, but in order to
allow this in the future we have to prevent it now, otherwise we'd
need to break the API.
g_ptr_array_insert() is too recent (2.40), but prepending is required. GQueue
is a fine replacement with better old-glib support, at the expense of working
with a doubly-linked list instead of plain array.
Geany now remembers how many plugins depend on a pluxy. It uses this
information to disable the "Active" checkbox in the PM dialog.
Additionally, the PM dialog displays plugins in a hierarchical manner, so that
sub-plugins are shown next to pluxy. This is espcially handy since it makes
the sub-plugin <-> pluxy relationship really obvious, and it's easier to spot
which plugins need to be disabled before the pluxy can be disabled. This allows
to remove code to re-select the plugin because the row (respective to the
hierarchy level) does not change anymore.
This demo proxy does not actually do anything useful. It simply loads
pseudo-plugins from an ini-style file. The point is that there will be a plugin
in the PM dialog for each ini. Each ini-plugin also causes a menu item to be
generated.
When enabling/disabling pluxys in the PM dialog the list of available
plugins might change. If plugins before the pluxy go/come then the wrong
plugin becomes selected (the selected row number stays the same). Re-apply
the selection to the current one in the toggle callback to overcome this issue.
This function finally allows plugins to register themselves as a proxy
for one or more file extensions.
Lots of documentation is added to doc/plugins.dox, please refer to that for more
details.
When a file extension alone is ambigious as to whether a potential plugin is
really handled then the proxy should use the probe hook to find out. This can
be especially helpful when two pluxies work on the same file extension.
The proxy's probe() should return PROXY_IGNORED or PROXY_MATCHED accordingly.
A special flag value, PROXY_NOLOAD, can be or'ed into PROXY_MATCHED to say
that the file belongs to the proxy, but isn't directly loaded and should not
be handled by any other proxy or geany itself.
Example for PROXY_IGNORED:
geanypy only supports python2 at the moment. So, scripts written
for python3 aren't handled by it and should be skipped for the PM dialog.
Or perhaps they are handled by another proxy that supports python3.
Example for PROXY_NOLOAD:
A pluxy registers for the metadata file extension (.plugin) where author etc
is in. The actual implmentation is in a python script (.py). The .py file
is tied to the .plugin and should not be processed by other pluxies. Thus,
the pluxy also registers for the .py extension but returns
PROXY_MATCHED|PROXY_NOLOAD for it (if it would return only PROXY_MATCHED
the sub-plugin would show up twice in the PM dialog).
During the loading of the active plugins they are also initialized (done at
startup). As a result, these plugins could be pluxys and make more plugins
available, some of which may be active as well.
Because of this the loop has to be restarted if pluxies become
available to also load active plugins that depend on the pluxy.
The loop is only restarted at the end so only nested pluxys could possibly
cause the loop to be run more than twice.
Being a GModule is actually a detail of standard plugins. Future proxy plugins
might need different handles. Therefore replace the module field with a more
generic pointer and encapsulate the GModule detail further.
This pointer shall be returned from GeanyProxyFuncs::load and is passed back
to GeanyProxyFuncs::unload, and isn't interpreted by Geany.
Currently they encapsulate loading and unloading of standard plugins. In
the future plugins can provide such functions to load their types of plugins.
Such a dummy proxy plugin is implemented now to load standard plugins so
that these aren't going to be specially handled.
GVFS uses different backends for "native" GIO operations and POSIX
operations which use the FUSE backend. If the two kinds of operations are
mixed, we may get races.
The patch checks the value of file_prefs.use_gio_unsafe_file_saving and
based on it either uses GIO operations or POSIX operations for file loading,
saving and checking modification time.
This also includes obvious changes to msgstr of some languages.
Languages that didn't explicitly use 'l' as previous shortcut or
didn't have 'g' on their translation were left untouched.
The current shorcut key for "Use multi-line matching" conflicts with
"In Selection" when "Use regular expressions" is enabled. It should be
convenient if we change it.
We choose 'g' since other letters are already in use:
u: "Use regular expressions"
s: "Search for"
e: "Use escape sequences"
m: "Mark"
l: "In Selection"
t: "Match from start of word"
i: "In Document"
n: "Replace & Find"
a: "Case sensitive"
c: "Close"
h: "Replace with"
When creating a new document for a non-existing file from the command
line, check if we don't already have opened it and simply show the
existing one if we do. This avoids creating new documents that will be
saved to the same location again and again.
Closes https://bugs.launchpad.net/linuxmint/+bug/1482558
The destroy_notify can be used to make Geany automatically free the
per-KeyGroup or per-KeyBinding user_data. This is particularly useful for
vala-based plugins or other (future) language bindings.
The destroy functions can be conviniently hooked into the destroy_notify of
the underlying GPtrArrays, therefore this commit also implements such notifies
internally.
These are new keybinding callback functions that take a few more parameters.
Most importantly they have pdata pointer which allows plugins
to store context information. This is especially useful for future plugins
in OOP languages to store an instance pointer there, or interpreted ones to
store interpreter context.
Since geany_load_module() is called for non-enabled plugins you may not
use the plugin API here yet. The only exceptions to this rule are API functions
required for plugin registration.
This rule is hard to enforce (would need to g_return_if_val(PLUGIN_LOADED_OK(p))
for all API functions (well, those taking a plugin pointer anyway), so this
rule is only documented for now.
It was found that because geany_plugin_set_data() could be used by both
plugin's init() and geany_load_module(), that it introduced some uncertainty
as to when to call the free_func. init() callers might expect the call
around the same time as cleanup() is called, while geany_load_module()
callers expected the call at module unload time.
It was indeed called at module unload time. But that means that init() callers
cannot call it again reliably after in a init()->cleanup()->init() flow (when
toggling the plugin) without fully unloading the plugin (which is what we do
currently but that's we would want to change).
With the separation we can actually destroy the data depending on where
it was set and do everything unambigiously.
The documentation provides a quite detailed description of the new loader
In addition it adds a "how to transition" that briefly describes the old
loader (for curious newcomers) and lots of hints for porting legacy
plugins to the new loader.
If the plugin did not set its own user_data we set it to whatever it set
with geany_plugin_register_full() or geany_plugin_set_data().
This is particularly convinient because PluginCallback is usually statically
allocated, at which point dynamically allocated plugin data doesn't exists yet.
- The return value from geany_load_module is removed (void). It was ignored
anyway and we have to check separately whether the plugin loaded OK or not
anyway. If the plugin specific code fails it should simply not call
geany_plugin_register() (which it should only call iff all other conditions
are good).
- GeanyPluginFuncs::init() now returns a bool to allow failing initialization.
Some plugins might want to defer work to their init() (i.e. only do
it when the plugin was activated by the user), and some of that work can
possibly fail (e.g. GtkBuilder fails to load .xml).
Note that the GUI integration of the latter is less than ideal but this kind
of GUI/policy work is out of scope for this patch set. Therefore a plugin
failing to init is simply removed from the PM dialog as if it became
incompatible. However, as the code that generates the list does not call init
they will show up again if the PM dialog is re-opened.
With geany_plugin_set_data() the legacy plugin support can be made
more transparent by using wrapper functions that call the actual plugin_*
functions. This allows to remove the differentiation in code that's not
directly concerned with actually loading plugins.
This commit doesn't change anything except for one thing: legacy plugins now
cannot call geany_plugin_set_data(). But it is meant for new-style plugins
anyway.
The API function adds a free_func parameter, and can also be called
after geany_plugin_register(), i.e. in the plugin's init() callback. This
fixes a by-design memory leak and gives greater flexibility.