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.
This is easier to handle if we decide to add callbacks. Since we can
zero-initialize callbacks before passing it to the plugin we can be certain as
to which callbacks the plugin knew about when it was compiled. This is exactly
the same method used for GeanyPlugin::info already and easier than inspecting
the API version.
The old plugin loader has a number of deficiencies:
- plugins need to export a couple of callback functions into the global namespace
- plugins need to export data pointers, that are written by Geany
- the exported functions have no user_data param, so there is no way to
pass context/state back to the plugin (it needs global storage for that)
- plugin registration is implicit, plugins have no way to not register themselves
(it may want that due to missing runtime dependencies)
- plugins perform the ABI/API verification, and even though we provide a
convinience wrapper, it may get that wrong
As a result, I designed a new loader with the following design principles
- semantics of callbacks should not change, but they they shouldn't be mess
with the global namespace
- each callback receives a self-identifying param (the GeanyPlugin instance) and
a plugin-defined data pointer for their own use
- explicit registration through a new API function
- in-core API/ABI checks
The following principles shall be left unchanged:
- The scan is done on startup and when the PM dialog is opened
- Geany allocates GeanyPluginPrivate for each plugin, and GeanyPlugin is
a member of it
- Geany initially probes for the validity of the plugin, including file type
and API/ABI check, thus Geany has the last word in determining what a
plugin is
- the PM dialog is updated with the proper, translated plugin information
- the PM dialog GUI and user interaction in general is unchanged
With the redesign, plugins export a single function: geany_load_module().
This is called when the GModule is loaded. The main purpose of this function
is to call geany_plugin_register() (new API function) to register the plugin.
This is the only function that is learned about through g_module_symbol().
Within this call the plugin should
a) set the localized info fields of GeanyPlugin::info
b) pass compiled-against and minimum API version as well as compiled-against
ABI version, to allow Geany to verify compatibility
c) pass a pointer to an instance of GeanyPluginFuncs
which holds pointers to enhanced versions of the known callbacks (except
configure_single which is dropped).
d) optionally pass a plugin-private data pointer for later callbacks
Enhanced means that all callbacks receive the GeanyPlugin pointer as the first
and a pdata pointer as the last. pdata is private to the plugin and is set
by geany_plugin_register().
The callbacks need (should) not be globally defined anymore, and the global
GeanyData, GeanyPlugin and GeanyFunctions pointers are ignored and not set
anymore. GeanyData is available through GeanyPlugin::geany_data.
As the edited file can be a remote file on a server with a different time
zone, the mtime can actually be in the future. In this case the check not
only shows the misleading warning but more importantly the
doc->priv->mtime < st.st_mtime
check never happens and the user doesn't get the modified file prompt.
Setting
doc->priv->mtime = time(NULL);
to the current time on file creation isn't harmful in any way because the
saved file's mtime is taken but it's a bit misleading so better to set it
to 0.
This commit adds the following new keywords for perl:
- say
- state
- given, when, default
- __SUB__
While __SUB__ was introduced in perl 5.16, the others date back
to v5.10 released in 2007!
Since both gcc and llvm use ^ to mark the position of the error now,
monospace font seems to be a better default font for the message window
to avoid the ^ character misalignment.
Fixes#435.
This function won't work correctly on unsorted array because the second
part of the function (after the tags search) expects the array is sorted
by name. The only user of this is tm_source_file_set_tag_arglist() in which
we can go through the tags manually by ourselves (it needs only a single
value so the original behavior of tm_tags_find() wasn't a problem).
Eliminate the tags_search() function as it isn't needed any more.
Just cleanup, not functional change.
Do the same with struct/class/union... member tags as we do with
typenames - extract them from the edited file and merge them with
the array containing all of them so while editing, there should
be no slowdowns because one file usually doesn't contain so many
tags. This eliminates about 2s freeze when typing "." on a linux
kernel project with 2300000 tags.
Extract typename and member tags also for global tags in case someone
creates a giant tags file - this needs to be done just once when
loading the tag files.
All the remaining tm_tags_extract() in Geany are called on
file tag array only so there shouldn't be any performance problems.
This patch contains a bit too many things which are however related.
It started by the part in editor.c (where we previously used only the
first type we found to perform scoped search) by going through all the
possible variable types until the scoped search returns some result
(this is useful if variable foo is used once as int and once as struct
and if the int is the first type found, we won't get the struct's members).
This didn't work. After an hour of debugging, it turned out that
because tm_workspace_find_scope_members() calls internally
tm_workspace_find() and this function returns static array, this
invalidates the array returned by the tm_workspace_find() used
previously to get all the possible variable types.
Since this is really dangerous and hard to notice, I tried to eliminate
the static returns from both tm_workspace_find() and
tm_workspace_find_scoped_members().
The tm_workspace_find_scoped_members() function is where I got
stuck because as I started to understand what it's doing, I found
many problems there. This patch does the following in this function:
1. Eliminates search_global and no_definitions parameters because
we always search the whole workspace and this simplifies the slightly
strange logic at the end of the function.
2. Returns members from global tags even when something found in
workspace tags - previously global tags were skipped when something
was found from workspace tags but I don't see a reason why.
3. Adds the lang parameter to restrict tags by language (we do this
with normal search and the same should be done here).
4. Previously when searching for types with members the function
returned NULL when more than one such type was found (there should
have been >=1 instead of ==1 at line 906). This patch improves the
logic a bit and if multiple types are found, it tries to use the one
which is other than typedef because it probably has some members (the
typedef can resolve to e.g. int).
5. Previously the function prevented only direct typedef loops like
typedef A B;
typedef B A;
but a loop like A->B->C->A would lead to an infinite cycle. This patch
restricts the number how many times the typedef can be resolved by
using for loop with limited number of repetitions and giving up when
nothing useful is resolved.
6. Finally the patch tries to simplify the function a bit, make it
easier to read and adds some comments to make it clearer what the
function does.
They are basically identical except:
1. _scoped() compares scope in addition
2. _scoped() is missing the C/CPP tag compatibility part
3. _scoped() allows returning just single result (unused)
4. _scoped() allows not searching in global tags (unused)
Since we now always put lang also under tag->lang, the match_langs()
function is not necessary.
Extend the add_filtered_tags() (and rename it to fill_find_tags_array()) to
perform the tm_tags_find(), compare the scope and add scope
as parameter of tm_workspace_find() and eliminate tm_workspace_find_scoped()
completely.
1. Factor-out the part common to tags_array and global_tags
2. Get both C/CPP tags when either of the languages is specified (both
for global_tags and tags_array)
3. Remove unnecessary strcmp()s (tm_tags_find() should return only tags
with the specified name)
4. Various minor cleanups