[gtksourceview/wip/fix-move-lines: 3/3] move-lines: fix bug with trailing newline



commit 6efb71d34cf93ba8871f65204183150b1b72ecda
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Thu Mar 30 15:42:33 2017 +0200

    move-lines: fix bug with trailing newline
    
    https://bugzilla.gnome.org/show_bug.cgi?id=624963

 gtksourceview/gtksourceview.c |  153 ++++++++++++++++++++++++++---------------
 testsuite/test-view.c         |    8 +-
 2 files changed, 101 insertions(+), 60 deletions(-)
---
diff --git a/gtksourceview/gtksourceview.c b/gtksourceview/gtksourceview.c
index e4a3516..3040fde 100644
--- a/gtksourceview/gtksourceview.c
+++ b/gtksourceview/gtksourceview.c
@@ -3699,6 +3699,66 @@ gtk_source_view_move_words (GtkSourceView *view,
        g_free (new_text);
 }
 
+static gboolean
+buffer_contains_trailing_newline (GtkTextBuffer *buffer)
+{
+       GtkTextIter iter;
+       gunichar ch;
+
+       gtk_text_buffer_get_end_iter (buffer, &iter);
+       gtk_text_iter_backward_char (&iter);
+       ch = gtk_text_iter_get_char (&iter);
+
+       return (ch == '\n' || ch == '\r');
+}
+
+/* TODO could be a function of GtkSourceBuffer, it's also useful for the
+ * FileLoader.
+ */
+static void
+remove_trailing_newline (GtkTextBuffer *buffer)
+{
+       GtkTextIter start;
+       GtkTextIter end;
+
+       gtk_text_buffer_get_end_iter (buffer, &end);
+       start = end;
+
+       gtk_text_iter_set_line_offset (&start, 0);
+
+       if (gtk_text_iter_ends_line (&start) &&
+           gtk_text_iter_backward_line (&start))
+       {
+               if (!gtk_text_iter_ends_line (&start))
+               {
+                       gtk_text_iter_forward_to_line_end (&start);
+               }
+
+               gtk_text_buffer_delete (buffer, &start, &end);
+       }
+}
+
+static void
+get_move_lines_boundaries (GtkTextBuffer *buffer,
+                          GtkTextIter   *start,
+                          GtkTextIter   *end)
+{
+       g_assert (start != NULL);
+       g_assert (end != NULL);
+
+       gtk_text_buffer_get_selection_bounds (buffer, start, end);
+
+       /* Get the entire lines, including the paragraph terminator. */
+
+       gtk_text_iter_set_line_offset (start, 0);
+
+       if (!gtk_text_iter_starts_line (end) ||
+            gtk_text_iter_get_line (start) == gtk_text_iter_get_line (end))
+       {
+               gtk_text_iter_forward_line (end);
+       }
+}
+
 static void
 gtk_source_view_move_lines (GtkSourceView *view,
                            gboolean       copy,
@@ -3707,9 +3767,11 @@ gtk_source_view_move_lines (GtkSourceView *view,
        GtkTextBuffer *buffer;
        GtkTextIter start;
        GtkTextIter end;
+       GtkTextIter insert_pos;
        GtkTextMark *mark;
-       gboolean down;
        gchar *text;
+       gboolean initially_contains_trailing_newline;
+       gboolean down;
 
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
@@ -3722,47 +3784,35 @@ gtk_source_view_move_lines (GtkSourceView *view,
 
        down = step > 0;
 
-       gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
-
-       /* Get the entire lines, including the paragraph terminator. */
-       gtk_text_iter_set_line_offset (&start, 0);
-       if (!gtk_text_iter_starts_line (&end) ||
-            gtk_text_iter_get_line (&start) == gtk_text_iter_get_line (&end))
-       {
-               gtk_text_iter_forward_line (&end);
-       }
+       get_move_lines_boundaries (buffer, &start, &end);
 
        if ((!down && gtk_text_iter_is_start (&start)) ||
            (down && gtk_text_iter_is_end (&end)))
        {
+               /* Nothing must be done, and the undo/redo history must remain
+                * unchanged.
+                */
                return;
        }
 
-       text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
+       gtk_text_buffer_begin_user_action (buffer);
 
-       /* First special case) We are moving up the last line
-        * of the buffer, check if buffer ends with a paragraph
-        * delimiter otherwise append a \n ourselves.
-        */
-       if (gtk_text_iter_is_end (&end))
-       {
-               GtkTextIter iter;
-               iter = end;
+       initially_contains_trailing_newline = buffer_contains_trailing_newline (buffer);
 
-               gtk_text_iter_set_line_offset (&iter, 0);
-               if (!gtk_text_iter_ends_line (&iter) &&
-                   !gtk_text_iter_forward_to_line_end (&iter))
-               {
-                       gchar *tmp;
+       if (!initially_contains_trailing_newline)
+       {
+               /* Insert a trailing newline. */
+               gtk_text_buffer_get_end_iter (buffer, &end);
+               gtk_text_buffer_insert (buffer, &end, "\n", -1);
+       }
 
-                       tmp = g_strdup_printf ("%s\n", text);
+       /* At this point all lines finish with a newline or carriage return, so
+        * there are no special cases for the last line.
+        */
 
-                       g_free (text);
-                       text = tmp;
-               }
-       }
+       get_move_lines_boundaries (buffer, &start, &end);
 
-       gtk_text_buffer_begin_user_action (buffer);
+       text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
 
        if (!copy)
        {
@@ -3771,45 +3821,36 @@ gtk_source_view_move_lines (GtkSourceView *view,
 
        if (down)
        {
-               gtk_text_iter_forward_line (&end);
-
-               /* Second special case) We are moving down the last-but-one line
-                * of the buffer, check if buffer ends with a paragraph
-                * delimiter otherwise prepend a \n ourselves.
-                */
-               if (gtk_text_iter_is_end (&end))
-               {
-                       GtkTextIter iter;
-                       iter = end;
-
-                       gtk_text_iter_set_line_offset (&iter, 0);
-                       if (!gtk_text_iter_ends_line (&iter) &&
-                           !gtk_text_iter_forward_to_line_end (&iter))
-                       {
-                               gtk_text_buffer_insert (buffer, &end, "\n", -1);
-                       }
-               }
+               insert_pos = end;
+               gtk_text_iter_forward_line (&insert_pos);
        }
        else
        {
-               gtk_text_iter_backward_line (&end);
+               insert_pos = start;
+               gtk_text_iter_backward_line (&insert_pos);
        }
 
-       /* Use anon mark to be able to select after insertion. */
-       mark = gtk_text_buffer_create_mark (buffer, NULL, &end, TRUE);
-
-       gtk_text_buffer_insert (buffer, &end, text, -1);
-
-       gtk_text_buffer_end_user_action (buffer);
+       /* Left gravity mark */
+       mark = gtk_text_buffer_create_mark (buffer, NULL, &insert_pos, TRUE);
 
-       g_free (text);
+       gtk_text_buffer_insert (buffer, &insert_pos, text, -1);
 
        /* Select the moved text. */
        gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
+       end = insert_pos;
        gtk_text_buffer_select_range (buffer, &start, &end);
+
+       if (!initially_contains_trailing_newline)
+       {
+               remove_trailing_newline (buffer);
+       }
+
+       gtk_text_buffer_end_user_action (buffer);
+
        gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
                                            gtk_text_buffer_get_insert (buffer));
 
+       g_free (text);
        gtk_text_buffer_delete_mark (buffer, mark);
 }
 
diff --git a/testsuite/test-view.c b/testsuite/test-view.c
index 5906e55..34a199b 100644
--- a/testsuite/test-view.c
+++ b/testsuite/test-view.c
@@ -161,7 +161,7 @@ test_move_lines__move_single_line (void)
                g_assert_cmpstr (text, ==,
                                 "line1\n"
                                 "line3\n"
-                                "line2\n"); /* FIXME should be "line2" without the '\n'. */
+                                "line2");
                g_free (text);
 
                gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
@@ -209,7 +209,7 @@ test_move_lines__move_single_line (void)
                g_assert_cmpstr (text, ==,
                                 "line1\n"
                                 "line3\n"
-                                "line2\n"); /* FIXME should be "line2" without the '\n'. */
+                                "line2");
                g_free (text);
 
                gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
@@ -455,7 +455,7 @@ test_move_lines__move_several_lines (void)
                                 "line1\n"
                                 "line4\n"
                                 "line2\n"
-                                "line3\n"); /* FIXME should be "line3" without the '\n'. */
+                                "line3");
                g_free (text);
 
                gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
@@ -507,7 +507,7 @@ test_move_lines__move_several_lines (void)
                                 "line1\n"
                                 "line3\n"
                                 "line4\n"
-                                "line2\n"); /* FIXME should be "line2" without the '\n'. */
+                                "line2");
                g_free (text);
 
                gtk_text_buffer_get_selection_bounds (buffer, &start, &end);


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