[gnome-builder/wip/libide] libide: add IdeSourceView:smart-backspace gproperty



commit 074ad36e63dab752c2fbc1211d00fee72d87c49d
Author: Christian Hergert <christian hergert me>
Date:   Sat Mar 14 21:01:04 2015 -0700

    libide: add IdeSourceView:smart-backspace gproperty
    
    Smart backspace will attempt to backspace extra characters when you are
    at the indent boundary. It will mind the tab_indent and indent_width
    properties to generally do the right thing.
    
    If you are a tab, and the indent_width is less than the tab width, spaces
    will be added until you reach the target indent width (after removing the
    tab).

 libide/ide-source-view.c |  121 +++++++++++++++++++++++++++++++++++++++++++++-
 libide/ide-source-view.h |    3 +
 2 files changed, 122 insertions(+), 2 deletions(-)
---
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index 8e3e4f9..a521c78 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -143,6 +143,7 @@ typedef struct
   guint                        show_line_changes : 1;
   guint                        show_search_bubbles : 1;
   guint                        show_search_shadow : 1;
+  guint                        smart_backspace : 1;
   guint                        snippet_completion : 1;
   guint                        waiting_for_capture : 1;
 } IdeSourceViewPrivate;
@@ -174,6 +175,7 @@ enum {
   PROP_SHOW_LINE_CHANGES,
   PROP_SHOW_SEARCH_BUBBLES,
   PROP_SHOW_SEARCH_SHADOW,
+  PROP_SMART_BACKSPACE,
   PROP_SNIPPET_COMPLETION,
   LAST_PROP
 };
@@ -1881,6 +1883,73 @@ is_modifier_key (GdkEventKey *event)
 }
 
 static gboolean
