Skip to content

Commit 4b11638

Browse files
committed
fix(ptx): Align text wrapping behavior with GNU in traditional mode and add related test
In traditional mode (-G) with references enabled, `uutils/ptx` failed to wrap long lines in the same way as the GNU `ptx` reference implementation. This was due to the layout algorithm operating on an incorrectly large line width, as the space for the reference column was not being subtracted from the total width budget. This commit implements the correct line width adjustment by subtracting the reference width. This aligns the wrapping behavior and makes the output identical to GNU `ptx` for the tested cases.
1 parent 788bf92 commit 4b11638

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

src/uu/ptx/src/ptx.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ fn get_config(matches: &clap::ArgMatches) -> UResult<Config> {
224224
}
225225
config.auto_ref = matches.get_flag(options::AUTO_REFERENCE);
226226
config.input_ref = matches.get_flag(options::REFERENCES);
227-
config.right_ref &= matches.get_flag(options::RIGHT_SIDE_REFS);
227+
config.right_ref = matches.get_flag(options::RIGHT_SIDE_REFS);
228228
config.ignore_case = matches.get_flag(options::IGNORE_CASE);
229229
if matches.contains_id(options::MACRO_NAME) {
230230
config.macro_name = matches
@@ -661,7 +661,7 @@ fn prepare_line_chunks(
661661
}
662662

663663
fn write_traditional_output(
664-
config: &Config,
664+
config: &mut Config,
665665
file_map: &FileMap,
666666
words: &BTreeSet<WordRef>,
667667
output_filename: &OsStr,
@@ -677,6 +677,15 @@ fn write_traditional_output(
677677

678678
let context_reg = Regex::new(&config.context_regex).unwrap();
679679

680+
if !config.right_ref {
681+
let max_ref_len = if config.auto_ref {
682+
get_auto_max_reference_len(words)
683+
} else {
684+
0
685+
};
686+
config.line_width -= max_ref_len;
687+
}
688+
680689
for word_ref in words {
681690
let file_map_value: &FileContent = file_map
682691
.get(&word_ref.filename)
@@ -722,6 +731,31 @@ fn write_traditional_output(
722731
Ok(())
723732
}
724733

734+
fn get_auto_max_reference_len(words: &BTreeSet<WordRef>) -> usize {
735+
//Get the maximum length of the reference field
736+
let line_num = words
737+
.iter()
738+
.map(|w| {
739+
if w.local_line_nr == 0 {
740+
1
741+
} else {
742+
(w.local_line_nr as f64).log10() as usize + 1
743+
}
744+
})
745+
.max()
746+
.unwrap_or(0);
747+
748+
let filename_len = words
749+
.iter()
750+
.filter(|w| w.filename != "-")
751+
.map(|w| w.filename.maybe_quote().to_string().len())
752+
.max()
753+
.unwrap_or(0);
754+
755+
// +1 for the colon
756+
line_num + filename_len + 1
757+
}
758+
725759
mod options {
726760
pub mod format {
727761
pub static ROFF: &str = "roff";
@@ -749,7 +783,7 @@ mod options {
749783
#[uucore::main]
750784
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
751785
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
752-
let config = get_config(&matches)?;
786+
let mut config = get_config(&matches)?;
753787

754788
let input_files;
755789
let output_file: OsString;
@@ -783,7 +817,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
783817
let word_filter = WordFilter::new(&matches, &config)?;
784818
let file_map = read_input(&input_files).map_err_context(String::new)?;
785819
let word_set = create_word_set(&config, &word_filter, &file_map);
786-
write_traditional_output(&config, &file_map, &word_set, &output_file)
820+
write_traditional_output(&mut config, &file_map, &word_set, &output_file)
787821
}
788822

789823
pub fn uu_app() -> Command {

tests/by-util/test_ptx.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,30 @@ fn test_truncation_no_extra_space_in_after() {
5757
.stdout_contains(".xx \"\" \"Rust\" \"is/\" \"\"");
5858
}
5959

60+
#[test]
61+
fn gnu_ext_disabled_reference_calculation() {
62+
let input = "Hello World Rust is good language";
63+
let expected_output = concat!(
64+
r#".xx "language" "" "Hello World Rust is good" "" ":1""#,
65+
"\n",
66+
r#".xx "" "Hello World" "Rust is good language" "" ":1""#,
67+
"\n",
68+
r#".xx "" "Hello" "World Rust is good language" "" ":1""#,
69+
"\n",
70+
r#".xx "" "Hello World Rust is" "good language" "" ":1""#,
71+
"\n",
72+
r#".xx "" "Hello World Rust" "is good language" "" ":1""#,
73+
"\n",
74+
r#".xx "" "Hello World Rust is good" "language" "" ":1""#,
75+
"\n",
76+
);
77+
new_ucmd!()
78+
.args(&["-G", "-A"])
79+
.pipe_in(input)
80+
.succeeds()
81+
.stdout_only(expected_output);
82+
}
83+
6084
#[test]
6185
fn gnu_ext_disabled_rightward_no_ref() {
6286
new_ucmd!()

0 commit comments

Comments
 (0)