[gnome-builder] source-view: tab to indent, shift-tab to unindent selection.
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] source-view: tab to indent, shift-tab to unindent selection.
- Date: Fri, 19 Sep 2014 21:09:26 +0000 (UTC)
commit 656efdb79dc10dadfdaa0b9b48d008d59499940f
Author: Christian Hergert <christian hergert me>
Date: Fri Sep 19 14:09:21 2014 -0700
source-view: tab to indent, shift-tab to unindent selection.
src/editor/gb-source-view.c | 215 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 215 insertions(+), 0 deletions(-)
---
diff --git a/src/editor/gb-source-view.c b/src/editor/gb-source-view.c
index fa56a89..24299eb 100644
--- a/src/editor/gb-source-view.c
+++ b/src/editor/gb-source-view.c
@@ -167,6 +167,198 @@ gb_source_view_set_show_shadow (GbSourceView *view,
}
static void
+gb_source_view_indent_selection (GbSourceView *view)
+{
+ GbSourceViewPrivate *priv;
+ GtkTextIter begin;
+ GtkTextIter end;
+ GtkTextIter iter;
+ GtkTextMark *mark_begin;
+ GtkTextMark *mark_end;
+ gboolean use_spaces = FALSE;
+ guint tab_width = 0;
+
+ ENTRY;
+
+ g_return_if_fail (GB_IS_SOURCE_VIEW (view));
+
+ priv = view->priv;
+
+ g_object_get (view,
+ "insert-spaces-instead-of-tabs", &use_spaces,
+ "tab-width", &tab_width,
+ NULL);
+
+ if (!gtk_text_buffer_get_has_selection (priv->buffer))
+ return;
+
+ gtk_text_buffer_get_selection_bounds (priv->buffer, &begin, &end);
+
+ /*
+ * Expand the iters to the beginning of the first line and the
+ * end of the last line.
+ */
+ while (!gtk_text_iter_starts_line (&begin))
+ gtk_text_iter_backward_char (&begin);
+ while (!gtk_text_iter_ends_line (&end))
+ gtk_text_iter_forward_char (&end);
+
+ /*
+ * Set marks so we can track our end position after every edit.
+ * Also allows us to reselect the whole range at the end.
+ */
+ mark_begin = gtk_text_buffer_create_mark (priv->buffer,
+ "tab-selection-begin",
+ &begin, TRUE);
+ mark_end = gtk_text_buffer_create_mark (priv->buffer,
+ "tab-selection-end",
+ &end, FALSE);
+ gtk_text_iter_assign (&iter, &begin);
+
+ /*
+ * Walk through each selected line, adding a tab or the proper number of
+ * spaces at the beginning of each line.
+ */
+ gtk_text_buffer_begin_user_action (priv->buffer);
+ do
+ {
+ if (use_spaces)
+ {
+ guint i;
+
+ for (i = 0; i < tab_width; i++)
+ gtk_text_buffer_insert (priv->buffer, &iter, " ", 1);
+ }
+ else
+ gtk_text_buffer_insert (priv->buffer, &iter, "\t", 1);
+
+ if (!gtk_text_iter_forward_line (&iter))
+ break;
+
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &end, mark_end);
+ }
+ while (gtk_text_iter_compare (&iter, &end) < 0);
+ gtk_text_buffer_end_user_action (priv->buffer);
+
+ /*
+ * Reselect our expanded range.
+ */
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &begin, mark_begin);
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &end, mark_end);
+ gtk_text_buffer_select_range (priv->buffer, &begin, &end);
+
+ /*
+ * Remove our temporary marks.
+ */
+ gtk_text_buffer_delete_mark (priv->buffer, mark_begin);
+ gtk_text_buffer_delete_mark (priv->buffer, mark_end);
+
+ EXIT;
+}
+
+static void
+gb_source_view_unindent_selection (GbSourceView *view)
+{
+ GbSourceViewPrivate *priv;
+ GtkTextIter begin;
+ GtkTextIter end;
+ GtkTextIter iter;
+ GtkTextMark *mark_begin;
+ GtkTextMark *mark_end;
+ gboolean use_spaces = FALSE;
+ guint tab_width = 0;
+
+ ENTRY;
+
+ g_return_if_fail (GB_IS_SOURCE_VIEW (view));
+
+ priv = view->priv;
+
+ g_object_get (view,
+ "insert-spaces-instead-of-tabs", &use_spaces,
+ "tab-width", &tab_width,
+ NULL);
+
+ if (!gtk_text_buffer_get_has_selection (priv->buffer))
+ return;
+
+ gtk_text_buffer_get_selection_bounds (priv->buffer, &begin, &end);
+
+ /*
+ * Expand the iters to the beginning of the first line and the
+ * end of the last line.
+ */
+ while (!gtk_text_iter_starts_line (&begin))
+ gtk_text_iter_backward_char (&begin);
+ while (!gtk_text_iter_ends_line (&end))
+ gtk_text_iter_forward_char (&end);
+
+ /*
+ * Set marks so we can track our end position after every edit.
+ * Also allows us to reselect the whole range at the end.
+ */
+ mark_begin = gtk_text_buffer_create_mark (priv->buffer,
+ "tab-selection-begin",
+ &begin, TRUE);
+ mark_end = gtk_text_buffer_create_mark (priv->buffer,
+ "tab-selection-end",
+ &end, FALSE);
+ gtk_text_iter_assign (&iter, &begin);
+
+ /*
+ * Walk through each selected line, removing up to `tab_width`
+ * spaces from the beginning of the line, or a single tab.
+ */
+ gtk_text_buffer_begin_user_action (priv->buffer);
+ do
+ {
+ GtkTextIter next;
+ gboolean found_tab = FALSE;
+ guint n_spaces = 0;
+ gunichar ch;
+
+ while (!found_tab && (n_spaces < tab_width))
+ {
+ ch = gtk_text_iter_get_char (&iter);
+
+ if ((ch == '\t') || (ch == ' '))
+ {
+ gtk_text_iter_assign (&next, &iter);
+ gtk_text_iter_forward_char (&next);
+ gtk_text_buffer_delete (priv->buffer, &iter, &next);
+
+ found_tab = (ch == '\t');
+ n_spaces += (ch == ' ');
+ }
+ else
+ break;
+ }
+
+ if (!gtk_text_iter_forward_line (&iter))
+ break;
+
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &end, mark_end);
+ }
+ while (gtk_text_iter_compare (&iter, &end) < 0);
+ gtk_text_buffer_end_user_action (priv->buffer);
+
+ /*
+ * Reselect our expanded range.
+ */
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &begin, mark_begin);
+ gtk_text_buffer_get_iter_at_mark (priv->buffer, &end, mark_end);
+ gtk_text_buffer_select_range (priv->buffer, &begin, &end);
+
+ /*
+ * Remove our temporary marks.
+ */
+ gtk_text_buffer_delete_mark (priv->buffer, mark_begin);
+ gtk_text_buffer_delete_mark (priv->buffer, mark_end);
+
+ EXIT;
+}
+
+static void
get_rect_for_iters (GtkTextView *text_view,
const GtkTextIter *iter1,
const GtkTextIter *iter2,
@@ -731,6 +923,7 @@ gb_source_view_key_press_event (GtkWidget *widget,
gb_source_view_unblock_handlers (view);
return TRUE;
+ case GDK_KEY_KP_Tab:
case GDK_KEY_Tab:
gb_source_view_block_handlers (view);
if (!gb_source_snippet_move_next (snippet))
@@ -751,6 +944,28 @@ gb_source_view_key_press_event (GtkWidget *widget,
}
}
+ /*
+ * If we come across tab or shift tab (left tab) while we have a selection,
+ * try to (un)indent the selected lines.
+ */
+ if (gtk_text_buffer_get_has_selection (priv->buffer))
+ {
+ switch ((gint) event->keyval)
+ {
+ case GDK_KEY_KP_Tab:
+ case GDK_KEY_Tab:
+ gb_source_view_indent_selection (view);
+ return TRUE;
+
+ case GDK_KEY_ISO_Left_Tab:
+ gb_source_view_unindent_selection (view);
+ return TRUE;
+
+ default:
+ break;
+ }
+ }
+
if (priv->auto_indenter &&
gb_source_auto_indenter_is_trigger (priv->auto_indenter, event))
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]