[gnome-builder/wip/highlight] highlight: implement incremental, callback based, highlight engine



commit ceadec60177fd81c24423ccdf0062a18dca2337f
Author: Christian Hergert <christian hergert me>
Date:   Thu Mar 26 16:49:40 2015 -0700

    highlight: implement incremental, callback based, highlight engine
    
    Now, the highlight engine will provide a callback to perform a style
    update. That callback will return if the highlighter may continue or
    if it has expired its quanta.
    
    This helps reduce the overhead in highlighters that need to setup a bunch
    of information to make forward progress in the buffer. It has the small
    cost of a qdata lookup in the callback. (We could make this less by
    enforcing the highlighter pass extra data back, but I don't like the API
    much for that).
    
    The index can now take arbitrary pointers as the values for words. The
    clang index takes advantage of this to specify the direct tags it wants.
    
    This will change in the future as we add more styling information to
    builder.xml (and builder-dark.xml). Other style schemes will need to
    do the same if they want extra-detailed coloring.
    
    For example, we have plans for functions, macros, members, fields, and
    other special types which may not map to the same generic coloring that
    other languages will want to use.
    
    Anyway, WIP

 libide/clang/ide-clang-highlighter.c |   73 +++++++++--------
 libide/clang/ide-clang-service.c     |    6 +-
 libide/ide-highlight-engine.c        |  147 +++++++++++++++++-----------------
 libide/ide-highlight-index.c         |   24 ++++--
 libide/ide-highlight-index.h         |    6 +-
 libide/ide-highlighter.c             |   43 ++++++----
 libide/ide-highlighter.h             |   48 +++++++-----
 7 files changed, 189 insertions(+), 158 deletions(-)
---
diff --git a/libide/clang/ide-clang-highlighter.c b/libide/clang/ide-clang-highlighter.c
index 32e45b8..c214160 100644
--- a/libide/clang/ide-clang-highlighter.c
+++ b/libide/clang/ide-clang-highlighter.c
@@ -58,12 +58,12 @@ select_next_word (GtkTextIter *begin,
   return TRUE;
 }
 
