[gnome-builder/wip/gtk4-port: 673/736] libide/sourceview: add hover providers




commit fe14b6b5875e7e351ff4a105a348e765c07f09c7
Author: Christian Hergert <chergert redhat com>
Date:   Wed Apr 20 12:03:31 2022 -0700

    libide/sourceview: add hover providers
    
    This also cleans up the initialization and moves addin management to an
    external source file to keep ide-source-view.c less busy.
    
    To prevent things from loading until a language has been set, the default
    value is "--disabled--" for the language so we are less likely to load
    something incorrectly when the page is created.

 src/libide/sourceview/ide-source-view-addins.c  | 236 ++++++++++++++++++++++++
 src/libide/sourceview/ide-source-view-private.h |  72 ++++++++
 src/libide/sourceview/ide-source-view.c         | 117 +-----------
 src/libide/sourceview/meson.build               |   3 +-
 4 files changed, 319 insertions(+), 109 deletions(-)
---
diff --git a/src/libide/sourceview/ide-source-view-addins.c b/src/libide/sourceview/ide-source-view-addins.c
new file mode 100644
index 000000000..cf84bbbe8
--- /dev/null
+++ b/src/libide/sourceview/ide-source-view-addins.c
@@ -0,0 +1,236 @@
+/* ide-source-view-addins.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-source-view-addins"
+
+#include "config.h"
+
+#include "ide-source-view-private.h"
+
+#define DISABLED_LANGUAGE_ID "--disabled--"
+
+static void
+ide_source_view_completion_provider_added_cb (IdeExtensionSetAdapter *adapter,
+                                              PeasPluginInfo         *plugin_info,
+                                              PeasExtension          *exten,
+                                              gpointer                user_data)
+{
+  GtkSourceCompletionProvider *provider = (GtkSourceCompletionProvider *)exten;
+  IdeSourceView *self = user_data;
+  GtkSourceCompletion *completion;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
+  g_assert (plugin_info != NULL);
+  g_assert (GTK_SOURCE_IS_COMPLETION_PROVIDER (provider));
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  g_debug ("Adding completion provider %s from module %s",
+           G_OBJECT_TYPE_NAME (provider),
+           peas_plugin_info_get_module_name (plugin_info));
+
+  completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self));
+  gtk_source_completion_add_provider (completion, provider);
+
+  IDE_EXIT;
+}
+
+static void
+ide_source_view_completion_provider_removed_cb (IdeExtensionSetAdapter *adapter,
+                                                PeasPluginInfo         *plugin_info,
+                                                PeasExtension          *exten,
+                                                gpointer                user_data)
+{
+  GtkSourceCompletionProvider *provider = (GtkSourceCompletionProvider *)exten;
+  IdeSourceView *self = user_data;
+  GtkSourceCompletion *completion;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
+  g_assert (plugin_info != NULL);
+  g_assert (GTK_SOURCE_IS_COMPLETION_PROVIDER (provider));
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  g_debug ("Removing completion provider %s from module %s\n",
+           G_OBJECT_TYPE_NAME (provider),
+           peas_plugin_info_get_module_name (plugin_info));
+
+  completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self));
+  gtk_source_completion_remove_provider (completion, provider);
+
+  IDE_EXIT;
+}
+
+static void
+ide_source_view_hover_provider_added_cb (IdeExtensionSetAdapter *adapter,
+                                         PeasPluginInfo         *plugin_info,
+                                         PeasExtension          *exten,
+                                         gpointer                user_data)
+{
+  GtkSourceHoverProvider *provider = (GtkSourceHoverProvider *)exten;
+  IdeSourceView *self = user_data;
+  GtkSourceHover *hover;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
+  g_assert (plugin_info != NULL);
+  g_assert (GTK_SOURCE_IS_HOVER_PROVIDER (provider));
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  g_debug ("Adding hover provider %s from module %s",
+           G_OBJECT_TYPE_NAME (provider),
+           peas_plugin_info_get_module_name (plugin_info));
+
+  hover = gtk_source_view_get_hover (GTK_SOURCE_VIEW (self));
+  gtk_source_hover_add_provider (hover, provider);
+
+  IDE_EXIT;
+}
+
+static void
+ide_source_view_hover_provider_removed_cb (IdeExtensionSetAdapter *adapter,
+                                           PeasPluginInfo         *plugin_info,
+                                           PeasExtension          *exten,
+                                           gpointer                user_data)
+{
+  GtkSourceHoverProvider *provider = (GtkSourceHoverProvider *)exten;
+  IdeSourceView *self = user_data;
+  GtkSourceHover *hover;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
+  g_assert (plugin_info != NULL);
+  g_assert (GTK_SOURCE_IS_HOVER_PROVIDER (provider));
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  g_debug ("Removing hover provider %s from module %s\n",
+           G_OBJECT_TYPE_NAME (provider),
+           peas_plugin_info_get_module_name (plugin_info));
+
+  hover = gtk_source_view_get_hover (GTK_SOURCE_VIEW (self));
+  gtk_source_hover_remove_provider (hover, provider);
+
+  IDE_EXIT;
+}
+
+void
+_ide_source_view_addins_init (IdeSourceView     *self,
+                              GtkSourceLanguage *language)
+{
+  const char *language_id;
+  IdeObjectBox *parent;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+  g_return_if_fail (IDE_IS_BUFFER (self->buffer));
+  g_return_if_fail (!language || GTK_SOURCE_IS_LANGUAGE (language));
+  g_return_if_fail (self->completion_providers == NULL);
+  g_return_if_fail (self->hover_providers == NULL);
+
+  if (language != NULL)
+    language_id = gtk_source_language_get_id (language);
+  else
+    language_id = DISABLED_LANGUAGE_ID;
+
+  /* Get a handle to the buffers "Box" on the object tree */
+  parent = ide_object_box_from_object (G_OBJECT (self->buffer));
+
+  /* Create our completion providers and attach them */
+  self->completion_providers =
+    ide_extension_set_adapter_new (IDE_OBJECT (parent),
+                                   peas_engine_get_default (),
+                                   GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
+                                   "Completion-Provider-Languages",
+                                   language_id);
+  g_signal_connect (self->completion_providers,
+                    "extension-added",
+                    G_CALLBACK (ide_source_view_completion_provider_added_cb),
+                    self);
+  g_signal_connect (self->completion_providers,
+                    "extension-removed",
+                    G_CALLBACK (ide_source_view_completion_provider_removed_cb),
+                    self);
+  ide_extension_set_adapter_foreach (self->completion_providers,
+                                     ide_source_view_completion_provider_added_cb,
+                                     self);
+
+  /* Create our hover providers and attach them */
+  self->hover_providers =
+    ide_extension_set_adapter_new (IDE_OBJECT (parent),
+                                   peas_engine_get_default (),
+                                   GTK_SOURCE_TYPE_HOVER_PROVIDER,
+                                   "Hover-Provider-Languages",
+                                   language_id);
+  g_signal_connect (self->hover_providers,
+                    "extension-added",
+                    G_CALLBACK (ide_source_view_hover_provider_added_cb),
+                    self);
+  g_signal_connect (self->hover_providers,
+                    "extension-removed",
+                    G_CALLBACK (ide_source_view_hover_provider_removed_cb),
+                    self);
+  ide_extension_set_adapter_foreach (self->hover_providers,
+                                     ide_source_view_hover_provider_added_cb,
+                                     self);
+
+  IDE_EXIT;
+}
+
+void
+_ide_source_view_addins_shutdown (IdeSourceView *self)
+{
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  ide_clear_and_destroy_object (&self->completion_providers);
+  ide_clear_and_destroy_object (&self->hover_providers);
+
+  IDE_EXIT;
+}
+
+void
+_ide_source_view_addins_set_language (IdeSourceView     *self,
+                                      GtkSourceLanguage *language)
+{
+  const char *language_id;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+  g_return_if_fail (!language || GTK_SOURCE_IS_LANGUAGE (language));
+  g_return_if_fail (self->completion_providers != NULL);
+  g_return_if_fail (self->hover_providers != NULL);
+
+  if (language != NULL)
+    language_id = gtk_source_language_get_id (language);
+  else
+    language_id = DISABLED_LANGUAGE_ID;
+
+  ide_extension_set_adapter_set_value (self->completion_providers, language_id);
+  ide_extension_set_adapter_set_value (self->hover_providers, language_id);
+
+  IDE_EXIT;
+}
diff --git a/src/libide/sourceview/ide-source-view-private.h b/src/libide/sourceview/ide-source-view-private.h
new file mode 100644
index 000000000..19c847351
--- /dev/null
+++ b/src/libide/sourceview/ide-source-view-private.h
@@ -0,0 +1,72 @@
+/* ide-source-view-private.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-code.h>
+#include <libide-gtk.h>
+#include <libide-plugins.h>
+
+#include "ide-source-view.h"
+
+G_BEGIN_DECLS
+
+struct _IdeSourceView
+{
+  GtkSourceView source_view;
+
+  /* The document (same as get_buffer()) but gives us a pointer
+   * to see our old value when notify::buffer is emitted.
+   */
+  IdeBuffer *buffer;
+
+  /* These are used to generate custom CSS based on the font
+   * description which is also used to scale the contents
+   * in response to user zoom setting. The line-height contains
+   * our setting for additional padding beyond what the font
+   * itself will give us.
+   */
+  GtkCssProvider *css_provider;
+  PangoFontDescription *font_desc;
+  double line_height;
+  int font_scale;
+
+  /* This is a joined menu used to extend the GtkTextView
+   * "extra-menu" property. We join things here and allow
+   * addins to extend it.
+   */
+  IdeJoinedMenu *joined_menu;
+
+  /* Various addins for different ways of extending the
+   * GtkSourceView. These are managed in ide-source-view-addins.c
+   * to load/unload/change-language in response to buffer changes.
+   */
+  IdeExtensionSetAdapter *completion_providers;
+  IdeExtensionSetAdapter *hover_providers;
+};
+
+
+void _ide_source_view_addins_init         (IdeSourceView     *self,
+                                           GtkSourceLanguage *language);
+void _ide_source_view_addins_shutdown     (IdeSourceView     *self);
+void _ide_source_view_addins_set_language (IdeSourceView     *self,
+                                           GtkSourceLanguage *language);
+
+G_END_DECLS
diff --git a/src/libide/sourceview/ide-source-view.c b/src/libide/sourceview/ide-source-view.c
index 34405278a..d2833f6ba 100644
--- a/src/libide/sourceview/ide-source-view.c
+++ b/src/libide/sourceview/ide-source-view.c
@@ -25,25 +25,7 @@
 #include <glib/gi18n.h>
 #include <math.h>
 