+ide_source_view_do_smart_backspace (IdeSourceView *self,
+                                    GdkEventKey   *event)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter insert;
+  GtkTextIter end;
+  guint visual_column;
+  gint indent_width;
+  gint tab_width;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (event);
+  g_assert (event->type == GDK_KEY_PRESS);
+
+#define GET_VISUAL_COLUMN(iter) gtk_source_view_get_visual_column(GTK_SOURCE_VIEW(self),iter)
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+
+  gtk_text_buffer_get_selection_bounds (buffer, &insert, &end);
+
+  if (!gtk_text_iter_equal (&insert, &end))
+    return FALSE;
+
+  visual_column = GET_VISUAL_COLUMN (&insert);
+  indent_width = gtk_source_view_get_indent_width (GTK_SOURCE_VIEW (self));
+  tab_width = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (self));
+  if (indent_width <= 0)
+    indent_width = tab_width;
+
+  if (visual_column < indent_width)
+    return FALSE;
+
+  if ((visual_column % indent_width) == 0)
+    {
+      gint target_column = visual_column - indent_width;
+      gunichar ch;
+
+      g_assert_cmpint (target_column, >=, 0);
+
+      while (GET_VISUAL_COLUMN (&insert) > target_column)
+        {
+          gtk_text_iter_backward_char (&insert);
+          ch = gtk_text_iter_get_char (&insert);
+
+          if (!g_unichar_isspace (ch))
+            return FALSE;
+        }
+
+      ch = gtk_text_iter_get_char (&insert);
+      if (!g_unichar_isspace (ch))
+        return FALSE;
+
+      gtk_text_buffer_begin_user_action (buffer);
+      gtk_text_buffer_delete (buffer, &insert, &end);
+      while (GET_VISUAL_COLUMN (&insert) < target_column)
+        gtk_text_buffer_insert (buffer, &insert, " ", 1);
+      gtk_text_buffer_end_user_action (buffer);
+
+      return TRUE;
+    }
+
+#undef GET_VISUAL_COLUMN
+
+  return FALSE;
+}
+
+static gboolean
 ide_source_view_key_press_event (GtkWidget   *widget,
                                  GdkEventKey *event)
 {
@@ -1981,8 +2050,12 @@ ide_source_view_key_press_event (GtkWidget   *widget,
    * then we might want to delete it too.
    */
   if ((event->keyval == GDK_KEY_BackSpace) && !gtk_text_buffer_get_has_selection (buffer))
-    if (ide_source_view_maybe_delete_match (self, event))
-      return TRUE;
+    {
+      if (ide_source_view_maybe_delete_match (self, event))
+        return TRUE;
+      else if (priv->smart_backspace && ide_source_view_do_smart_backspace (self, event))
+        return TRUE;
+    }
 
   /*
    * If we have an auto-indenter and the event is for a trigger key, then we
@@ -4149,6 +4222,10 @@ ide_source_view_get_property (GObject    *object,
       g_value_set_boolean (value, ide_source_view_get_show_search_shadow (self));
       break;
 
+    case PROP_SMART_BACKSPACE:
+      g_value_set_boolean (value, ide_source_view_get_smart_backspace (self));
+      break;
+
     case PROP_SNIPPET_COMPLETION:
       g_value_set_boolean (value, ide_source_view_get_snippet_completion (self));
       break;
@@ -4218,6 +4295,10 @@ ide_source_view_set_property (GObject      *object,
       ide_source_view_set_show_search_shadow (self, g_value_get_boolean (value));
       break;
 
+    case PROP_SMART_BACKSPACE:
+      ide_source_view_set_smart_backspace (self, g_value_get_boolean (value));
+      break;
+
     case PROP_SNIPPET_COMPLETION:
       ide_source_view_set_snippet_completion (self, g_value_get_boolean (value));
       break;
@@ -4397,6 +4478,15 @@ ide_source_view_class_init (IdeSourceViewClass *klass)
   g_object_class_install_property (object_class, PROP_SHOW_SEARCH_SHADOW,
                                    gParamSpecs [PROP_SHOW_SEARCH_SHADOW]);
 
+  gParamSpecs [PROP_SMART_BACKSPACE] =
+    g_param_spec_boolean ("smart-backspace",
+                         _("Smart Backspace"),
+                         _("If smart backspace should be used."),
+                         FALSE,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SMART_BACKSPACE,
+                                   gParamSpecs [PROP_SMART_BACKSPACE]);
+
   gParamSpecs [PROP_SNIPPET_COMPLETION] =
     g_param_spec_boolean ("snippet-completion",
                           _("Snippet Completion"),
@@ -5673,3 +5763,30 @@ ide_source_view_set_show_search_shadow (IdeSourceView *self,
       ide_source_view_invalidate_window (self);
     }
 }
+
+gboolean
+ide_source_view_get_smart_backspace (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_SOURCE_VIEW (self), NULL);
+
+  return priv->smart_backspace;
+}
+
+void
+ide_source_view_set_smart_backspace (IdeSourceView *self,
+                                     gboolean       smart_backspace)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  smart_backspace = !!smart_backspace;
+
+  if (smart_backspace != priv->smart_backspace)
+    {
+      priv->smart_backspace = smart_backspace;
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_SMART_BACKSPACE]);
+    }
+}
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index 561c471..549e880 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -284,6 +284,7 @@ gboolean                    ide_source_view_get_show_grid_lines       (IdeSource
 gboolean                    ide_source_view_get_show_line_changes     (IdeSourceView              *self);
 gboolean                    ide_source_view_get_show_search_bubbles   (IdeSourceView              *self);
 gboolean                    ide_source_view_get_show_search_shadow    (IdeSourceView              *self);
+gboolean                    ide_source_view_get_smart_backspace       (IdeSourceView              *self);
 gboolean                    ide_source_view_get_snippet_completion    (IdeSourceView              *self);
 GType                       ide_source_view_get_type                  (void);
 void                        ide_source_view_get_visible_rect          (IdeSourceView              *self,
@@ -313,6 +314,8 @@ void                        ide_source_view_set_show_search_bubbles   (IdeSource
                                                                        gboolean                    
show_search_bubbles);
 void                        ide_source_view_set_show_search_shadow    (IdeSourceView              *self,
                                                                        gboolean                    
show_search_bubbles);
+void                        ide_source_view_set_smart_backspace       (IdeSourceView              *self,
+                                                                       gboolean                    
smart_backspace);
 void                        ide_source_view_set_snippet_completion    (IdeSourceView              *self,
                                                                        gboolean                    
snippet_completion);
 void                        ide_source_view_set_back_forward_list     (IdeSourceView              *self,


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