From b5362919895823f64c3866f1f6c823d3ddce0eda Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 27 Mar 2020 20:32:43 -0700 Subject: [PATCH] Fix replacing with embedded newline characters Resolves #39 --- babi/file.py | 25 ++++++++++++++++++++++--- tests/features/replace_test.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/babi/file.py b/babi/file.py index 5e0fecc..d46b230 100644 --- a/babi/file.py +++ b/babi/file.py @@ -464,9 +464,28 @@ class File: with self.edit_action_context('replace', final=True): replaced = match.expand(replace) line = screen.file.lines[line_y] - line = line[:match.start()] + replaced + line[match.end():] - screen.file.lines[line_y] = line - search.offset = len(replaced) + if '\n' in replaced: + replaced_lines = replaced.split('\n') + self.lines[line_y] = ( + f'{line[:match.start()]}{replaced_lines[0]}' + ) + for i, ins_line in enumerate(replaced_lines[1:-1], 1): + self.lines.insert(line_y + i, ins_line) + last_insert = line_y + len(replaced_lines) - 1 + self.lines.insert( + last_insert, + f'{replaced_lines[-1]}{line[match.end():]}', + ) + self.y = last_insert + self.x = self.x_hint = 0 + search.offset = len(replaced_lines[-1]) + else: + self.lines[line_y] = ( + f'{line[:match.start()]}' + f'{replaced}' + f'{line[match.end():]}' + ) + search.offset = len(replaced) elif res == 'n': search.offset = 1 else: diff --git a/tests/features/replace_test.py b/tests/features/replace_test.py index 36a209e..6120bba 100644 --- a/tests/features/replace_test.py +++ b/tests/features/replace_test.py @@ -272,3 +272,31 @@ def test_replace_separate_line_after_wrapping(run, ten_lines): h.await_text_missing('line_0') h.press('y') h.await_text_missing('line_1') + + +def test_replace_with_newline_characters(run, ten_lines): + with run(str(ten_lines)) as h, and_exit(h): + h.press('^\\') + h.await_text('search (to replace):') + h.press_and_enter('(line)_([01])') + h.await_text('replace with:') + h.press_and_enter(r'\1\n\2') + h.await_text('replace [yes, no, all]?') + h.press('a') + h.await_text_missing('line_0') + h.await_text_missing('line_1') + h.await_text('line\n0\nline\n1\n') + + +def test_replace_with_multiple_newline_characters(run, ten_lines): + with run(str(ten_lines)) as h, and_exit(h): + h.press('^\\') + h.await_text('search (to replace):') + h.press_and_enter('(li)(ne)_(1)') + h.await_text('replace with:') + h.press_and_enter(r'\1\n\2\n\3\n') + h.await_text('replace [yes, no, all]?') + h.press('a') + + h.await_text_missing('line_1') + h.await_text('li\nne\n1\n\nline_2')