-static IdeHighlightKind
-ide_clang_highlighter_real_next (IdeHighlighter    *highlighter,
-                                 const GtkTextIter *range_begin,
-                                 const GtkTextIter *range_end,
-                                 GtkTextIter       *begin,
-                                 GtkTextIter       *end)
+static void
+ide_clang_highlighter_real_update (IdeHighlighter       *highlighter,
+                                   IdeHighlightCallback  callback,
+                                   const GtkTextIter    *range_begin,
+                                   const GtkTextIter    *range_end,
+                                   GtkTextIter          *location)
 {
   IdeClangHighlighter *self = (IdeClangHighlighter *)highlighter;
   GtkTextBuffer *text_buffer;
@@ -74,18 +74,14 @@ ide_clang_highlighter_real_next (IdeHighlighter    *highlighter,
   IdeClangService *service;
   IdeBuffer *buffer;
   IdeFile *file;
-
-  /*
-   * TODO:
-   *
-   * This API has a decent bit of overhead. Instead, we should move to an API
-   * design that allows us to walk through the entire buffer, and then call a
-   * callback (back into the engine) to set the style name for the region.
-   * This would allow us to amortize the overhead cost of getting the
-   * information we need.
-   */
+  GtkTextIter begin;
+  GtkTextIter end;
 
   g_assert (IDE_IS_CLANG_HIGHLIGHTER (self));
+  g_assert (callback != NULL);
+  g_assert (range_begin != NULL);
+  g_assert (range_end != NULL);
+  g_assert (location != NULL);
 
   if (!(text_buffer = gtk_text_iter_get_buffer (range_begin)) ||
       !IDE_IS_BUFFER (text_buffer) ||
@@ -96,39 +92,46 @@ ide_clang_highlighter_real_next (IdeHighlighter    *highlighter,
       !(service = ide_context_get_service_typed (context, IDE_TYPE_CLANG_SERVICE)) ||
       !(unit = ide_clang_service_get_cached_translation_unit (service, file)) ||
       !(index = ide_clang_translation_unit_get_index (unit)))
-    return IDE_HIGHLIGHT_KIND_NONE;
+    return;
 
-  *begin = *end = *range_begin;
+  begin = end = *location = *range_begin;
 
-  while (gtk_text_iter_compare (begin, range_end) < 0)
+  while (gtk_text_iter_compare (&begin, range_end) < 0)
     {
-      if (!select_next_word (begin, end))
-        return IDE_HIGHLIGHT_KIND_NONE;
+      if (!select_next_word (&begin, &end))
+        goto completed;
 
-      if (gtk_text_iter_compare (begin, range_end) >= 0)
-        return IDE_HIGHLIGHT_KIND_NONE;
+      if (gtk_text_iter_compare (&begin, range_end) >= 0)
+        goto completed;
 
-      g_assert (!gtk_text_iter_equal (begin, end));
+      g_assert (!gtk_text_iter_equal (&begin, &end));
 
-      if (!gtk_source_buffer_iter_has_context_class (source_buffer, begin, "string") &&
-          !gtk_source_buffer_iter_has_context_class (source_buffer, begin, "path") &&
-          !gtk_source_buffer_iter_has_context_class (source_buffer, begin, "comment"))
+      if (!gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "string") &&
+          !gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "path") &&
+          !gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "comment"))
         {
-          IdeHighlightKind ret;
+          const gchar *tag;
           gchar *word;
 
-          word = gtk_text_iter_get_slice (begin, end);
-          ret = ide_highlight_index_lookup (index, word);
+          word = gtk_text_iter_get_slice (&begin, &end);
+          tag = ide_highlight_index_lookup (index, word);
           g_free (word);
 
-          if (ret != IDE_HIGHLIGHT_KIND_NONE)
-            return ret;
+          if (tag != NULL)
+            {
+              if (callback (&begin, &end, tag) == IDE_HIGHLIGHT_STOP)
+                {
+                  *location = end;
+                  return;
+                }
+            }
         }
 
-      *begin = *end;
+      begin = end;
     }
 
-  return IDE_HIGHLIGHT_KIND_NONE;
+completed:
+  *location = *range_end;
 }
 
 static void
@@ -136,7 +139,7 @@ ide_clang_highlighter_class_init (IdeClangHighlighterClass *klass)
 {
   IdeHighlighterClass *highlighter_class = IDE_HIGHLIGHTER_CLASS (klass);
 
-  highlighter_class->next = ide_clang_highlighter_real_next;
+  highlighter_class->update = ide_clang_highlighter_real_update;
 }
 
 static void
diff --git a/libide/clang/ide-clang-service.c b/libide/clang/ide-clang-service.c
index 1633ffc..700666d 100644
--- a/libide/clang/ide-clang-service.c
+++ b/libide/clang/ide-clang-service.c
@@ -93,20 +93,20 @@ ide_clang_service_build_index_visitor (CXCursor     cursor,
     case CXCursor_TypeAliasDecl:
       cxstr = clang_getCursorSpelling (cursor);
       word = clang_getCString (cxstr);
-      ide_highlight_index_insert (request->index, word, IDE_HIGHLIGHT_KIND_TYPE_NAME);
+      ide_highlight_index_insert (request->index, word, "def:type");
       break;
 
     case CXCursor_FunctionDecl:
       cxstr = clang_getCursorSpelling (cursor);
       word = clang_getCString (cxstr);
-      ide_highlight_index_insert (request->index, word, IDE_HIGHLIGHT_KIND_FUNCTION_NAME);
+      ide_highlight_index_insert (request->index, word, "def:function");
       break;
 
     case CXCursor_MacroDefinition:
     case CXCursor_MacroExpansion:
       cxstr = clang_getCursorSpelling (cursor);
       word = clang_getCString (cxstr);
-      ide_highlight_index_insert (request->index, word, IDE_HIGHLIGHT_KIND_MACRO_NAME);
+      ide_highlight_index_insert (request->index, word, "def:preprocessor");
       break;
 
     default:
diff --git a/libide/ide-highlight-engine.c b/libide/ide-highlight-engine.c
index b4a7160..0035e7a 100644
--- a/libide/ide-highlight-engine.c
+++ b/libide/ide-highlight-engine.c
@@ -34,11 +34,13 @@ struct _IdeHighlightEngine
   IdeBuffer      *buffer;
   IdeHighlighter *highlighter;
 
-  GtkTextTag     *tags[IDE_HIGHLIGHT_KIND_LAST];
-
   GtkTextMark    *invalid_begin;
   GtkTextMark    *invalid_end;
 
+  GList          *tags;
+
+  guint64         quanta_expiration;
+
   guint           work_timeout;
 };
 
