[gtksourceview/wip/fix-completion-words: 2/3] CompletionWords buffer: work with strings for scanning the words



commit f2f8f182035366682a84001bf2674810c9c29e79
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sat Jun 8 15:54:25 2013 +0200

    CompletionWords buffer: work with strings for scanning the words
    
    Instead of working with GtkTextIters. It normally improves the
    performances.
    
    And there was maybe a bug with the previous code (warning messages).

 .../words/gtksourcecompletionwordsbuffer.c         |   75 ++++----------
 .../words/gtksourcecompletionwordslibrary.c        |    1 +
 .../words/gtksourcecompletionwordsutils.c          |  106 ++++++++++++++++----
 .../words/gtksourcecompletionwordsutils.h          |    9 +-
 4 files changed, 109 insertions(+), 82 deletions(-)
---
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c 
b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c
index 036fd2b..be483de 100644
--- a/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsbuffer.c
@@ -3,6 +3,7 @@
  * This file is part of GtkSourceView
  *
  * Copyright (C) 2009 - Jesse van den Kieboom
+ * Copyright (C) 2013 - Sébastien Wilmet
  *
  * gtksourceview is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -201,70 +202,32 @@ gtk_source_completion_words_buffer_init (GtkSourceCompletionWordsBuffer *self)
                                                   (GDestroyNotify)proposal_cache_free);
 }
 
-static gboolean
-valid_word_char (gunichar ch,
-                 gpointer data)
-{
-       return g_unichar_isprint (ch) && (ch == '_' || g_unichar_isalnum (ch));
-}
-
-static gboolean
-valid_start_char (gunichar ch)
-{
-       return !g_unichar_isdigit (ch);
-}
-
 static GSList *
 scan_line (GtkSourceCompletionWordsBuffer *buffer,
            GtkTextIter                    *start)
 {
-       GSList *ret = NULL;
-       GtkTextIter end;
-       gint line = gtk_text_iter_get_line (start);
+       GtkTextIter end = *start;
+       gchar *text_line;
+       GSList *words;
 
-       while (line == gtk_text_iter_get_line (start))
+       if (!gtk_text_iter_starts_line (start))
        {
-               gchar *word;
-
-               while (!gtk_text_iter_ends_line (start) &&
-                      !valid_word_char (gtk_text_iter_get_char (start), NULL))
-               {
-                       gtk_text_iter_forward_char (start);
-               }
-
-               if (gtk_text_iter_ends_line (start))
-               {
-                       break;
-               }
-
-               end = *start;
-
-               if (!gtk_source_completion_words_utils_forward_word_end (&end,
-                                                                        valid_word_char,
-                                                                        NULL))
-               {
-                       break;
-               }
+               g_warning ("scan line: 'start' doesn't start a line.");
+               gtk_text_iter_set_line_offset (start, 0);
+       }
 
-               if (valid_start_char (gtk_text_iter_get_char (start)))
-               {
-                       if (gtk_text_iter_get_offset (&end) -
-                           gtk_text_iter_get_offset (start) >= buffer->priv->minimum_word_size)
-                       {
-                               word = gtk_text_iter_get_text (start, &end);
-                               ret = g_slist_prepend (ret, word);
-                       }
-               }
+       gtk_text_iter_forward_to_line_end (&end);
 
-               *start = end;
+       text_line = gtk_text_buffer_get_text (buffer->priv->buffer,
+                                             start,
+                                             &end,
+                                             FALSE);
 
-               if (!gtk_text_iter_forward_char (start))
-               {
-                       break;
-               }
-       }
+       words = _gtk_source_completion_words_utils_scan_words (text_line,
+                                                              buffer->priv->minimum_word_size);
 
-       return ret;
+       g_free (text_line);
+       return words;
 }
 
 static void
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c 
b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c
index 1e898d4..8f70fd2 100644
--- a/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordslibrary.c
@@ -3,6 +3,7 @@
  * This file is part of GtkSourceView
  *
  * Copyright (C) 2009 - Jesse van den Kieboom
+ * Copyright (C) 2013 - Sébastien Wilmet
  *
  * gtksourceview is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.c 
b/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.c
index edc1a8c..d27034b 100644
--- a/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.c
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.c
@@ -23,42 +23,108 @@
 #include "gtksourcecompletionwordsutils.h"
 #include <string.h>
 
