[meld] filediff: Fix chunk deletion for CRLF endings (bgo#778856)



commit 83022aeb170aff16acf503bbcb1438581638a5b8
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Feb 19 09:04:22 2017 +1000

    filediff: Fix chunk deletion for CRLF endings (bgo#778856)
    
    The problem here was that we were always only going backwards by a
    single character for the last line in a file, even when file endings
    were CRLF. The line ending behaviour here is weird, because of how
    Gtk.TextBuffer handles the last line in a file, but it appears to be
    correct.
    
    Also added a test for this case.

 meld/filediff.py           |    5 ++++
 test/test_chunk_actions.py |   57 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 0 deletions(-)
---
diff --git a/meld/filediff.py b/meld/filediff.py
index ff0ab46..8b05609 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -1816,7 +1816,12 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         b0 = self.textbuffer[src]
         it = b0.get_iter_at_line_or_eof(chunk[1])
         if chunk[2] >= b0.get_line_count():
+            # If this is the end of the buffer, we need to remove the
+            # previous newline, because the current line has none.
             it.backward_char()
+            newline_type = b0.data.sourcefile.get_newline_type()
+            if newline_type == GtkSource.NewlineType.CR_LF:
+                it.backward_char()
         b0.delete(it, b0.get_iter_at_line_or_eof(chunk[2]))
         mark0 = b0.create_mark(None, it, True)
         mark1 = b0.create_mark(None, it, True)
diff --git a/test/test_chunk_actions.py b/test/test_chunk_actions.py
new file mode 100644
index 0000000..b233303
--- /dev/null
+++ b/test/test_chunk_actions.py
@@ -0,0 +1,57 @@
+
+from unittest import mock
+
+import pytest
+from gi.repository import GtkSource
+
+import meld.meldbuffer
+from meld.filediff import FileDiff
+from meld.matchers.myers import DiffChunk
+
+
+@pytest.mark.parametrize("text, newline, expected_text", [
+    # For the following tests, newlines and text match
+    # Basic CRLF tests
+    ("ree\r\neee", GtkSource.NewlineType.CR_LF, 'ree'),
+    ("ree\r\neee\r\n", GtkSource.NewlineType.CR_LF, 'ree\r\neee'),
+    # Basic CR tests
+    ("ree\neee", GtkSource.NewlineType.CR, 'ree'),
+    ("ree\neee\n", GtkSource.NewlineType.CR, 'ree\neee'),
+    # Basic LF tests
+    ("ree\reee", GtkSource.NewlineType.LF, 'ree'),
+    ("ree\reee\r", GtkSource.NewlineType.LF, 'ree\reee'),
+
+    # This case is intentionally incorrect; the newline information is
+    # wrong for the text, and the result is also incorrect.
+    ("ree\r\neee", GtkSource.NewlineType.CR, 'ree\r'),
+])
+def test_delete_last_line_crlf(text, newline, expected_text):
+    filediff = mock.Mock(FileDiff)
+
+    with mock.patch.multiple(
+            'meld.meldbuffer',
+            bind_settings=mock.DEFAULT, meldsettings=mock.DEFAULT):
+        with mock.patch('meld.meldbuffer.MeldBuffer.set_style_scheme'):
+            meldbuffer = meld.meldbuffer.MeldBuffer()
+            meldbuffer.set_text(text)
+
+    def make_last_line_chunk(buf):
+        end = buf.get_line_count()
+        last = end - 1
+        return DiffChunk('delete', last, end, last, end)
+
+    start, end = meldbuffer.get_bounds()
+    buf_text = meldbuffer.get_text(start, end, False)
+    print(repr(buf_text))
+
+    with mock.patch.object(
+            meldbuffer.data.sourcefile,
+            'get_newline_type', return_value=newline):
+        filediff.textbuffer = [meldbuffer]
+        filediff.textview = [mock.Mock()]
+        FileDiff.delete_chunk(filediff, 0, make_last_line_chunk(meldbuffer))
+
+    start, end = meldbuffer.get_bounds()
+    buf_text = meldbuffer.get_text(start, end, False)
+    print(repr(buf_text))
+    assert buf_text == expected_text


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