[gtksourceview] Add "smart-backspace" property
- From: Paolo Borelli <pborelli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview] Add "smart-backspace" property
- Date: Sun, 21 Jun 2015 12:14:08 +0000 (UTC)
commit b04a9f5cf5a85f11b3a5ee98da180214ac58e55b
Author: Paolo Borelli <pborelli gnome org>
Date: Sun Jun 21 12:25:25 2015 +0200
Add "smart-backspace" property
Ported from gnome-builder code. Gedit has a smart-spaces plugin
with the same logic, so it makes sense to consolidate the
implementation in gtksourceview itself
docs/reference/gtksourceview-3.0-sections.txt | 2 +
gtksourceview/gtksourceview.c | 197 ++++++++++++++++++++++++-
gtksourceview/gtksourceview.h | 5 +
tests/test-widget.c | 8 +
tests/test-widget.ui | 15 ++-
5 files changed, 224 insertions(+), 3 deletions(-)
---
diff --git a/docs/reference/gtksourceview-3.0-sections.txt b/docs/reference/gtksourceview-3.0-sections.txt
index 7e18b88..01a6a46 100644
--- a/docs/reference/gtksourceview-3.0-sections.txt
+++ b/docs/reference/gtksourceview-3.0-sections.txt
@@ -852,6 +852,8 @@ gtk_source_view_get_insert_spaces_instead_of_tabs
gtk_source_view_indent_lines
gtk_source_view_unindent_lines
gtk_source_view_get_visual_column
+gtk_source_view_set_smart_backspace
+gtk_source_view_get_smart_backspace
gtk_source_view_set_smart_home_end
gtk_source_view_get_smart_home_end
gtk_source_view_set_mark_attributes
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index 8f0e1ea..2c98f3e 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -157,7 +157,8 @@ enum
PROP_HIGHLIGHT_CURRENT_LINE,
PROP_INDENT_ON_TAB,
PROP_DRAW_SPACES,
- PROP_BACKGROUND_PATTERN
+ PROP_BACKGROUND_PATTERN,
+ PROP_SMART_BACKSPACE
};
struct _GtkSourceViewPrivate
@@ -202,6 +203,7 @@ struct _GtkSourceViewPrivate
guint style_scheme_applied : 1;
guint current_line_color_set : 1;
guint background_pattern_color_set : 1;
+ guint smart_backspace : 1;
};
typedef struct _MarkCategory MarkCategory;
@@ -652,6 +654,14 @@ gtk_source_view_class_init (GtkSourceViewClass *klass)
GTK_SOURCE_BACKGROUND_PATTERN_TYPE_NONE,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SMART_BACKSPACE,
+ g_param_spec_boolean ("smart-backspace",
+ _("Smart Backspace"),
+ _("Whether smart Backspace should be used."),
+ FALSE,
+ G_PARAM_READWRITE));
+
signals[UNDO] =
g_signal_new ("undo",
G_TYPE_FROM_CLASS (klass),
@@ -1114,6 +1124,10 @@ gtk_source_view_set_property (GObject *object,
gtk_source_view_set_background_pattern (view, g_value_get_enum (value));
break;
+ case PROP_SMART_BACKSPACE:
+ gtk_source_view_set_smart_backspace (view, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1137,6 +1151,7 @@ gtk_source_view_get_property (GObject *object,
case PROP_COMPLETION:
g_value_set_object (value, gtk_source_view_get_completion (view));
break;
+
case PROP_SHOW_LINE_NUMBERS:
g_value_set_boolean (value, gtk_source_view_get_show_line_numbers (view));
break;
@@ -1189,6 +1204,10 @@ gtk_source_view_get_property (GObject *object,
g_value_set_enum (value, gtk_source_view_get_background_pattern (view));
break;
+ case PROP_SMART_BACKSPACE:
+ g_value_set_boolean (value, gtk_source_view_get_smart_backspace (view));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -4025,6 +4044,128 @@ gtk_source_view_move_lines (GtkSourceView *view,
}
static gboolean
+gtk_source_view_do_smart_backspace (GtkSourceView *view,
+ guint modifiers)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter insert;
+ GtkTextIter end;
+ GtkTextIter tmp;
+ guint visual_column;
+ gint indent_width;
+ gint tab_width;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ if (gtk_text_buffer_get_selection_bounds (buffer, &insert, &end))
+ {
+ return FALSE;
+ }
+
+ if ((modifiers & GDK_CONTROL_MASK) != 0)
+ {
+ /*
+ * A <Control>BackSpace at the beginning of the line should only move us to the
+ * end of the previous line. Anything more than that is non-obvious because it requires
+ * looking in a position other than where the cursor is.
+ */
+ if ((gtk_text_iter_get_line_offset (&insert) == 0) && (gtk_text_iter_get_line (&insert) > 0))
+ {
+ gtk_text_buffer_begin_user_action (buffer);
+ gtk_text_iter_backward_char (&insert);
+ gtk_text_buffer_delete (buffer, &insert, &end);
+ gtk_text_buffer_end_user_action (buffer);
+
+ return TRUE;
+ }
+ }
+
+ /* if the line isn't empty up to our cursor, ignore */
+ tmp = insert;
+ while (TRUE)
+ {
+ gunichar ch;
+
+ ch = gtk_text_iter_get_char (&tmp);
+
+ if ((ch != 0) && !g_unichar_isspace (ch))
+ {
+ return FALSE;
+ }
+
+ if (gtk_text_iter_starts_line (&tmp))
+ {
+ break;
+ }
+
+ gtk_text_iter_backward_char (&tmp);
+ }
+
+ /*
+ * If <Control>BackSpace was specified, delete up to the zero position.
+ */
+ if ((modifiers & GDK_CONTROL_MASK) != 0)
+ {
+ gtk_text_buffer_begin_user_action (buffer);
+ gtk_text_iter_set_line_offset (&insert, 0);
+ gtk_text_buffer_delete (buffer, &insert, &end);
+ gtk_text_buffer_end_user_action (buffer);
+
+ return TRUE;
+ }
+
+ visual_column = gtk_source_view_get_visual_column (view, &insert);
+ indent_width = gtk_source_view_get_indent_width (view);
+ tab_width = gtk_source_view_get_tab_width (view);
+ 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 (target_column >= 0);
+
+ while (gtk_source_view_get_visual_column (view, &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 (gtk_source_view_get_visual_column (view, &insert) < target_column)
+ {
+ gtk_text_buffer_insert (buffer, &insert, " ", 1);
+ }
+ gtk_text_buffer_end_user_action (buffer);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
gtk_source_view_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
@@ -4131,7 +4272,15 @@ gtk_source_view_key_press_event (GtkWidget *widget,
}
insert_tab_or_spaces (view, &s, &e);
- return TRUE;
+ return TRUE;
+ }
+
+ if ((key == GDK_KEY_BackSpace) && view->priv->smart_backspace)
+ {
+ if (gtk_source_view_do_smart_backspace (view, (event->state & modifiers)))
+ {
+ return TRUE;
+ }
}
return GTK_WIDGET_CLASS (gtk_source_view_parent_class)->key_press_event (widget, event);
@@ -4464,6 +4613,50 @@ gtk_source_view_set_right_margin_position (GtkSourceView *view,
}
/**
+ * gtk_source_view_set_smart_backspace:
+ * @view: a #GtkSourceView.
+ * @smart_backspace: whether to enable smart Backspace handling.
+ *
+ * When set to %TRUE, pressing the Backspace key will try to delete spaces
+ * up to the previous tab stop.
+ *
+ * Since: 3.18
+ */
+void
+gtk_source_view_set_smart_backspace (GtkSourceView *view,
+ gboolean smart_backspace)
+{
+ g_return_if_fail (GTK_SOURCE_IS_VIEW (view));
+
+ smart_backspace = smart_backspace != FALSE;
+
+ if (smart_backspace != view->priv->smart_backspace)
+ {
+ view->priv->smart_backspace = smart_backspace;
+ g_object_notify (G_OBJECT (view), "smart-backspace");
+ }
+}
+
+/**
+ * gtk_source_view_get_smart_backspace:
+ * @view: a #GtkSourceView.
+ *
+ * Returns %TRUE if pressing the Backspace key will try to delete spaces
+ * up to the previous tab stop.
+ *
+ * Returns: %TRUE if smart Backspace handling is enabled.
+ *
+ * Since: 3.18
+ */
+gboolean
+gtk_source_view_get_smart_backspace (GtkSourceView *view)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_VIEW (view), FALSE);
+
+ return view->priv->smart_backspace;
+}
+
+/**
* gtk_source_view_set_smart_home_end:
* @view: a #GtkSourceView.
* @smart_home_end: the desired behavior among #GtkSourceSmartHomeEndType.
diff --git a/gtksourceview/gtksourceview.h b/gtksourceview/gtksourceview.h
index c89358e..2e2e9db 100644
--- a/gtksourceview/gtksourceview.h
+++ b/gtksourceview/gtksourceview.h
@@ -208,6 +208,11 @@ GtkSourceMarkAttributes *
const gchar *category,
gint *priority);
+void gtk_source_view_set_smart_backspace (GtkSourceView *view,
+ gboolean smart_backspace);
+
+gboolean gtk_source_view_get_smart_backspace (GtkSourceView *view);
+
void gtk_source_view_set_smart_home_end (GtkSourceView *view,
GtkSourceSmartHomeEndType smart_home_end);
diff --git a/tests/test-widget.c b/tests/test-widget.c
index e5a6f66..d399046 100644
--- a/tests/test-widget.c
+++ b/tests/test-widget.c
@@ -54,6 +54,7 @@ struct _TestWidgetPrivate
GtkSourceFile *file;
GtkSourceMap *map;
GtkCheckButton *show_map_checkbutton;
+ GtkCheckButton *smart_backspace_checkbutton;
GtkCheckButton *indent_width_checkbutton;
GtkSpinButton *indent_width_spinbutton;
GtkLabel *cursor_position_info;
@@ -984,6 +985,7 @@ test_widget_class_init (TestWidgetClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, view);
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, map);
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, show_map_checkbutton);
+ gtk_widget_class_bind_template_child_private (widget_class, TestWidget, smart_backspace_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, indent_width_checkbutton);
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, indent_width_spinbutton);
gtk_widget_class_bind_template_child_private (widget_class, TestWidget, cursor_position_info);
@@ -1047,6 +1049,12 @@ test_widget_init (TestWidget *self)
"visible",
G_BINDING_SYNC_CREATE);
+ g_object_bind_property (self->priv->smart_backspace_checkbutton,
+ "active",
+ self->priv->view,
+ "smart-backspace",
+ G_BINDING_SYNC_CREATE);
+
g_signal_connect (self->priv->background_pattern,
"changed",
G_CALLBACK (on_background_pattern_changed),
diff --git a/tests/test-widget.ui b/tests/test-widget.ui
index 82c4f40..1e26770 100644
--- a/tests/test-widget.ui
+++ b/tests/test-widget.ui
@@ -227,6 +227,19 @@
</packing>
</child>
<child>
+ <object class="GtkCheckButton" id="smart_backspace_checkbutton">
+ <property name="label">Smart Backspace</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">10</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkGrid" id="grid8">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -263,7 +276,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">10</property>
+ <property name="top_attach">11</property>
</packing>
</child>
<child>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]