[gnome-builder] ctags: add experimental ctags autocompletion



commit 88fb356645e53b8188e990275194e8f1eae4fd1c
Author: Christian Hergert <christian hergert me>
Date:   Fri May 15 21:27:50 2015 -0700

    ctags: add experimental ctags autocompletion
    
    Lots of things need to be improved here, but it gets some basic things
    working. We don't even try to deduplicate items right now, which can
    be slightly annoying for common things.
    
    I haven't tried all the various languages that are "supported" but
    in theory they should work. Probably more useful once we land an
    additional symbol resolver.

 libide/c/ide-c-language.c                    |    5 ++
 libide/ctags/ide-ctags-completion-item.c     |    6 +-
 libide/ctags/ide-ctags-completion-item.h     |    6 +-
 libide/ctags/ide-ctags-completion-provider.c |   90 +++++++++++++++++++++++++-
 libide/html/ide-html-language.c              |    1 +
 libide/ide-language.c                        |   32 +++++++++
 libide/python/ide-python-language.c          |    1 +
 7 files changed, 132 insertions(+), 9 deletions(-)
---
diff --git a/libide/c/ide-c-language.c b/libide/c/ide-c-language.c
index d4cdefa..37cd0cb 100644
--- a/libide/c/ide-c-language.c
+++ b/libide/c/ide-c-language.c
@@ -52,6 +52,11 @@ ide_c_language_get_completion_providers (IdeLanguage *language)
 
   g_return_val_if_fail (IDE_IS_C_LANGUAGE (language), NULL);
 