@@ -52,6 +54,7 @@ enum {
 };
 
 static GParamSpec *gParamSpecs [LAST_PROP];
+static GQuark      gEngineQuark;
 
 static GtkTextTag *
 create_tag_from_style (IdeHighlightEngine *self,
@@ -75,7 +78,7 @@ create_tag_from_style (IdeHighlightEngine *self,
   g_assert (self->buffer != NULL);
   g_assert (IDE_IS_BUFFER (self->buffer));
 
-  tag = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (self->buffer), NULL, NULL);
+  tag = gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (self->buffer), style_name, NULL);
 
   style_scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (self->buffer));
   if (style_scheme == NULL)
@@ -117,38 +120,46 @@ create_tag_from_style (IdeHighlightEngine *self,
 }
 
 static GtkTextTag *
-get_kind_tag (IdeHighlightEngine *self,
-              IdeHighlightKind    kind)
+get_style_tag (IdeHighlightEngine *self,
+               const gchar        *style_name)
 {
-  const gchar *name = NULL;
+  GtkTextTagTable *tag_table;
+  GtkTextTag *tag;
 
   g_assert (IDE_IS_HIGHLIGHT_ENGINE (self));
+  g_assert (style_name != NULL);
+
+  tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (self->buffer));
+  tag = gtk_text_tag_table_lookup (tag_table, style_name);
 
-  switch (kind)
+  if (tag == NULL)
     {
-    case IDE_HIGHLIGHT_KIND_TYPE_NAME:
-    case IDE_HIGHLIGHT_KIND_CLASS_NAME:
-      name = "def:type";
-      break;
+      tag = create_tag_from_style (self, style_name);
+      self->tags = g_list_prepend (self->tags, tag);
+    }
 
-    case IDE_HIGHLIGHT_KIND_FUNCTION_NAME:
-    case IDE_HIGHLIGHT_KIND_MACRO_NAME:
-      name = "def:function";
-      break;
+  return tag;
+}
 
-    case IDE_HIGHLIGHT_KIND_CONSTANT:
-      name = "def:constant";
-      break;
+static IdeHighlightResult
+ide_highlight_engine_apply_style (const GtkTextIter *begin,
+                                  const GtkTextIter *end,
+                                  const gchar       *style_name)
+{
+  IdeHighlightEngine *self;
+  GtkTextBuffer *buffer;
+  GtkTextTag *tag;
 
-    case IDE_HIGHLIGHT_KIND_NONE:
-    default:
-      return NULL;
-    }
+  buffer = gtk_text_iter_get_buffer (begin);
+  self = g_object_get_qdata (G_OBJECT (buffer), gEngineQuark);
+  tag = get_style_tag (self, style_name);
+
+  gtk_text_buffer_apply_tag (buffer, tag, begin, end);
 
-    if ((self->tags [kind] == NULL) && (name != NULL))
-      self->tags [kind] = create_tag_from_style (self, name);
+  if (g_get_monotonic_time () >= self->quanta_expiration)
+    return IDE_HIGHLIGHT_STOP;
 
-    return self->tags [kind];
+  return IDE_HIGHLIGHT_CONTINUE;
 }
 
 static gboolean
