From fa82066ceed07588771a3dbe22202b9e95ecb56b Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 12 Nov 2025 22:42:47 +0100 Subject: [PATCH] pr: fix header formatting for custom date formats starting with '+' Should fix tests/misc/time-style.sh --- src/uu/pr/src/pr.rs | 70 +++++++++++++++++++++++++++++++--------- tests/by-util/test_pr.rs | 43 ++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/uu/pr/src/pr.rs b/src/uu/pr/src/pr.rs index f21f69732..f5c5662aa 100644 --- a/src/uu/pr/src/pr.rs +++ b/src/uu/pr/src/pr.rs @@ -1150,23 +1150,61 @@ fn get_formatted_line_number(opts: &OutputOptions, line_number: usize, index: us /// Returns a five line header content if displaying header is not disabled by /// using `NO_HEADER_TRAILER_OPTION` option. fn header_content(options: &OutputOptions, page: usize) -> Vec { - if options.display_header_and_trailer { - let first_line = format!( - "{} {} {} {page}", - options.last_modified_time, - options.header, - translate!("pr-page") - ); - vec![ - String::new(), - String::new(), - first_line, - String::new(), - String::new(), - ] - } else { - Vec::new() + if !options.display_header_and_trailer { + return Vec::new(); } + + // The header should be formatted with proper spacing: + // - Date/time on the left + // - Filename centered + // - "Page X" on the right + let date_part = &options.last_modified_time; + let filename = &options.header; + let page_part = format!("{} {page}", translate!("pr-page")); + + // Use the line width if available, otherwise use default of 72 + let total_width = options.line_width.unwrap_or(DEFAULT_COLUMN_WIDTH); + + // GNU pr uses a specific layout: + // Date takes up the left part, filename is centered, page is right-aligned + let date_len = date_part.chars().count(); + let filename_len = filename.chars().count(); + let page_len = page_part.chars().count(); + + let header_line = if date_len + filename_len + page_len + 2 < total_width { + // Check if we're using a custom date format that needs centered alignment + // This preserves backward compatibility while fixing the GNU time-style test + if date_part.starts_with('+') { + // GNU pr uses centered layout for headers with custom date formats + // The filename should be centered between the date and page parts + let space_for_filename = total_width - date_len - page_len; + let padding_before_filename = (space_for_filename - filename_len) / 2; + let padding_after_filename = + space_for_filename - filename_len - padding_before_filename; + + format!( + "{date_part}{:width1$}{filename}{:width2$}{page_part}", + "", + "", + width1 = padding_before_filename, + width2 = padding_after_filename + ) + } else { + // For standard date formats, use simple spacing for backward compatibility + format!("{date_part} {filename} {page_part}") + } + } else { + // If content is too long, just use single spaces + format!("{date_part} {filename} {page_part}") + }; + + vec![ + String::new(), + String::new(), + header_line, + String::new(), + String::new(), + ] } /// Returns five empty lines as trailer content if displaying trailer diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 0d1c4bc4b..1fa91dab2 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -558,6 +558,49 @@ fn test_value_for_number_lines() { new_ucmd!().args(&["-n", "foo5.txt", "test.log"]).fails(); } +#[test] +fn test_header_formatting_with_custom_date_format() { + // This test verifies that the header is properly formatted with: + // - Date/time on the left + // - Filename centered + // - "Page X" on the right + // This matches GNU pr behavior for the time-style test + + let test_file_path = "test_one_page.log"; + + // Set a specific date format like in the GNU test + let output = new_ucmd!() + .args(&["-D", "+%Y-%m-%d %H:%M:%S %z (%Z)", test_file_path]) + .succeeds() + .stdout_move_str(); + + // Extract the header line (3rd line of output) + let lines: Vec<&str> = output.lines().collect(); + assert!( + lines.len() >= 5, + "Output should have at least 5 lines for header" + ); + + let header_line = lines[2]; + + // The header should be 72 characters wide (default page width) + assert_eq!(header_line.chars().count(), 72); + + // Check that it contains the expected parts + assert!(header_line.contains(test_file_path)); + assert!(header_line.contains("Page 1")); + + // Verify the filename is roughly centered + let filename_pos = header_line.find(test_file_path).unwrap(); + let page_pos = header_line.find("Page 1").unwrap(); + + // Filename should be somewhere in the middle third of the line + assert!(filename_pos > 24 && filename_pos < 48); + + // Page should be right-aligned (near the end) + assert!(page_pos >= 60); +} + #[test] fn test_help() { new_ucmd!().arg("--help").succeeds();