-gboolean
-gtk_source_completion_words_utils_forward_word_end (GtkTextIter    *iter,
-                                                    CharacterCheck  valid,
-                                                    gpointer        data)
+/* Here, we work on strings. It is more efficient than working with
+ * GtkTextIters to traverse the text. Both techniques are equally difficult to
+ * implement.
+ */
+
+static gboolean
+valid_word_char (gunichar ch)
+{
+       return g_unichar_isprint (ch) && (ch == '_' || g_unichar_isalnum (ch));
+}
+
+static gboolean
+valid_start_char (gunichar ch)
+{
+       return !g_unichar_isdigit (ch);
+}
+
+/* Find the next word in @text, beginning at the index @start_idx.
+ * Use only valid_word_char() to find the word boundaries.
+ * Store in @start_idx and @end_idx the word boundaries. The character at
+ * @start_idx is included in the word, but the character at @end_idx is not
+ * included in the word (it is the next char, or '\0').
+ *
+ * Returns %TRUE if a word has been found.
+ */
+static gboolean
+find_next_word (gchar *text,
+               guint *start_idx,
+               guint *end_idx)
 {
-       /* Go backward as long as there are word characters */
+       gchar *cur_char;
+
+       /* Find the start of the next word */
+
+       cur_char = text + *start_idx;
+
        while (TRUE)
        {
-               /* Ending a line is good */
-               if (gtk_text_iter_ends_line (iter))
+               gunichar ch = g_utf8_get_char (cur_char);
+
+               if (ch == '\0')
                {
-                       break;
+                       return FALSE;
                }
 
-               /* Check if the next character is a valid word character */
-               if (!valid (gtk_text_iter_get_char (iter), data))
+               if (valid_word_char (ch))
                {
+                       *start_idx = cur_char - text;
                        break;
                }
 
-               gtk_text_iter_forward_char (iter);
+               cur_char = g_utf8_next_char (cur_char);
        }
 
-       return TRUE;
-}
+       /* Find the end of the word */
 
-static gboolean
-valid_word_char (gunichar ch)
-{
-       return g_unichar_isprint (ch) && (ch == '_' || g_unichar_isalnum (ch));
+       while (TRUE)
+       {
+               gunichar ch;
+
+               cur_char = g_utf8_next_char (cur_char);
+               ch = g_utf8_get_char (cur_char);
+
+               if (ch == '\0' ||
+                   !valid_word_char (ch))
+               {
+                       *end_idx = cur_char - text;
+                       return TRUE;
+               }
+       }
 }
 
-static gboolean
-valid_start_char (gunichar ch)
+/* Get the list of words in @text.
+ * You must free the data with g_free(), and free the list with
+ * g_slist_free().
+ */
+GSList *
+_gtk_source_completion_words_utils_scan_words (gchar *text,
+                                              guint  minimum_word_size)
 {
-       return !g_unichar_isdigit (ch);
+       GSList *words = NULL;
+       guint start_idx = 0;
+       guint end_idx = 0;
+
+       while (find_next_word (text, &start_idx, &end_idx))
+       {
+               gint word_size = end_idx - start_idx;
+               gunichar ch = g_utf8_get_char (text + start_idx);
+
+               g_assert (word_size >= 0);
+
+               if (word_size >= minimum_word_size &&
+                   valid_start_char (ch))
+               {
+                       gchar *new_word = g_strndup (text + start_idx, word_size);
+                       words = g_slist_prepend (words, new_word);
+               }
+
+               start_idx = end_idx;
+       }
+
+       return words;
 }
 
 /* Get the word at the end of @text.
diff --git a/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.h 
b/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.h
index 5d6650c..7c4f100 100644
--- a/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.h
+++ b/gtksourceview/completion-providers/words/gtksourcecompletionwordsutils.h
@@ -27,15 +27,12 @@
 
 G_BEGIN_DECLS
 
-typedef gboolean (*CharacterCheck)(gunichar ch, gpointer data);
-
 G_GNUC_INTERNAL
-gboolean        gtk_source_completion_words_utils_forward_word_end     (GtkTextIter    *iter,
-                                                                        CharacterCheck  valid,
-                                                                        gpointer        data);
+GSList         *_gtk_source_completion_words_utils_scan_words          (gchar *text,
+                                                                        guint  minimum_word_size);
 
 G_GNUC_INTERNAL
-gchar          *_gtk_source_completion_words_utils_get_end_word        (gchar          *text);
+gchar          *_gtk_source_completion_words_utils_get_end_word        (gchar *text);
 
 G_END_DECLS
 


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