@@ -156,10 +167,8 @@ ide_highlight_engine_tick (IdeHighlightEngine *self)
 {
   GtkTextBuffer *buffer;
   GtkTextIter iter;
-  GtkTextIter begin;
-  GtkTextIter end;
-  guint64 quanta_expiration;
-  IdeHighlightKind kind;
+  GtkTextIter invalid_begin;
+  GtkTextIter invalid_end;
 
   IDE_PROBE;
 
@@ -169,50 +178,38 @@ ide_highlight_engine_tick (IdeHighlightEngine *self)
   g_assert (self->invalid_begin != NULL);
   g_assert (self->invalid_end != NULL);
 
-  quanta_expiration = g_get_monotonic_time () + HIGHLIGHT_QUANTA_USEC;
+  self->quanta_expiration = g_get_monotonic_time () + HIGHLIGHT_QUANTA_USEC;
 
   buffer = GTK_TEXT_BUFFER (self->buffer);
 
-  do
-    {
-      GtkTextTag *tag;
-      GtkTextIter invalid_begin;
-      GtkTextIter invalid_end;
-
-      gtk_text_buffer_get_iter_at_mark (buffer, &invalid_begin, self->invalid_begin);
-      gtk_text_buffer_get_iter_at_mark (buffer, &invalid_end, self->invalid_end);
-
-      IDE_TRACE_MSG ("Highlight Range (%u:%u <=> %u:%u)",
-                     gtk_text_iter_get_line (&invalid_begin),
-                     gtk_text_iter_get_line_offset (&invalid_begin),
-                     gtk_text_iter_get_line (&invalid_end),
-                     gtk_text_iter_get_line_offset (&invalid_end));
-
-      if (gtk_text_iter_compare (&invalid_begin, &invalid_end) >= 0)
-        IDE_GOTO (up_to_date);
+  gtk_text_buffer_get_iter_at_mark (buffer, &invalid_begin, self->invalid_begin);
+  gtk_text_buffer_get_iter_at_mark (buffer, &invalid_end, self->invalid_end);
 
-      iter = invalid_begin;
+  IDE_TRACE_MSG ("Highlight Range (%u:%u <=> %u:%u)",
+                 gtk_text_iter_get_line (&invalid_begin),
+                 gtk_text_iter_get_line_offset (&invalid_begin),
+                 gtk_text_iter_get_line (&invalid_end),
+                 gtk_text_iter_get_line_offset (&invalid_end));
 
-      kind = ide_highlighter_next (self->highlighter, &iter, &invalid_end, &begin, &end);
+  if (gtk_text_iter_compare (&invalid_begin, &invalid_end) >= 0)
+    IDE_GOTO (up_to_date);
 
-      if (kind == IDE_HIGHLIGHT_KIND_NONE)
-        IDE_GOTO (up_to_date);
+  iter = invalid_begin;
 
-      IDE_TRACE_MSG ("Found tag of kind: %d", kind);
+  ide_highlighter_update (self->highlighter, ide_highlight_engine_apply_style,
+                          &invalid_begin, &invalid_end, &iter);
 
-      tag = get_kind_tag (self, kind);
+  if (gtk_text_iter_compare (&iter, &invalid_end) >= 0)
+    IDE_GOTO (up_to_date);
 
-      gtk_text_buffer_apply_tag (buffer, tag, &begin, &end);
-      gtk_text_buffer_move_mark (buffer, self->invalid_begin, &end);
-    }
-  while (g_get_monotonic_time () < quanta_expiration);
+  gtk_text_buffer_move_mark (buffer, self->invalid_begin, &iter);
 
   return TRUE;
 
 up_to_date:
-  gtk_text_buffer_get_start_iter (buffer, &begin);
-  gtk_text_buffer_move_mark (buffer, self->invalid_begin, &begin);
-  gtk_text_buffer_move_mark (buffer, self->invalid_end, &begin);
+  gtk_text_buffer_get_start_iter (buffer, &iter);
+  gtk_text_buffer_move_mark (buffer, self->invalid_begin, &iter);
+  gtk_text_buffer_move_mark (buffer, self->invalid_end, &iter);
 
   return FALSE;
 }
