As a diff is sometimes clearer than words, here's an additional one addressing some discussions above (it's on top of my previous patch, but I don't mean to suggest they should be applied as-is). It includes _provided()
that can tell the caller whether it was the winner, user_data
for the vfuncs, and a fairly thorough multi-extension support.
diff --git a/src/document.c b/src/document.c
index adf5b8cc6..9bcbc7996 100644
--- a/src/document.c
+++ b/src/document.c
@@ -2720,7 +2720,7 @@ void document_highlight_tags(GeanyDocument *doc)
GString *keywords_str;
gint keyword_idx;
- if (! plugin_extension_active(plugin_extension_geany))
+ if (! plugin_extension_symbol_highlight_provided(doc, plugin_extension_geany))
return;
/* some filetypes support type keywords (such as struct names), but not
diff --git a/src/editor.c b/src/editor.c
index 7a1d2fdc1..0d0d5ff23 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -838,11 +838,8 @@ static void on_char_added(GeanyEditor *editor, SCNotification *nt)
}
}
- if (plugin_extension_calltips_provided(editor->document))
- plugin_extension_calltips_show(editor->document, FALSE);
-
- if (plugin_extension_autocomplete_provided(editor->document))
- plugin_extension_autocomplete_perform(editor->document, FALSE);
+ plugin_extension_calltips_show(editor->document, FALSE);
+ plugin_extension_autocomplete_perform(editor->document, FALSE);
check_line_breaking(editor, pos);
}
@@ -1137,7 +1134,7 @@ static gboolean on_editor_notify(G_GNUC_UNUSED GObject *object, GeanyEditor *edi
/* now that autocomplete is finishing or was cancelled, reshow calltips
* if they were showing */
autocomplete_scope_shown = FALSE;
- if (plugin_extension_active(plugin_extension_geany))
+ if (plugin_extension_calltips_provided(doc, plugin_extension_geany))
request_reshowing_calltip(nt);
break;
case SCN_NEEDSHOWN:
@@ -1152,7 +1149,7 @@ static gboolean on_editor_notify(G_GNUC_UNUSED GObject *object, GeanyEditor *edi
break;
case SCN_CALLTIPCLICK:
- if (plugin_extension_active(plugin_extension_geany) && nt->position > 0)
+ if (plugin_extension_calltips_provided(doc, plugin_extension_geany) && nt->position > 0)
{
switch (nt->position)
{
@@ -5295,7 +5292,7 @@ void editor_indent(GeanyEditor *editor, gboolean increase)
}
-void editor_extension_autocomplete_perform(GeanyDocument *doc, gboolean force)
+void editor_extension_autocomplete_perform(GeanyDocument *doc, gboolean force, gpointer data G_GNUC_UNUSED)
{
gint pos = sci_get_current_position(doc->editor->sci);
@@ -5335,7 +5332,7 @@ void editor_extension_autocomplete_perform(GeanyDocument *doc, gboolean force)
}
-void editor_extension_calltips_show(GeanyDocument *doc, gboolean force)
+void editor_extension_calltips_show(GeanyDocument *doc, gboolean force, gpointer data G_GNUC_UNUSED)
{
gint pos = sci_get_current_position(doc->editor->sci);
diff --git a/src/editor.h b/src/editor.h
index 95c36a3e3..cee71df5e 100644
--- a/src/editor.h
+++ b/src/editor.h
@@ -279,8 +279,8 @@ void editor_snippets_free(void);
const GeanyEditorPrefs *editor_get_prefs(GeanyEditor *editor);
-void editor_extension_autocomplete_perform(struct GeanyDocument *doc, gboolean force);
-void editor_extension_calltips_show(struct GeanyDocument *doc, gboolean force);
+void editor_extension_autocomplete_perform(struct GeanyDocument *doc, gboolean force, gpointer data);
+void editor_extension_calltips_show(struct GeanyDocument *doc, gboolean force, gpointer data);
/* General editing functions */
diff --git a/src/keybindings.c b/src/keybindings.c
index 9eba0ef30..b5e08172f 100644
--- a/src/keybindings.c
+++ b/src/keybindings.c
@@ -2152,12 +2152,10 @@ static gboolean cb_func_editor_action(guint key_id)
sci_send_command(doc->editor->sci, SCI_LINETRANSPOSE);
break;
case GEANY_KEYS_EDITOR_AUTOCOMPLETE:
- if (plugin_extension_autocomplete_provided(doc))
- plugin_extension_autocomplete_perform(doc, TRUE);
+ plugin_extension_autocomplete_perform(doc, TRUE);
break;
case GEANY_KEYS_EDITOR_CALLTIP:
- if (plugin_extension_calltips_provided(doc))
- plugin_extension_calltips_show(doc, TRUE);
+ plugin_extension_calltips_show(doc, TRUE);
break;
case GEANY_KEYS_EDITOR_CONTEXTACTION:
if (check_current_word(doc, FALSE))
diff --git a/src/libmain.c b/src/libmain.c
index d849bfa45..a54831d5a 100644
--- a/src/libmain.c
+++ b/src/libmain.c
@@ -46,6 +46,7 @@
#include "navqueue.h"
#include "notebook.h"
#include "plugins.h"
+#include "pluginextension.h"
#include "projectprivate.h"
#include "prefs.h"
#include "printing.h"
@@ -1033,6 +1034,8 @@ void main_init_headless(void)
memset(&template_prefs, 0, sizeof(GeanyTemplatePrefs));
memset(&ui_prefs, 0, sizeof(UIPrefs));
memset(&ui_widgets, 0, sizeof(UIWidgets));
+
+ plugin_extension_register(plugin_extension_geany, 0, NULL);
}
diff --git a/src/pluginextension.c b/src/pluginextension.c
index 0460a7c5a..5d0c8d546 100644
--- a/src/pluginextension.c
+++ b/src/pluginextension.c
@@ -24,12 +24,12 @@
#include "symbols.h"
-static gboolean func_return_true(GeanyDocument *doc)
+static gboolean func_return_true(GeanyDocument *doc, gpointer data)
{
return TRUE;
}
-static GPtrArray *func_return_ptrarr(GeanyDocument *doc)
+static GPtrArray *func_return_ptrarr(GeanyDocument *doc, gpointer data)
{
return NULL;
}
@@ -50,86 +50,161 @@ static PluginExtension plugin_extension_geany_intenral = {
.symbol_highlight_provided = func_return_true
};
-static PluginExtension *current_extension = &plugin_extension_geany_intenral;
+typedef struct
+{
+ PluginExtension *extension;
+ gpointer data;
+ gint priority;
+} PluginExtensionEntry;
+
+static GList *all_extensions = NULL;
+
PluginExtension *plugin_extension_geany = &plugin_extension_geany_intenral;
-GEANY_API_SYMBOL
-void plugin_extension_register(PluginExtension *extension)
+/* sort higher priorities first */
+static gint sort_extension_entries(gconstpointer a, gconstpointer b)
{
- /* possibly, in the future if there's a need for multiple extensions,
- * have a list of extensions and add/remove to/from the list */
- current_extension = extension;
+ const PluginExtensionEntry *entry_a = a;
+ const PluginExtensionEntry *entry_b = b;
+
+ return entry_b->priority - entry_a->priority;
}
GEANY_API_SYMBOL
-void plugin_extension_unregister(PluginExtension *extension)
+void plugin_extension_register(PluginExtension *extension, gint priority, gpointer data)
{
- current_extension = &plugin_extension_geany_intenral;
+ PluginExtensionEntry *entry = g_malloc(sizeof *entry);
+
+ entry->extension = extension;
+ entry->data = data;
+ entry->priority = priority;
+
+ all_extensions = g_list_insert_sorted(all_extensions, entry, sort_extension_entries);
}
GEANY_API_SYMBOL
-gboolean plugin_extension_active(PluginExtension *extension)
+void plugin_extension_unregister(PluginExtension *extension)
{
- return current_extension == extension;
+ for (GList *node = all_extensions; node; node = node->next)
+ {
+ PluginExtensionEntry *entry = node->data;
+
+ if (entry->extension == extension)
+ {
+ g_free(entry);
+ all_extensions = g_list_delete_link(all_extensions, node);
+ break;
+ }
+ }
}
-/* allow plugins not to implement all the functions and fall back to the dummy
- * implementation */
-#define CALL_IF_EXISTS(f) (current_extension->f ? current_extension->f : plugin_extension_geany_intenral.f)
+/*
+ * @brief Checks whether a feature is provided
+ * @param f The virtual function name
+ * @param doc The document to check the feature on
+ * @param ext A @c PluginExtension, or @c NULL
+ * @returns @c TRUE if the feature is provided, @c FALSE otherwise. If @p ext
+ * is @c NULL, it check whether any extension provides the feature;
+ * if it is an extension, it check whether it's this extension that
+ * provides the feature (taking into account possible overrides).
+ */
+#define CALL_PROVIDED(f, doc, ext) \
+ G_STMT_START { \
+ for (GList *node = all_extensions; node; node = node->next) \
+ { \
+ PluginExtensionEntry *entry = node->data; \
+ \
+ if (entry->extension->f && entry->extension->f(doc, entry->data)) \
+ return (ext) ? entry->extension == (ext) : TRUE; \
+ } \
+ return FALSE; \
+ } G_STMT_END
+
+/*
+ * @brief Calls the extension implementation for f_provided/f_perform
+ * @param f_provided The name of the virtual function checking if the feature is provided
+ * @param doc The document to check the feature on
+ * @param f_perform The name of the virtual function implementing the feature
+ * @param args Arguments for @p f_perform. This should include @c entry->data as the last argument
+ * @param defret Return value if the feature is not implemented
+ * @returns The return value of @p f_perform or @p defret
+ */
+#define CALL_PERFORM(f_provided, doc, f_perform, args, defret) \
+ G_STMT_START { \
+ for (GList *node = all_extensions; node; node = node->next) \
+ { \
+ PluginExtensionEntry *entry = node->data; \
+ \
+ if (entry->extension->f_provided && \
+ entry->extension->f_provided(doc, entry->data)) \
+ { \
+ if (entry->extension->f_perform) \
+ return entry->extension->f_perform args; \
+ break; \
+ } \
+ } \
+ return defret; \
+ } G_STMT_END
+
-gboolean plugin_extension_autocomplete_provided(GeanyDocument *doc)
+GEANY_API_SYMBOL
+gboolean plugin_extension_autocomplete_provided(GeanyDocument *doc, PluginExtension *ext)
{
- return CALL_IF_EXISTS(autocomplete_provided)(doc);
+ CALL_PROVIDED(autocomplete_provided, doc, ext);
}
void plugin_extension_autocomplete_perform(GeanyDocument *doc, gboolean force)
{
- CALL_IF_EXISTS(autocomplete_perform)(doc, force);
+ CALL_PERFORM(autocomplete_provided, doc, autocomplete_perform, (doc, force, entry->data), /* void */);
}
-gboolean plugin_extension_calltips_provided(GeanyDocument *doc)
+GEANY_API_SYMBOL
+gboolean plugin_extension_calltips_provided(GeanyDocument *doc, PluginExtension *ext)
{
- return CALL_IF_EXISTS(calltips_provided)(doc);
+ CALL_PROVIDED(calltips_provided, doc, ext);
}
void plugin_extension_calltips_show(GeanyDocument *doc, gboolean force)
{
- CALL_IF_EXISTS(calltips_show)(doc, force);
+ CALL_PERFORM(calltips_provided, doc, calltips_show, (doc, force, entry->data), /* void */);
}
-gboolean plugin_extension_goto_provided(GeanyDocument *doc)
+GEANY_API_SYMBOL
+gboolean plugin_extension_goto_provided(GeanyDocument *doc, PluginExtension *ext)
{
- return CALL_IF_EXISTS(goto_provided)(doc);
+ CALL_PROVIDED(goto_provided, doc, ext);
}
void plugin_extension_goto_perform(GeanyDocument *doc, gint pos, gboolean definition)
{
- CALL_IF_EXISTS(goto_perform)(doc, pos, definition);
+ CALL_PERFORM(goto_provided, doc, goto_perform, (doc, pos, definition, entry->data), /* void */);
}
-gboolean plugin_extension_doc_symbols_provided(GeanyDocument *doc)
+GEANY_API_SYMBOL
+gboolean plugin_extension_doc_symbols_provided(GeanyDocument *doc, PluginExtension *ext)
{
- return CALL_IF_EXISTS(doc_symbols_provided)(doc);
+ CALL_PROVIDED(doc_symbols_provided, doc, ext);
}
GPtrArray *plugin_extension_doc_symbols_get(GeanyDocument *doc)
{
- return CALL_IF_EXISTS(doc_symbols_get)(doc);
+ CALL_PERFORM(doc_symbols_provided, doc, doc_symbols_get, (doc, entry->data), NULL);
}
-gboolean plugin_extension_symbol_highlight_provided(GeanyDocument *doc)
+GEANY_API_SYMBOL
+gboolean plugin_extension_symbol_highlight_provided(GeanyDocument *doc, PluginExtension *ext)
{
- return CALL_IF_EXISTS(symbol_highlight_provided)(doc);
+ CALL_PROVIDED(symbol_highlight_provided, doc, ext);
}
diff --git a/src/pluginextension.h b/src/pluginextension.h
index 48866a4a6..3f018efd8 100644
--- a/src/pluginextension.h
+++ b/src/pluginextension.h
@@ -31,47 +31,42 @@ G_BEGIN_DECLS
typedef struct {
- gboolean (*autocomplete_provided)(GeanyDocument *doc);
- void (*autocomplete_perform)(GeanyDocument *doc, gboolean force);
+ gboolean (*autocomplete_provided)(GeanyDocument *doc, gpointer data);
+ void (*autocomplete_perform)(GeanyDocument *doc, gboolean force, gpointer data);
- gboolean (*calltips_provided)(GeanyDocument *doc);
- void (*calltips_show)(GeanyDocument *doc, gboolean force);
+ gboolean (*calltips_provided)(GeanyDocument *doc, gpointer data);
+ void (*calltips_show)(GeanyDocument *doc, gboolean force, gpointer data);
- gboolean (*goto_provided)(GeanyDocument *doc);
- void (*goto_perform)(GeanyDocument *doc, gint pos, gboolean definition);
+ gboolean (*goto_provided)(GeanyDocument *doc, gpointer data);
+ void (*goto_perform)(GeanyDocument *doc, gint pos, gboolean definition, gpointer data);
- gboolean (*doc_symbols_provided)(GeanyDocument *doc);
- GPtrArray *(*doc_symbols_get)(GeanyDocument *doc);
+ gboolean (*doc_symbols_provided)(GeanyDocument *doc, gpointer data);
+ GPtrArray *(*doc_symbols_get)(GeanyDocument *doc, gpointer data);
- gboolean (*symbol_highlight_provided)(GeanyDocument *doc);
+ gboolean (*symbol_highlight_provided)(GeanyDocument *doc, gpointer data);
gchar _dummy[1024];
} PluginExtension;
-void plugin_extension_register(PluginExtension *extension);
+void plugin_extension_register(PluginExtension *extension, gint priority, gpointer data);
void plugin_extension_unregister(PluginExtension *extension);
-gboolean plugin_extension_active(PluginExtension *extension);
+gboolean plugin_extension_autocomplete_provided(GeanyDocument *doc, PluginExtension *ext);
+gboolean plugin_extension_calltips_provided(GeanyDocument *doc, PluginExtension *ext);
+gboolean plugin_extension_goto_provided(GeanyDocument *doc, PluginExtension *ext);
+gboolean plugin_extension_doc_symbols_provided(GeanyDocument *doc, PluginExtension *ext);
+gboolean plugin_extension_symbol_highlight_provided(GeanyDocument *doc, PluginExtension *ext);
#ifdef GEANY_PRIVATE
extern PluginExtension *plugin_extension_geany;
-gboolean plugin_extension_autocomplete_provided(GeanyDocument *doc);
void plugin_extension_autocomplete_perform(GeanyDocument *doc, gboolean force);
-
-gboolean plugin_extension_calltips_provided(GeanyDocument *doc);
void plugin_extension_calltips_show(GeanyDocument *doc, gboolean force);
-
-gboolean plugin_extension_goto_provided(GeanyDocument *doc);
void plugin_extension_goto_perform(GeanyDocument *doc, gint pos, gboolean definition);
-
-gboolean plugin_extension_doc_symbols_provided(GeanyDocument *doc);
GPtrArray *plugin_extension_doc_symbols_get(GeanyDocument *doc);
-gboolean plugin_extension_symbol_highlight_provided(GeanyDocument *doc);
-
#endif /* GEANY_PRIVATE */
G_END_DECLS
diff --git a/src/symbols.c b/src/symbols.c
index e1585ece1..366db783a 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -1708,7 +1708,7 @@ gboolean symbols_goto_tag(const gchar *name, gint pos, gboolean definition)
{
GeanyDocument *doc = document_get_current();
- if (plugin_extension_goto_provided(doc))
+ if (plugin_extension_goto_provided(doc, NULL))
{
/* FIXME: this should return TRUE on success so click handling in
* editor.c can let the even pass through if there was nothing to do here
@@ -1722,7 +1722,7 @@ gboolean symbols_goto_tag(const gchar *name, gint pos, gboolean definition)
}
-void symbols_goto_perform(GeanyDocument *doc, gint pos, gboolean definition)
+void symbols_goto_perform(GeanyDocument *doc, gint pos, gboolean definition, gpointer data G_GNUC_UNUSED)
{
const gchar *name;
diff --git a/src/symbols.h b/src/symbols.h
index 00face7f8..070f4ed42 100644
--- a/src/symbols.h
+++ b/src/symbols.h
@@ -60,7 +60,7 @@ void symbols_show_load_tags_dialog(void);
gboolean symbols_goto_tag(const gchar *name, gint pos, gboolean definition);
-void symbols_goto_perform(GeanyDocument *doc, gint pos, gboolean definition);
+void symbols_goto_perform(GeanyDocument *doc, gint pos, gboolean definition, gpointer data);
gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname);
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.