-#include <libide-code.h>
-#include <libide-gtk.h>
-#include <libide-plugins.h>
-
-#include "ide-source-view.h"
-
-struct _IdeSourceView
-{
-  GtkSourceView            source_view;
-
-  IdeBuffer               *buffer;
-  GtkCssProvider          *css_provider;
-  PangoFontDescription    *font_desc;
-  IdeJoinedMenu           *joined_menu;
-  IdeExtensionSetAdapter  *completion_providers;
-
-  int                      font_scale;
-  double                   line_height;
-};
+#include "ide-source-view-private.h"
 
 G_DEFINE_TYPE (IdeSourceView, ide_source_view, GTK_SOURCE_TYPE_VIEW)
 
@@ -264,78 +246,18 @@ ide_source_view_buffer_request_scroll_to_insert_cb (IdeSourceView *self,
   IDE_EXIT;
 }
 
-static void
-ide_source_view_completion_provider_added_cb (IdeExtensionSetAdapter *adapter,
-                                              PeasPluginInfo         *plugin_info,
-                                              PeasExtension          *exten,
-                                              gpointer                user_data)
-{
-  GtkSourceCompletionProvider *provider = (GtkSourceCompletionProvider *)exten;
-  IdeSourceView *self = user_data;
-  GtkSourceCompletion *completion;
-
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
-  g_assert (plugin_info != NULL);
-  g_assert (GTK_SOURCE_IS_COMPLETION_PROVIDER (provider));
-  g_assert (IDE_IS_SOURCE_VIEW (self));
-
-  g_debug ("Adding completion provider %s from module %s",
-           G_OBJECT_TYPE_NAME (provider),
-           peas_plugin_info_get_module_name (plugin_info));
-
-  completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self));
-  gtk_source_completion_add_provider (completion, provider);
-
-  IDE_EXIT;
-}
-
-static void
-ide_source_view_completion_provider_removed_cb (IdeExtensionSetAdapter *adapter,
-                                                PeasPluginInfo         *plugin_info,
-                                                PeasExtension          *exten,
-                                                gpointer                user_data)
-{
-  GtkSourceCompletionProvider *provider = (GtkSourceCompletionProvider *)exten;
-  IdeSourceView *self = user_data;
-  GtkSourceCompletion *completion;
-
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
-  g_assert (plugin_info != NULL);
-  g_assert (GTK_SOURCE_IS_COMPLETION_PROVIDER (provider));
-  g_assert (IDE_IS_SOURCE_VIEW (self));
-
-  g_debug ("Removing completion provider %s from module %s\n",
-           G_OBJECT_TYPE_NAME (provider),
-           peas_plugin_info_get_module_name (plugin_info));
-
-  completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (self));
-  gtk_source_completion_remove_provider (completion, provider);
-
-  IDE_EXIT;
-}
-
 static void
 ide_source_view_buffer_notify_language_cb (IdeSourceView *self,
                                            GParamSpec    *pspec,
                                            IdeBuffer     *buffer)
 {
-  GtkSourceLanguage *language;
-  const char *language_id = NULL;
-
   IDE_ENTRY;
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
   g_assert (IDE_IS_BUFFER (buffer));
 
-  if ((language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))))
-    language_id = gtk_source_language_get_id (language);
-
-  if (self->completion_providers != NULL)
-    ide_extension_set_adapter_set_value (self->completion_providers, language_id);
+  _ide_source_view_addins_set_language (self,
+                                        gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer)));
 
   IDE_EXIT;
 }
