[gnome-builder] libide: add vim style word movements



commit 7409958dcec47cbb71353a67d261be67b49ac93a
Author: Christian Hergert <christian hergert me>
Date:   Thu Mar 5 19:37:21 2015 -0800

    libide: add vim style word movements
    
    These seem to be working better for me under hard to diagnose scenarios.
    So I'm going to switch back to using ours from vim mode.

 libide/ide-source-view-movements.c |   50 ++++++++++--------
 libide/ide-vim-iter.c              |  102 ++++++++++++++++++++++++++++++++++++
 libide/ide-vim-iter.h              |    3 +
 3 files changed, 133 insertions(+), 22 deletions(-)
---
diff --git a/libide/ide-source-view-movements.c b/libide/ide-source-view-movements.c
index 66f76e4..aa03d18 100644
--- a/libide/ide-source-view-movements.c
+++ b/libide/ide-source-view-movements.c
@@ -32,6 +32,24 @@ typedef struct
 } MatchingBracketState;
 
 static gboolean
+text_iter_forward_to_empty_line (GtkTextIter *iter,
+                                 GtkTextIter *bounds)
+{
+  if (!gtk_text_iter_forward_char (iter))
+    return FALSE;
+
+  while (gtk_text_iter_compare (iter, bounds) < 0)
+    {
+      if (gtk_text_iter_starts_line (iter) && gtk_text_iter_ends_line (iter))
+        return TRUE;
+      if (!gtk_text_iter_forward_char (iter))
+        return FALSE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
 is_single_line_selection (const GtkTextIter *insert,
                           const GtkTextIter *selection)
 {
@@ -807,18 +825,12 @@ ide_source_view_movements_next_word_start (IdeSourceView         *self,
 
   copy = insert;
 
-  if (!_ide_source_iter_ends_word (&insert))
-    _ide_source_iter_forward_visible_word_end (&insert);
-
-  if (_ide_source_iter_forward_visible_word_end (&insert))
-    _ide_source_iter_backward_visible_word_start (&insert);
+  _ide_vim_iter_forward_word_start (&insert);
 
-  /*
-   * Vim treats an empty line as a word.
-   */
-  if (gtk_text_iter_forward_char (&copy))
-    if (gtk_text_iter_get_char (&copy) == '\n')
-      insert = copy;
+  /* prefer an empty line before word */
+  text_iter_forward_to_empty_line (&copy, &insert);
+  if (gtk_text_iter_compare (&copy, &insert) < 0)
+    insert = copy;
 
   ide_source_view_movements_select_range (self, &insert, &selection, extend_selection);
 }
@@ -837,18 +849,12 @@ ide_source_view_movements_next_full_word_start (IdeSourceView         *self,
 
   copy = insert;
 
-  if (!_ide_source_iter_ends_full_word (&insert))
-    _ide_source_iter_forward_full_word_end (&insert);
-
-  _ide_source_iter_forward_full_word_end (&insert);
-  _ide_source_iter_backward_full_word_start (&insert);
+  _ide_vim_iter_forward_WORD_start (&insert);
 
-  /*
-   * Vim treats an empty line as a word.
-   */
-  if (gtk_text_iter_forward_char (&copy))
-    if (gtk_text_iter_get_char (&copy) == '\n')
-      insert = copy;
+  /* prefer an empty line before word */
+  text_iter_forward_to_empty_line (&copy, &insert);
+  if (gtk_text_iter_compare (&copy, &insert) < 0)
+    insert = copy;
 
   ide_source_view_movements_select_range (self, &insert, &selection, extend_selection);
 }
diff --git a/libide/ide-vim-iter.c b/libide/ide-vim-iter.c
index 0089f4f..37fa560 100644
--- a/libide/ide-vim-iter.c
+++ b/libide/ide-vim-iter.c
@@ -28,6 +28,49 @@ typedef enum
   SENTENCE_FAILED,
 } SentenceStatus;
 
+enum
+{
+  CLASS_0,
+  CLASS_SPACE,
+  CLASS_SPECIAL,
+  CLASS_WORD,
+};
+
+static int
+_ide_vim_word_classify (gunichar ch)
+{
+  switch (ch)
+    {
+    case ' ':
+    case '\t':
+    case '\n':
+      return CLASS_SPACE;
+
+    case '"': case '\'':
+    case '(': case ')':
+    case '{': case '}':
+    case '[': case ']':
+    case '<': case '>':
+    case '-': case '+': case '*': case '/':
+    case '!': case '@': case '#': case '$': case '%':
+    case '^': case '&': case ':': case ';': case '?':
+    case '|': case '=': case '\\': case '.': case ',':
+      return CLASS_SPECIAL;
+
+    case '_':
+    default:
+      return CLASS_WORD;
+    }
+}
+
+static int
+_ide_vim_WORD_classify (gunichar ch)
+{
+  if (g_unichar_isspace (ch))
+    return CLASS_SPACE;
+  return CLASS_WORD;
+}
+
 static gboolean
 _ide_vim_iter_line_is_empty (GtkTextIter *iter)
 {
@@ -257,3 +300,62 @@ _ide_vim_iter_backward_sentence_start (GtkTextIter *iter)
       return FALSE;
     }
 }
+
+static gboolean
+_ide_vim_iter_forward_classified_start (GtkTextIter *iter,
+                                        gint (*classify) (gunichar ch))
+{
+  gint begin_class;
+  gint cur_class;
+  gunichar ch;
+
+  g_assert (iter);
+
+  ch = gtk_text_iter_get_char (iter);
+  begin_class = classify (ch);
+
+  /* Move to the first non-whitespace character if necessary. */
+  if (begin_class == CLASS_SPACE)
+    {
+      for (;;)
+        {
+          if (!gtk_text_iter_forward_char (iter))
+            return FALSE;
+
+          ch = gtk_text_iter_get_char (iter);
+          cur_class = classify (ch);
+          if (cur_class != CLASS_SPACE)
+            return TRUE;
+        }
+    }
+
+  /* move to first character not at same class level. */
+  while (gtk_text_iter_forward_char (iter))
+    {
+      ch = gtk_text_iter_get_char (iter);
+      cur_class = classify (ch);
+
+      if (cur_class == CLASS_SPACE)
+        {
+          begin_class = CLASS_0;
+          continue;
+        }
+
+      if (cur_class != begin_class)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+_ide_vim_iter_forward_word_start (GtkTextIter *iter)
+{
+  return _ide_vim_iter_forward_classified_start (iter, _ide_vim_word_classify);
+}
+
+gboolean
+_ide_vim_iter_forward_WORD_start (GtkTextIter *iter)
+{
+  return _ide_vim_iter_forward_classified_start (iter, _ide_vim_WORD_classify);
+}
diff --git a/libide/ide-vim-iter.h b/libide/ide-vim-iter.h
index 85ba31d..a286105 100644
--- a/libide/ide-vim-iter.h
+++ b/libide/ide-vim-iter.h
@@ -23,6 +23,9 @@
 
 G_BEGIN_DECLS
 
+gboolean _ide_vim_iter_forward_word_start       (GtkTextIter *iter);
+gboolean _ide_vim_iter_forward_WORD_start       (GtkTextIter *iter);
+
 gboolean _ide_vim_iter_backward_paragraph_start (GtkTextIter *iter);
 gboolean _ide_vim_iter_forward_paragraph_end    (GtkTextIter *iter);
 gboolean _ide_vim_iter_backward_sentence_start  (GtkTextIter *iter);


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