+  providers = IDE_LANGUAGE_CLASS (ide_c_language_parent_class)->get_completion_providers (language);
+
+  /*
+   * Our printf/strftime completion provider.
+   */
   providers = g_list_append (providers, g_object_new (IDE_TYPE_C_FORMAT_PROVIDER, NULL));
 
   /*
diff --git a/libide/ctags/ide-ctags-completion-item.c b/libide/ctags/ide-ctags-completion-item.c
index ab79451..e648378 100644
--- a/libide/ctags/ide-ctags-completion-item.c
+++ b/libide/ctags/ide-ctags-completion-item.c
@@ -25,8 +25,8 @@
 
 struct _IdeCtagsCompletionItem
 {
-  GObject             parent_instance;
-  IdeCtagsIndexEntry *entry;
+  GObject                   parent_instance;
+  const IdeCtagsIndexEntry *entry;
 };
 
 static void proposal_iface_init (GtkSourceCompletionProposalIface *iface);
@@ -36,7 +36,7 @@ G_DEFINE_TYPE_WITH_CODE (IdeCtagsCompletionItem, ide_ctags_completion_item, G_TY
                                                 proposal_iface_init))
 
 GtkSourceCompletionProposal *
-ide_ctags_completion_item_new (IdeCtagsIndexEntry *entry)
+ide_ctags_completion_item_new (const IdeCtagsIndexEntry *entry)
 {
   IdeCtagsCompletionItem *self;
 
diff --git a/libide/ctags/ide-ctags-completion-item.h b/libide/ctags/ide-ctags-completion-item.h
index 0c37bca..5587231 100644
--- a/libide/ctags/ide-ctags-completion-item.h
+++ b/libide/ctags/ide-ctags-completion-item.h
@@ -29,9 +29,9 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCtagsCompletionItem, ide_ctags_completion_item, IDE, CTAGS_COMPLETION_ITEM, GObject)
 
-GtkSourceCompletionProposal *ide_ctags_completion_item_new     (IdeCtagsIndexEntry     *entry);
-gint                         ide_ctags_completion_item_compare (IdeCtagsCompletionItem *itema,
-                                                                IdeCtagsCompletionItem *itemb);
+GtkSourceCompletionProposal *ide_ctags_completion_item_new     (const IdeCtagsIndexEntry *entry);
+gint                         ide_ctags_completion_item_compare (IdeCtagsCompletionItem   *itema,
+                                                                IdeCtagsCompletionItem   *itemb);
 
 G_END_DECLS
 
diff --git a/libide/ctags/ide-ctags-completion-provider.c b/libide/ctags/ide-ctags-completion-provider.c
index 1578033..83a60e7 100644
--- a/libide/ctags/ide-ctags-completion-provider.c
+++ b/libide/ctags/ide-ctags-completion-provider.c
@@ -29,6 +29,7 @@ struct _IdeCtagsCompletionProvider
 {
   GObject        parent_instance;
 
+  GSettings     *settings;
   GPtrArray     *indexes;
 
   gint           minimum_word_size;
@@ -56,6 +57,7 @@ ide_ctags_completion_provider_finalize (GObject *object)
   IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)object;
 
   g_clear_pointer (&self->indexes, g_ptr_array_unref);
+  g_clear_object (&self->settings);
 
   G_OBJECT_CLASS (ide_ctags_completion_provider_parent_class)->finalize (object);
 }
@@ -73,6 +75,7 @@ ide_ctags_completion_provider_init (IdeCtagsCompletionProvider *self)
 {
   self->minimum_word_size = 3;
   self->indexes = g_ptr_array_new_with_free_func (g_object_unref);
+  self->settings = g_settings_new ("org.gnome.builder.experimental");
 }
 
 static gchar *
@@ -132,6 +135,75 @@ sort_wrapper (gconstpointer a,
   return ide_ctags_completion_item_compare (*enta, *entb);
 }
 
+static const gchar * const *
+get_allowed_suffixes (GtkSourceBuffer *buffer)
+{
+  static const gchar *c_languages[] = { ".c", ".h",
+                                        ".cc", ".hh",
+                                        ".cpp", ".hpp",
+                                        ".cxx", ".hxx",
+                                        NULL };
+  static const gchar *vala_languages[] = { ".vala", NULL };
+  static const gchar *python_languages[] = { ".py", NULL };
+  static const gchar *js_languages[] = { ".js", NULL };
+  static const gchar *html_languages[] = { ".html",
+                                           ".htm",
+                                           ".tmpl",
+                                           ".css",
+                                           ".js",
+                                           NULL };
+  GtkSourceLanguage *language;
+  const gchar *lang_id;
+
+  language = gtk_source_buffer_get_language (buffer);
+  if (!language)
+    return NULL;
+
+  lang_id = gtk_source_language_get_id (language);
+
+  /*
+   * NOTE:
+   *
+   * This seems like the type of thing that should be provided as a property
+   * to the ctags provider. However, I'm trying to only have one provider
+   * in process for now, so we hard code things here.
+   *
+   * If we decide to load multiple providers (that all sync with the ctags
+   * service), then we can put this in IdeLanguage:get_completion_providers()
+   * vfunc overrides.
+   */
+
+  if (ide_str_equal0 (lang_id, "c") || ide_str_equal0 (lang_id, "chdr") || ide_str_equal0 (lang_id, "cpp"))
+    return c_languages;
+  else if (ide_str_equal0 (lang_id, "vala"))
+    return vala_languages;
+  else if (ide_str_equal0 (lang_id, "python"))
+    return python_languages;
+  else if (ide_str_equal0 (lang_id, "js"))
+    return js_languages;
+  else if (ide_str_equal0 (lang_id, "html"))
+    return html_languages;
+  else
+    return NULL;
+}
+
+static gboolean
+is_allowed (const IdeCtagsIndexEntry *entry,
+            const gchar * const      *allowed)
+{
+  if (allowed)
+    {
+      const gchar *dotptr = strrchr (entry->path, '.');
+      gsize i;
+
+      for (i = 0; allowed [i]; i++)
+        if (ide_str_equal0 (dotptr, allowed [i]))
+          return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
                                         GtkSourceCompletionContext  *context)
@@ -139,7 +211,9 @@ ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
   IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider;
   g_autofree gchar *word = NULL;
   const IdeCtagsIndexEntry *entries;
+  const gchar * const *allowed;
   g_autoptr(GPtrArray) ar = NULL;
+  GtkSourceBuffer *buffer;
   gsize n_entries;
   GtkTextIter iter;
   GList *list = NULL;
@@ -154,9 +228,15 @@ ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
   if (self->indexes->len == 0)
     IDE_GOTO (failure);
 
+  if (!g_settings_get_boolean (self->settings, "ctags-autocompletion"))
+    IDE_GOTO (failure);
+
   if (!gtk_source_completion_context_get_iter (context, &iter))
     IDE_GOTO (failure);
 
+  buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (&iter));
+  allowed = get_allowed_suffixes (buffer);
+
   word = get_word_to_cursor (&iter);
   if (ide_str_empty0 (word) || strlen (word) < self->minimum_word_size)
     IDE_GOTO (failure);
@@ -166,7 +246,7 @@ ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
 
   ar = g_ptr_array_new_with_free_func (g_object_unref);
 