@@ -345,8 +267,6 @@ ide_source_view_connect_buffer (IdeSourceView *self,
                                 IdeBuffer     *buffer)
 {
   GtkSourceLanguage *language;
-  const char *language_id = NULL;
-  IdeObjectBox *parent;
 
   g_assert (IDE_IS_SOURCE_VIEW (self));
   g_assert (IDE_IS_BUFFER (buffer));
@@ -354,9 +274,6 @@ ide_source_view_connect_buffer (IdeSourceView *self,
 
   g_set_object (&self->buffer, buffer);
 
-  /* Get a handle to the buffers "Box" on the object tree */
-  parent = ide_object_box_from_object (G_OBJECT (buffer));
-
   /* There are cases where we need to force a scroll to insert
    * from just an IdeBuffer pointer. Respond to that appropriately
    * (which generally just happens on load).
@@ -375,27 +292,10 @@ ide_source_view_connect_buffer (IdeSourceView *self,
                            G_CALLBACK (ide_source_view_buffer_notify_language_cb),
                            self,
                            G_CONNECT_SWAPPED);
-  if ((language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer))))
-    language_id = gtk_source_language_get_id (language);
-
-  /* Create our completion providers and attach them */
-  self->completion_providers =
-    ide_extension_set_adapter_new (IDE_OBJECT (parent),
-                                   peas_engine_get_default (),
-                                   GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
-                                   "Completion-Provider-Languages",
-                                   language_id);
-  g_signal_connect (self->completion_providers,
-                    "extension-added",
-                    G_CALLBACK (ide_source_view_completion_provider_added_cb),
-                    self);
-  g_signal_connect (self->completion_providers,
-                    "extension-removed",
-                    G_CALLBACK (ide_source_view_completion_provider_removed_cb),
-                    self);
-  ide_extension_set_adapter_foreach (self->completion_providers,
-                                     ide_source_view_completion_provider_added_cb,
-                                     self);
+
+  /* Load addins immediately */
+  language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buffer));
+  _ide_source_view_addins_init (self, language);
 }
 
 static void
@@ -406,7 +306,8 @@ ide_source_view_disconnect_buffer (IdeSourceView *self)
   if (self->buffer == NULL)
     return;
 
-  g_clear_object (&self->completion_providers);
+  _ide_source_view_addins_shutdown (self);
+
   g_clear_object (&self->buffer);
 }
 
diff --git a/src/libide/sourceview/meson.build b/src/libide/sourceview/meson.build
index af7bd60c6..3dea3b5d7 100644
--- a/src/libide/sourceview/meson.build
+++ b/src/libide/sourceview/meson.build
@@ -10,7 +10,7 @@ libide_sourceview_generated_headers = []
 #
 
 libide_sourceview_private_headers = [
-  'ide-text-util.h',
+  'ide-source-view-private.h',
 ]
 
 libide_sourceview_public_headers = [
@@ -32,6 +32,7 @@ install_headers(libide_sourceview_public_headers, subdir: libide_sourceview_head
 #
 
 libide_sourceview_private_sources = [
+  'ide-source-view-addins.c',
 ]
 
 libide_sourceview_public_sources = [


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]