[gnome-builder] vim: enhance % motion



commit aed12e79973351e7c42e900751d4bee32da41e1d
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sat Nov 7 17:45:42 2015 +0100

    vim: enhance % motion
    
    Like vim, you don't need to be on a matching
    character to make matching special work
    
    Percent (%) now work with C block comments ( /* */ )

 libide/ide-source-view-movements.c |  174 +++++++++++++++++++++++++++++++-----
 1 files changed, 150 insertions(+), 24 deletions(-)
---
diff --git a/libide/ide-source-view-movements.c b/libide/ide-source-view-movements.c
index c91b916..ff05887 100644
--- a/libide/ide-source-view-movements.c
+++ b/libide/ide-source-view-movements.c
@@ -1004,46 +1004,172 @@ find_chars_forward (GtkTextIter *cursor,
   return FALSE;
 }
 static gboolean
+vim_percent_predicate (GtkTextIter *iter,
+                       gunichar     ch,
+                       gpointer     user_data)
+{
+  GtkTextIter near;
+
+  if (ch == '(' || ch == ')' ||
+      ch == '[' || ch == ']' ||
+      ch == '{' || ch == '}' ||
+      ch == '/' || ch == '*' ||
+      ch == '#')
+    {
+      if (!gtk_text_iter_starts_line (iter))
+        {
+          near = *iter;
+          gtk_text_iter_backward_char (&near);
+
+          return (gtk_text_iter_get_char (&near) != '\\');
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+match_comments (GtkTextIter *insert,
+                gunichar     ch)
+{
+  GtkTextIter cursor;
+  GtkTextIter cursor_before;
+  GtkTextIter cursor_after;
+  gunichar ch_before = 0;
+  gunichar ch_after = 0;
+  gboolean comment_start;
+
+  cursor_after = *insert;
+  if (gtk_text_iter_forward_char (&cursor_after))
+    ch_after = gtk_text_iter_get_char (&cursor_after);
+
+  cursor_before = *insert;
+  if (gtk_text_iter_backward_char (&cursor_before))
+    ch_before = gtk_text_iter_get_char (&cursor_before);
+
+  if ((ch == '/' && ch_before == '*' && ch_after == '*') ||
+      (ch == '*' && ch_before == '/' && ch_after == '/'))
+    {
+      *insert = cursor_after;
+      return FALSE;
+    }
+
+  if (ch == '/' && ch_after == '*')
+    {
+      gtk_text_iter_forward_char (&cursor_after);
+      *insert = cursor = cursor_after;
+      comment_start = TRUE;
+    }
+  else if (ch_before == '/' && ch == '*' && ch_after != 0)
+    {
+      *insert = cursor = cursor_after;
+      comment_start = TRUE;
+    }
+  else if (ch == '*' && ch_after == '/' && ch_before != 0)
+    {
+      cursor = *insert;
+      *insert = cursor_after;
+      gtk_text_iter_forward_char (insert);
+      comment_start = FALSE;
+    }
+  else if (ch_before == '*' && ch == '/')
+    {
+      cursor = cursor_before;
+      *insert = cursor_after;
+      comment_start = FALSE;
+    }
+  else
+    {
+      *insert = cursor_after;
+      return FALSE;
+    }
+
+  if (comment_start && !gtk_text_iter_is_end (&cursor))
+    {
+      if (find_chars_forward (&cursor, NULL, "*/", FALSE))
+        {
+          gtk_text_iter_forward_char (&cursor);
+          *insert = cursor;
+
+          return TRUE;
+        }
+    }
+  else if (!comment_start && !gtk_text_iter_is_start (&cursor))
+    {
+      if (find_chars_backward (&cursor, NULL, "/*", FALSE))
+        {
+          *insert = cursor;
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
 
 static void
 ide_source_view_movements_match_special (Movement *mv)
 {
   gunichar start_char;
   GtkTextIter copy;
-  gboolean ret;
+  GtkTextIter limit;
+  gboolean ret = FALSE;
+
+  limit = copy = mv->insert;
+  gtk_text_iter_forward_to_line_end (&limit);
 
-  copy = mv->insert;
   start_char = gtk_text_iter_get_char (&mv->insert);
+  if (!vim_percent_predicate (&mv->insert, start_char, NULL))
+    {
+loop:
+      if (_ide_vim_iter_forward_find_char (&mv->insert, vim_percent_predicate, NULL, &limit))
+        start_char = gtk_text_iter_get_char (&mv->insert);
+      else
+        {
+          mv->insert = copy;
+          return;
+        }
+    }
 
-  switch (start_char)
+  if (start_char == '/' || start_char == '*')
     {
-    case '{':
-      ret = match_char_with_depth (&mv->insert, '{', '}', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
-      break;
+      if (match_comments (&mv->insert, start_char))
+        return;
+      else
+        goto loop;
+    }
 
-    case '[':
-      ret = match_char_with_depth (&mv->insert, '[', ']', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
-      break;
+  switch (start_char)
+  {
+  case '{':
+    ret = match_char_with_depth (&mv->insert, '{', '}', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
+    break;
 
-    case '(':
-      ret = match_char_with_depth (&mv->insert, '(', ')', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
-      break;
+  case '[':
+    ret = match_char_with_depth (&mv->insert, '[', ']', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
+    break;
 
-    case '}':
-      ret = match_char_with_depth (&mv->insert, '{', '}', GTK_DIR_LEFT, 1, mv->exclusive, 0);
-      break;
+  case '(':
+    ret = match_char_with_depth (&mv->insert, '(', ')', GTK_DIR_RIGHT, 1, mv->exclusive, 0);
+    break;
 
-    case ']':
-      ret = match_char_with_depth (&mv->insert, '[', ']', GTK_DIR_LEFT, 1, mv->exclusive, 0);
-      break;
+  case '}':
+    ret = match_char_with_depth (&mv->insert, '{', '}', GTK_DIR_LEFT, 1, mv->exclusive, 0);
+    break;
 
-    case ')':
-      ret = match_char_with_depth (&mv->insert, '(', ')', GTK_DIR_LEFT, 1, mv->exclusive, 0);
-      break;
+  case ']':
+    ret = match_char_with_depth (&mv->insert, '[', ']', GTK_DIR_LEFT, 1, mv->exclusive, 0);
+    break;
 
-    default:
-      return;
-    }
+  case ')':
+    ret = match_char_with_depth (&mv->insert, '(', ')', GTK_DIR_LEFT, 1, mv->exclusive, 0);
+    break;
+
+  default:
+    return;
+  }
 
   if (!ret)
     mv->insert = copy;


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