-  g_print ("LOOKING UP WORD: %s\n", word);
+  IDE_TRACE_MSG ("Searching for %s", word);
 
   for (j = 0; j < self->indexes->len; j++)
     {
@@ -179,9 +259,13 @@ ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
       for (i = 0; i < n_entries; i++)
         {
           GtkSourceCompletionProposal *item;
+          const IdeCtagsIndexEntry *entry = &entries [i];
 
-          item = ide_ctags_completion_item_new ((IdeCtagsIndexEntry *)&entries [i]);
-          g_ptr_array_add (ar, item);
+          if (is_allowed (entry, allowed))
+            {
+              item = ide_ctags_completion_item_new (entry);
+              g_ptr_array_add (ar, item);
+            }
         }
     }
 
diff --git a/libide/html/ide-html-language.c b/libide/html/ide-html-language.c
index 75738f9..10f2bb9 100644
--- a/libide/html/ide-html-language.c
+++ b/libide/html/ide-html-language.c
@@ -44,6 +44,7 @@ ide_html_language_get_completion_providers (IdeLanguage *language)
 
   g_assert (IDE_IS_HTML_LANGUAGE (language));
 
+  list = IDE_LANGUAGE_CLASS (ide_html_language_parent_class)->get_completion_providers (language);
   list = g_list_append (list, g_object_new (IDE_TYPE_HTML_COMPLETION_PROVIDER, NULL));
 
   return list;
diff --git a/libide/ide-language.c b/libide/ide-language.c
index 8b311ed..56d85c9 100644
--- a/libide/ide-language.c
+++ b/libide/ide-language.c
@@ -18,6 +18,8 @@
 
 #include <glib/gi18n.h>
 
+#include "ide-context.h"
+#include "ide-ctags-service.h"
 #include "ide-diagnostician.h"
 #include "ide-gca-diagnostic-provider.h"
 #include "ide-highlighter.h"
@@ -75,6 +77,35 @@ ide_language_get_source_language (IdeLanguage *self)
   return language;
 }
 
+static GList *
+ide_language_real_get_completion_providers (IdeLanguage *self)
+{
+  IdeLanguagePrivate *priv = ide_language_get_instance_private (self);
+  GList *providers = NULL;
+
+  g_assert (IDE_IS_LANGUAGE (self));
+
+  if (ide_str_equal0 (priv->id, "c") ||
+      ide_str_equal0 (priv->id, "cpp") ||
+      ide_str_equal0 (priv->id, "chdr") ||
+      ide_str_equal0 (priv->id, "python") ||
+      ide_str_equal0 (priv->id, "js") ||
+      ide_str_equal0 (priv->id, "css") ||
+      ide_str_equal0 (priv->id, "html"))
+    {
+      IdeCtagsService *service;
+      GtkSourceCompletionProvider *provider;
+      IdeContext *context;
+
+      context = ide_object_get_context (IDE_OBJECT (self));
+      service = ide_context_get_service_typed (context, IDE_TYPE_CTAGS_SERVICE);
+      provider = ide_ctags_service_get_provider (service);
+      providers = g_list_prepend (providers, g_object_ref (provider));
+    }
+
+  return providers;
+}
+
 /**
  * ide_language_get_completion_providers:
  * @self: An #IdeLanguage.
@@ -339,6 +370,7 @@ ide_language_class_init (IdeLanguageClass *klass)
   object_class->get_property = ide_language_get_property;
   object_class->set_property = ide_language_set_property;
 
+  klass->get_completion_providers = ide_language_real_get_completion_providers;
   klass->get_diagnostician = ide_language_real_get_diagnostician;
 
   gParamSpecs [PROP_DIAGNOSTICIAN] =
diff --git a/libide/python/ide-python-language.c b/libide/python/ide-python-language.c
index 1b9ab70..f4070b8 100644
--- a/libide/python/ide-python-language.c
+++ b/libide/python/ide-python-language.c
@@ -44,6 +44,7 @@ ide_python_language_get_completion_providers (IdeLanguage *language)
 
   g_return_val_if_fail (IDE_IS_PYTHON_LANGUAGE (language), NULL);
 
+  providers = IDE_LANGUAGE_CLASS (ide_python_language_parent_class)->get_completion_providers (language);
   providers = g_list_append (providers, g_object_new (IDE_TYPE_PYTHON_FORMAT_PROVIDER, NULL));
 
   return providers;


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