From 835dd856c03aba20ec42666f6c22285a67fbf8be Mon Sep 17 00:00:00 2001 From: LoukasPap Date: Fri, 30 Jan 2026 17:34:10 +0200 Subject: [PATCH 1/2] Fix newlines in x, g, G commands with empty hold space. - If hold space is empty, `x` and `g` replace the pattern with a newline and `G` first appends and then replaces with a newline. --- src/sed/processor.rs | 13 +++++++++++-- tests/by-util/test_sed.rs | 5 ++++- .../sed/output/pattern_replace_append_empty_hold | 16 ++++++++++++++++ .../sed/output/pattern_replace_empty_hold | 14 ++++++++++++++ .../fixtures/sed/output/pattern_swap_empty_hold | 14 ++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/sed/output/pattern_replace_append_empty_hold create mode 100644 tests/fixtures/sed/output/pattern_replace_empty_hold create mode 100644 tests/fixtures/sed/output/pattern_swap_empty_hold diff --git a/src/sed/processor.rs b/src/sed/processor.rs index 070c815..60e6829 100644 --- a/src/sed/processor.rs +++ b/src/sed/processor.rs @@ -520,14 +520,17 @@ fn process_file( } 'g' => { // Replace pattern with the contents of the hold space. - pattern.set_to_string(context.hold.content.clone(), context.hold.has_newline); + pattern.set_to_string( + context.hold.content.clone(), + context.hold.has_newline || context.hold.content.is_empty(), + ); } 'G' => { // Append to pattern \n followed by hold space contents. let (pat_content, pat_has_newline) = pattern.fields_mut()?; pat_content.push('\n'); pat_content.push_str(&context.hold.content); - *pat_has_newline = context.hold.has_newline; + *pat_has_newline = context.hold.has_newline || context.hold.content.is_empty(); } 'h' => { // Replace hold with the contents of the pattern space. @@ -637,6 +640,12 @@ fn process_file( std::mem::swap(pat_has_newline, &mut context.hold.has_newline); } std::mem::swap(pat_content, &mut context.hold.content); + std::mem::swap(pat_has_newline, &mut context.hold.has_newline); + // If the hold space was empty (thus the pat_content is now empty), + // ensure the new pattern space is printed with a newline + if pat_content.is_empty() { + *pat_has_newline = true; + } } 'y' => { let trans = extract_variant!(command, Transliteration); diff --git a/tests/by-util/test_sed.rs b/tests/by-util/test_sed.rs index 0d43957..9438310 100644 --- a/tests/by-util/test_sed.rs +++ b/tests/by-util/test_sed.rs @@ -352,7 +352,7 @@ check_output!(trans_no_new_line, ["-e", r"y/l/L/", NO_NEW_LINE]); check_output!(trans_newline, ["-e", r"1N;2y/\n/X/", LINES1]); //////////////////////////////////////////////////////////// -// Pattern space manipulation: D, d, H, h, N, n, P, p, q, x +// Pattern space manipulation: D, d, H, h, N, n, P, p, q, x, g, G check_output!(pattern_print_to_newline, ["-n", r"1{;N;P;P;p;}", LINES1]); check_output!(pattern_next_print, ["-n", r"N;N;P", LINES1]); check_output!(pattern_delete_to_newline, ["-n", r"2N;3p;3D;3p", LINES1]); @@ -371,6 +371,9 @@ check_output!( pattern_hold_append_swap, ["-e", r"2h;3H;4g;5G;6x;6p;6x;6p", LINES1] ); +check_output!(pattern_swap_empty_hold, ["-e", r"4x", LINES1]); +check_output!(pattern_replace_empty_hold, ["-e", r"4g;5g", LINES1]); +check_output!(pattern_replace_append_empty_hold, ["-e", r"4G;5G", LINES1]); check_output!(pattern_next_output, ["-e", r"4n", LINES1]); check_output!(pattern_next_no_output, ["-n", "-e", r"4n", LINES1]); check_output!(pattern_next_print_output, ["-e", r"4n;p", LINES1]); diff --git a/tests/fixtures/sed/output/pattern_replace_append_empty_hold b/tests/fixtures/sed/output/pattern_replace_append_empty_hold new file mode 100644 index 0000000..5bdb8a6 --- /dev/null +++ b/tests/fixtures/sed/output/pattern_replace_append_empty_hold @@ -0,0 +1,16 @@ +l1_1 +l1_2 +l1_3 +l1_4 + +l1_5 + +l1_6 +l1_7 +l1_8 +l1_9 +l1_10 +l1_11 +l1_12 +l1_13 +l1_14 diff --git a/tests/fixtures/sed/output/pattern_replace_empty_hold b/tests/fixtures/sed/output/pattern_replace_empty_hold new file mode 100644 index 0000000..20604bf --- /dev/null +++ b/tests/fixtures/sed/output/pattern_replace_empty_hold @@ -0,0 +1,14 @@ +l1_1 +l1_2 +l1_3 + + +l1_6 +l1_7 +l1_8 +l1_9 +l1_10 +l1_11 +l1_12 +l1_13 +l1_14 diff --git a/tests/fixtures/sed/output/pattern_swap_empty_hold b/tests/fixtures/sed/output/pattern_swap_empty_hold new file mode 100644 index 0000000..b855951 --- /dev/null +++ b/tests/fixtures/sed/output/pattern_swap_empty_hold @@ -0,0 +1,14 @@ +l1_1 +l1_2 +l1_3 + +l1_5 +l1_6 +l1_7 +l1_8 +l1_9 +l1_10 +l1_11 +l1_12 +l1_13 +l1_14 From c212acd662d2c6c5ceebd288c487b5c47374fb6d Mon Sep 17 00:00:00 2001 From: LoukasPap Date: Wed, 4 Feb 2026 15:24:34 +0200 Subject: [PATCH 2/2] Fix problem with --separate flag --- src/sed/processor.rs | 7 +++++- tests/by-util/test_sed.rs | 5 ++++ .../fixtures/sed/output/pattern_swap_separate | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/sed/output/pattern_swap_separate diff --git a/src/sed/processor.rs b/src/sed/processor.rs index 60e6829..144fe72 100644 --- a/src/sed/processor.rs +++ b/src/sed/processor.rs @@ -724,9 +724,14 @@ pub fn process_all_files( .map_err_context(|| format!("error opening input file {}", path.quote()))?; let output = in_place.begin(path)?; - if index == 0 || context.separate { + if context.separate || index == 0 { context.line_number = 0; reset_latched_address_ranges(&mut context.range_commands); + + // Reset hold space for separate file processing + // (doesn't affect results if --separate is not used) + context.hold.content.clear(); + context.hold.has_newline = false; } context.input_name = path.quote().to_string(); diff --git a/tests/by-util/test_sed.rs b/tests/by-util/test_sed.rs index 9438310..b3b33eb 100644 --- a/tests/by-util/test_sed.rs +++ b/tests/by-util/test_sed.rs @@ -374,6 +374,11 @@ check_output!( check_output!(pattern_swap_empty_hold, ["-e", r"4x", LINES1]); check_output!(pattern_replace_empty_hold, ["-e", r"4g;5g", LINES1]); check_output!(pattern_replace_append_empty_hold, ["-e", r"4G;5G", LINES1]); +check_output!( + pattern_swap_separate, + ["--separate", r"4x;6x", LINES1, LINES2] +); + check_output!(pattern_next_output, ["-e", r"4n", LINES1]); check_output!(pattern_next_no_output, ["-n", "-e", r"4n", LINES1]); check_output!(pattern_next_print_output, ["-e", r"4n;p", LINES1]); diff --git a/tests/fixtures/sed/output/pattern_swap_separate b/tests/fixtures/sed/output/pattern_swap_separate new file mode 100644 index 0000000..5de4c38 --- /dev/null +++ b/tests/fixtures/sed/output/pattern_swap_separate @@ -0,0 +1,23 @@ +l1_1 +l1_2 +l1_3 + +l1_5 +l1_4 +l1_7 +l1_8 +l1_9 +l1_10 +l1_11 +l1_12 +l1_13 +l1_14 +l2_1 +l2_2 +l2_3 + +l2_5 +l2_4 +l2_7 +l2_8 +l2_9