@@ -251,7 +248,7 @@ ide_highlight_engine_reload (IdeHighlightEngine *self)
   GtkTextBuffer *buffer;
   GtkTextIter begin;
   GtkTextIter end;
-  gsize i;
+  GList *iter;
 
   IDE_ENTRY;
 
@@ -279,9 +276,10 @@ ide_highlight_engine_reload (IdeHighlightEngine *self)
   /*
    * Remove our highlight tags from the buffer.
    */
-  for (i = 0; i < G_N_ELEMENTS (self->tags); i++)
-    if (self->tags [i] != NULL)
-      gtk_text_buffer_remove_tag (buffer, self->tags [i], &begin, &end);
+  for (iter = self->tags; iter; iter = iter->next)
+    gtk_text_buffer_remove_tag (buffer, iter->data, &begin, &end);
+  g_list_free (self->tags);
+  self->tags = NULL;
 
   if (self->highlighter == NULL)
     IDE_EXIT;
@@ -393,6 +391,8 @@ ide_highlight_engine_connect_buffer (IdeHighlightEngine *self,
   g_assert (IDE_IS_HIGHLIGHT_ENGINE (self));
   g_assert (IDE_IS_BUFFER (buffer));
 
+  g_object_set_qdata (G_OBJECT (buffer), gEngineQuark, self);
+
   gtk_text_buffer_get_bounds (text_buffer, &begin, &end);
 
   self->invalid_begin = gtk_text_buffer_create_mark (text_buffer, NULL, &begin, TRUE);
@@ -423,7 +423,7 @@ ide_highlight_engine_disconnect_buffer (IdeHighlightEngine *self,
   GtkTextTagTable *tag_table;
   GtkTextIter begin;
   GtkTextIter end;
-  gsize i;
+  GList *iter;
 
   IDE_ENTRY;
 
@@ -436,6 +436,8 @@ ide_highlight_engine_disconnect_buffer (IdeHighlightEngine *self,
       self->work_timeout = 0;
     }
 
+  g_object_set_qdata (G_OBJECT (buffer), gEngineQuark, NULL);
+
   g_signal_handlers_disconnect_by_func (buffer,
                                         G_CALLBACK (ide_highlight_engine__buffer_delete_range_cb),
                                         self);
@@ -454,16 +456,15 @@ ide_highlight_engine_disconnect_buffer (IdeHighlightEngine *self,
 
   gtk_text_buffer_get_bounds (text_buffer, &begin, &end);
 
-  for (i = 0; i < G_N_ELEMENTS (self->tags); i++)
+  for (iter = self->tags; iter; iter= iter->next)
     {
-      if (self->tags [i] != NULL)
-        {
-          gtk_text_buffer_remove_tag (text_buffer, self->tags [i], &begin, &end);
-          gtk_text_tag_table_remove (tag_table, self->tags [i]);
-          self->tags [i] = NULL;
-        }
+      gtk_text_buffer_remove_tag (text_buffer, iter->data, &begin, &end);
+      gtk_text_tag_table_remove (tag_table, iter->data);
     }
 
+  g_list_free (self->tags);
+  self->tags = NULL;
+
   IDE_EXIT;
 }
 
@@ -584,6 +585,8 @@ ide_highlight_engine_class_init (IdeHighlightEngineClass *klass)
                          IDE_TYPE_HIGHLIGHTER,
                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_HIGHLIGHTER, gParamSpecs [PROP_HIGHLIGHTER]);
+
+  gEngineQuark = g_quark_from_string ("IDE_HIGHLIGHT_ENGINE");
 }
 
 static void
diff --git a/libide/ide-highlight-index.c b/libide/ide-highlight-index.c
index ee8b445..0d9d81b 100644
--- a/libide/ide-highlight-index.c
+++ b/libide/ide-highlight-index.c
@@ -52,12 +52,12 @@ ide_highlight_index_new (void)
 void
 ide_highlight_index_insert (IdeHighlightIndex *self,
                             const gchar       *word,
-                            IdeHighlightKind   kind)
+                            gpointer           tag)
 {
   gchar *key;
 
   g_assert (self);
-  g_assert (kind != IDE_HIGHLIGHT_KIND_NONE);
+  g_assert (tag != NULL);
 
   if (word == NULL || word[0] == '\0')
     return;
@@ -69,21 +69,27 @@ ide_highlight_index_insert (IdeHighlightIndex *self,
   self->chunk_size += strlen (word) + 1;
 
   key = g_string_chunk_insert (self->strings, word);
-  g_hash_table_insert (self->index, key, GINT_TO_POINTER (kind));
+  g_hash_table_insert (self->index, key, tag);
 }
 
-IdeHighlightKind
+/**
+ * ide_highlight_index_lookup:
+ * @self: An #IdeHighlightIndex.
+ *
+ * Gets the pointer tag that was registered for @word, or %NULL.  This can be
+ * any arbitrary value. Some highlight engines might use it to point at
+ * internal structures or strings they know about to optimize later work.
+ *
+ * Returns: (transfer none) (nullable): Highlighter specific tag.
+ */
+gpointer
 ide_highlight_index_lookup (IdeHighlightIndex *self,
                             const gchar       *word)
 {
-  gpointer value;
-
   g_assert (self);
   g_assert (word);
 
-  value = g_hash_table_lookup (self->index, word);
-
-  return GPOINTER_TO_INT (value);
+  return g_hash_table_lookup (self->index, word);
 }
 
 IdeHighlightIndex *
diff --git a/libide/ide-highlight-index.h b/libide/ide-highlight-index.h
index ab95c00..8cf294d 100644
--- a/libide/ide-highlight-index.h
+++ b/libide/ide-highlight-index.h
@@ -19,7 +19,7 @@
 #ifndef IDE_HIGHLIGHT_INDEX_H
 #define IDE_HIGHLIGHT_INDEX_H
 
-#include "ide-highlighter.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -33,8 +33,8 @@ IdeHighlightIndex *ide_highlight_index_ref      (IdeHighlightIndex *self);
 void               ide_highlight_index_unref    (IdeHighlightIndex *self);
 void               ide_highlight_index_insert   (IdeHighlightIndex *self,
                                                  const gchar       *word,
-                                                 IdeHighlightKind   kind);
-IdeHighlightKind   ide_highlight_index_lookup   (IdeHighlightIndex *self,
+                                                 gpointer           tag);
+gpointer           ide_highlight_index_lookup   (IdeHighlightIndex *self,
                                                  const gchar       *word);
 void               ide_highlight_index_dump     (IdeHighlightIndex *self);
 
diff --git a/libide/ide-highlighter.c b/libide/ide-highlighter.c
index 6b54162..9ccb0ed 100644
--- a/libide/ide-highlighter.c
+++ b/libide/ide-highlighter.c
@@ -30,23 +30,32 @@ ide_highlighter_init (IdeHighlighter *self)
 {
 }
 
-IdeHighlightKind
-ide_highlighter_next (IdeHighlighter    *self,
-                      const GtkTextIter *range_begin,
-                      const GtkTextIter *range_end,
-                      GtkTextIter       *match_begin,
-                      GtkTextIter       *match_end)
+/**
+ * ide_highlighter_update:
+ * @self: A #IdeHighlighter.
+ * @callback: (scope call): A callback to apply a given style.
+ * @range_begin: The beginning of the range to update.
+ * @range_end: The end of the range to update.
+ * @location: (out): How far the highlighter got in the update.
+ *
+ * Incrementally processes more of the buffer for highlighting.  If @callback
+ * returns %IDE_HIGHLIGHT_STOP, then this vfunc should stop processing and
+ * return, having set @location to the current position of processing.
+ *
+ * If processing the entire range was successful, then @location should be set
+ * to @range_end.
+ */
+void
+ide_highlighter_update (IdeHighlighter       *self,
+                        IdeHighlightCallback  callback,
+                        const GtkTextIter    *range_begin,
+                        const GtkTextIter    *range_end,
+                        GtkTextIter          *location)
 {
-  g_return_val_if_fail (IDE_IS_HIGHLIGHTER (self), 0);
-  g_return_val_if_fail (range_begin, 0);
-  g_return_val_if_fail (range_end, 0);
-  g_return_val_if_fail (match_begin, 0);
-  g_return_val_if_fail (match_end, 0);
-
-  if (IDE_HIGHLIGHTER_GET_CLASS (self)->next)
-    return IDE_HIGHLIGHTER_GET_CLASS (self)->next (self,
-                                                   range_begin, range_end,
-                                                   match_begin, match_end);
+  g_return_if_fail (IDE_IS_HIGHLIGHTER (self));
+  g_return_if_fail (range_begin);
+  g_return_if_fail (range_end);
 
-  return IDE_HIGHLIGHT_KIND_NONE;
+  if (IDE_HIGHLIGHTER_GET_CLASS (self)->update)
+    IDE_HIGHLIGHTER_GET_CLASS (self)->update (self, callback, range_begin, range_end, location);
 }
diff --git a/libide/ide-highlighter.h b/libide/ide-highlighter.h
index 4723f02..ed5932c 100644
--- a/libide/ide-highlighter.h
+++ b/libide/ide-highlighter.h
@@ -33,33 +33,43 @@ G_DECLARE_DERIVABLE_TYPE (IdeHighlighter, ide_highlighter, IDE, HIGHLIGHTER, Ide
 
 typedef enum
 {
-  IDE_HIGHLIGHT_KIND_NONE,
+  IDE_HIGHLIGHT_STOP,
+  IDE_HIGHLIGHT_CONTINUE,
+} IdeHighlightResult;
 
-  IDE_HIGHLIGHT_KIND_TYPE_NAME,
-  IDE_HIGHLIGHT_KIND_CLASS_NAME,
-  IDE_HIGHLIGHT_KIND_FUNCTION_NAME,
-  IDE_HIGHLIGHT_KIND_MACRO_NAME,
-  IDE_HIGHLIGHT_KIND_CONSTANT,
-
-  IDE_HIGHLIGHT_KIND_LAST
-} IdeHighlightKind;
+typedef IdeHighlightResult (*IdeHighlightCallback) (const GtkTextIter *begin,
+                                                    const GtkTextIter *end,
+                                                    const gchar       *style_name);
 
 struct _IdeHighlighterClass
 {
   IdeObjectClass parent;
 
-  IdeHighlightKind (*next) (IdeHighlighter    *self,
-                            const GtkTextIter *range_begin,
-                            const GtkTextIter *range_end,
-                            GtkTextIter       *match_begin,
-                            GtkTextIter       *match_end);
+  /**
+   * IdeHighlighter::update:
+   *
+   * #IdeHighlighter should call callback() with the range and style-name of
+   * the style to apply. Callback will ensure that the style exists and style
+   * it appropriately based on the style scheme.
+   *
+   * If @callback returns %IDE_HIGHLIGHT_STOP, the caller has run out of its
+   * time slice and should yield back to the highlight engine.
+   *
+   * @location should be set to the position that the highlighter got to
+   * before yielding back to the engine.
+   */
+  void (*update) (IdeHighlighter       *self,
+                  IdeHighlightCallback  callback,
+                  const GtkTextIter    *range_begin,
+                  const GtkTextIter    *range_end,
+                  GtkTextIter          *location);
 };
 
-IdeHighlightKind ide_highlighter_next (IdeHighlighter    *self,
-                                       const GtkTextIter *range_begin,
-                                       const GtkTextIter *range_end,
-                                       GtkTextIter       *match_begin,
-                                       GtkTextIter       *match_end);
+void ide_highlighter_update (IdeHighlighter       *self,
+                             IdeHighlightCallback  callback,
+                             const GtkTextIter    *range_begin,
+                             const GtkTextIter    *range_end,
+                             GtkTextIter          *location);
 
 G_END_DECLS
 


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