From 005ac6b6ef889ae87813fae6fdfdc2996ba1809b Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 10:08:26 +0100 Subject: [PATCH 01/26] Change queue from `Vec` to `VecDeque` This is to enable pushing lines to the front of the queue while preserving other pending lines. --- src/format.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/format.rs b/src/format.rs index 03fb6c8..c4ed468 100644 --- a/src/format.rs +++ b/src/format.rs @@ -12,6 +12,7 @@ use crate::wrap::*; use crate::write::*; use crate::LINE_END; use log::Level::{Info, Warn}; +use std::collections::VecDeque; use std::iter::zip; /// Central function to format a file @@ -29,7 +30,7 @@ pub fn format_file( // Initialise let mut state = State::new(); - let mut queue: Vec<(usize, String)> = vec![]; + let mut queue: VecDeque<(usize, String)> = vec![].into(); let mut new_text = String::with_capacity(2 * old_text.len()); // Select the character used for indentation. @@ -39,7 +40,7 @@ pub fn format_file( }; loop { - if let Some((linum_old, mut line)) = queue.pop() { + if let Some((linum_old, mut line)) = queue.pop_front() { // Read the patterns present on this line. let pattern = Pattern::new(&line); @@ -63,8 +64,8 @@ pub fn format_file( // Split the line into two ... let (this_line, next_line) = split_line(&line, &temp_state, file, args, logs); - // ... and queue the second part for formatting. - queue.push((linum_old, next_line.to_string())); + // ... and add the second part to the front of the queue for formatting. + queue.push_front((linum_old, next_line.to_string())); line = this_line.to_string(); } @@ -98,11 +99,11 @@ pub fn format_file( if let Some([this_line, next_line_start, next_line]) = wrapped_lines { - queue.push(( + queue.push_front(( linum_old, [next_line_start, next_line].concat(), )); - queue.push((linum_old, this_line.to_string())); + queue.push_front((linum_old, this_line.to_string())); continue; } } @@ -117,7 +118,7 @@ pub fn format_file( new_text.push_str(LINE_END); state.linum_new += 1; } else if let Some((linum_old, line)) = old_lines.next() { - queue.push((linum_old, line.to_string())); + queue.push_back((linum_old, line.to_string())); } else { break; } From ac22dfd4638912adae47ea291db1600f26fa6919 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 10:32:08 +0100 Subject: [PATCH 02/26] Add label to main formatting loop --- src/format.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/format.rs b/src/format.rs index c4ed468..01e3f07 100644 --- a/src/format.rs +++ b/src/format.rs @@ -39,7 +39,7 @@ pub fn format_file( TabChar::Space => " ", }; - loop { + 'main: loop { if let Some((linum_old, mut line)) = queue.pop_front() { // Read the patterns present on this line. let pattern = Pattern::new(&line); @@ -104,7 +104,7 @@ pub fn format_file( [next_line_start, next_line].concat(), )); queue.push_front((linum_old, this_line.to_string())); - continue; + continue 'main; } } @@ -120,7 +120,7 @@ pub fn format_file( } else if let Some((linum_old, line)) = old_lines.next() { queue.push_back((linum_old, line.to_string())); } else { - break; + break 'main; } } From 47baf12d89df4e73be78a292e056fdcfb99f7f68 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 10:47:42 +0100 Subject: [PATCH 03/26] Increase the formatting queue to always have at least 2 lines This will enable the re-wrapping code to access the next line of text to check if there are available words for re-wrapping. --- src/format.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/format.rs b/src/format.rs index 01e3f07..84b266b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -15,6 +15,11 @@ use log::Level::{Info, Warn}; use std::collections::VecDeque; use std::iter::zip; +/// The default number of lines to have in the formatting queue. +/// +/// Two lines are required for re-wrapping so that the line following the current one can always be accessed. +const DEFAULT_QUEUE_LENGTH: usize = 2; + /// Central function to format a file pub fn format_file( old_text: &str, @@ -40,6 +45,13 @@ pub fn format_file( }; 'main: loop { + // Add more lines to the queue if there aren't two + for _ in 0..DEFAULT_QUEUE_LENGTH.saturating_sub(queue.len()) { + if let Some((linum_old, line)) = old_lines.next() { + queue.push_back((linum_old, line.to_string())); + } + } + if let Some((linum_old, mut line)) = queue.pop_front() { // Read the patterns present on this line. let pattern = Pattern::new(&line); @@ -117,9 +129,9 @@ pub fn format_file( new_text.push_str(&line); new_text.push_str(LINE_END); state.linum_new += 1; - } else if let Some((linum_old, line)) = old_lines.next() { - queue.push_back((linum_old, line.to_string())); } else { + // If there are not lines in `queue`, then `old_lines` has been entirely consumed and it's safe to break the + // main loop. break 'main; } } From bf1ab973cf8ecad924eb86969ddf872af910c915 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 13:09:40 +0100 Subject: [PATCH 04/26] Save all potential wrap points in a `Vec` This commit maintains functionality by returning only the last wrap point from the `find_wrap_point()` function. --- src/wrap.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index aaf3aa2..eaba3a6 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -23,7 +23,7 @@ fn find_wrap_point( indent_length: usize, args: &Args, ) -> Option { - let mut wrap_point: Option = None; + let mut wrap_points: Vec = Vec::new(); let mut after_char = false; let mut prev_char: Option = None; @@ -34,19 +34,20 @@ fn find_wrap_point( // Return *byte* index rather than *char* index. for (i, c) in line.char_indices() { line_width += 1; - if line_width > wrap_boundary && wrap_point.is_some() { + if line_width > wrap_boundary && !wrap_points.is_empty() { break; } if c == ' ' && prev_char != Some('\\') { if after_char { - wrap_point = Some(i); + wrap_points.push(i); } } else if c != '%' { after_char = true; } prev_char = Some(c); } - wrap_point + + wrap_points.last().copied() } /// Wrap a long line into a short prefix and a suffix From 8fefe6f16a16280effb6cdb10409f9de196d91ff Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 13:53:57 +0100 Subject: [PATCH 05/26] Change `find_wrap_point()` to return list of possible wrap points To maintain behaviour, `apply_wrap()` is changed to extract the _last_ wrap point from the list, and wrap there. --- src/wrap.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index eaba3a6..131880f 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -17,12 +17,13 @@ pub fn needs_wrap(line: &str, indent_length: usize, args: &Args) -> bool { args.wrap && (line.chars().count() + indent_length > args.wraplen.into()) } -/// Find the best place to break a long line -fn find_wrap_point( +/// Returns a list of possible break points in the given line, taking into account the length of indentation that will +/// be added to the line. Returns `None` is no wrap points are found, so it should never return an empty list. +fn find_wrap_points( line: &str, indent_length: usize, args: &Args, -) -> Option { +) -> Option> { let mut wrap_points: Vec = Vec::new(); let mut after_char = false; let mut prev_char: Option = None; @@ -47,7 +48,11 @@ fn find_wrap_point( prev_char = Some(c); } - wrap_points.last().copied() + if wrap_points.is_empty() { + return None; + } + + Some(wrap_points) } /// Wrap a long line into a short prefix and a suffix @@ -70,7 +75,9 @@ pub fn apply_wrap<'a>( "Wrapping long line.", ); } - let wrap_point = find_wrap_point(line, indent_length, args); + // The `unwrap()` doesn't panic because find_wrap_points() returns None if there are no wrap points + let wrap_point = find_wrap_points(line, indent_length, args) + .map(|list| list.last().copied().unwrap()); let comment_index = find_comment_index(line); match wrap_point { From 47119002bd5964a6c313bb010fc474ccef56690b Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 14:19:52 +0100 Subject: [PATCH 06/26] Wrap long comments at 80 characters --- src/wrap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 131880f..ac935ac 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -17,8 +17,9 @@ pub fn needs_wrap(line: &str, indent_length: usize, args: &Args) -> bool { args.wrap && (line.chars().count() + indent_length > args.wraplen.into()) } -/// Returns a list of possible break points in the given line, taking into account the length of indentation that will -/// be added to the line. Returns `None` is no wrap points are found, so it should never return an empty list. +/// Returns a list of possible break points in the given line, taking into +/// account the length of indentation that will be added to the line. Returns +/// `None` is no wrap points are found, so it should never return an empty list. fn find_wrap_points( line: &str, indent_length: usize, @@ -75,7 +76,8 @@ pub fn apply_wrap<'a>( "Wrapping long line.", ); } - // The `unwrap()` doesn't panic because find_wrap_points() returns None if there are no wrap points + // The `unwrap()` doesn't panic because find_wrap_points() returns None if + // there are no wrap points let wrap_point = find_wrap_points(line, indent_length, args) .map(|list| list.last().copied().unwrap()); let comment_index = find_comment_index(line); From 11a26b655dae6ec43623491500188ecd9a0e79c9 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 14:22:44 +0100 Subject: [PATCH 07/26] WIP: initial re-wrapping detection logic This is still not enough for a MVP because it will attempt to re-wrap lines of text onto previous lines that didn't initially have text. --- src/format.rs | 6 ++++++ src/wrap.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/format.rs b/src/format.rs index 84b266b..c3df61b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -118,6 +118,12 @@ pub fn format_file( queue.push_front((linum_old, this_line.to_string())); continue 'main; } + } else if let Some(rewrap_point) = can_rewrap( + line.trim_start(), + queue.front().map(|(_, next_line)| next_line.as_str()), + indent_length, + args, + ) { } // Lastly, apply the indent if the line didn't need wrapping. diff --git a/src/wrap.rs b/src/wrap.rs index ac935ac..8ec3ae7 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -110,3 +110,50 @@ pub fn apply_wrap<'a>( [this_line, next_line_start, next_line] }) } + +/// Decides whether two contiguous lines can be re-wrapped. This assumes that +/// `current_line` has already been checked to not be longer than +/// `args.wraplen`. +pub fn can_rewrap( + current_line: &str, + next_line: Option<&str>, + indent_length: usize, + args: &Args, +) -> Option { + // Return early if wrapping is not enabled or if there is no next line to + // re-wrap from + if !args.wrap || next_line.is_none() { + return None; + } + + // Compute once because `.count()` is O(n) + let current_line_length = current_line.chars().count() + indent_length; + + // Sanity check that the current line is short enough + debug_assert!(current_line_length <= args.wraplen.into()); + + // Doesn't panic because None causes early return + let next_line: &str = next_line.unwrap().trim_start(); + + // Previous line ensures `next_line` is trimmed. 0 is passed for + // `indent_length` because we mostly care about the wrap points at the start + // of the line + let Some(potential_rewrap_points) = find_wrap_points(next_line, 0, args) + else { + // Early return if the next line does not contain any wrap points + return None; + }; + + let mut rewrap_point = None; + + for candidate_rewrap_point in potential_rewrap_points { + let candidate_length = current_line_length + + next_line[0..candidate_rewrap_point].chars().count(); + + if candidate_length + indent_length <= args.wrapmin.into() { + rewrap_point = Some(candidate_rewrap_point); + } + } + + rewrap_point +} From 567153d5a2de23f18d44c9b851b36058629900f8 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 15:53:43 +0100 Subject: [PATCH 08/26] Move large test files to a separate directory This branch is going to change the wrapping strategy so large test files will be impractical until they can be amended. --- src/tests.rs | 14 ++++++++++++++ tests/{ => large}/source/cam-thesis.cls | 0 .../source/higher_categories_thesis.bib | 0 .../source/higher_categories_thesis.tex | 0 tests/{ => large}/source/masters_dissertation.tex | 0 tests/{ => large}/source/ociamthesis.cls | 0 tests/{ => large}/source/phd_dissertation.tex | 0 tests/{ => large}/source/phd_dissertation_refs.bib | 0 tests/{ => large}/source/tikz_network.sty | 0 tests/{ => large}/target/cam-thesis.cls | 0 .../target/higher_categories_thesis.bib | 0 .../target/higher_categories_thesis.tex | 0 tests/{ => large}/target/masters_dissertation.tex | 0 tests/{ => large}/target/ociamthesis.cls | 0 tests/{ => large}/target/phd_dissertation.tex | 0 tests/{ => large}/target/phd_dissertation_refs.bib | 0 tests/{ => large}/target/tikz_network.sty | 0 17 files changed, 14 insertions(+) rename tests/{ => large}/source/cam-thesis.cls (100%) rename tests/{ => large}/source/higher_categories_thesis.bib (100%) rename tests/{ => large}/source/higher_categories_thesis.tex (100%) rename tests/{ => large}/source/masters_dissertation.tex (100%) rename tests/{ => large}/source/ociamthesis.cls (100%) rename tests/{ => large}/source/phd_dissertation.tex (100%) rename tests/{ => large}/source/phd_dissertation_refs.bib (100%) rename tests/{ => large}/source/tikz_network.sty (100%) rename tests/{ => large}/target/cam-thesis.cls (100%) rename tests/{ => large}/target/higher_categories_thesis.bib (100%) rename tests/{ => large}/target/higher_categories_thesis.tex (100%) rename tests/{ => large}/target/masters_dissertation.tex (100%) rename tests/{ => large}/target/ociamthesis.cls (100%) rename tests/{ => large}/target/phd_dissertation.tex (100%) rename tests/{ => large}/target/phd_dissertation_refs.bib (100%) rename tests/{ => large}/target/tikz_network.sty (100%) diff --git a/src/tests.rs b/src/tests.rs index 3133099..ade9399 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -80,6 +80,20 @@ fn test_target() { assert!(!fail, "Some tests failed"); } +#[test] +#[ignore = "large test files ignored by default."] +fn test_large_source() { + let source_files = read_files_from_dir("./tests/large/source/"); + for file in source_files { + if !test_file( + &format!("tests/large/source/{file}"), + &format!("tests/large/target/{file}"), + ) { + panic!("Failed in {file}"); + } + } +} + #[test] #[ignore] fn test_short() { diff --git a/tests/source/cam-thesis.cls b/tests/large/source/cam-thesis.cls similarity index 100% rename from tests/source/cam-thesis.cls rename to tests/large/source/cam-thesis.cls diff --git a/tests/source/higher_categories_thesis.bib b/tests/large/source/higher_categories_thesis.bib similarity index 100% rename from tests/source/higher_categories_thesis.bib rename to tests/large/source/higher_categories_thesis.bib diff --git a/tests/source/higher_categories_thesis.tex b/tests/large/source/higher_categories_thesis.tex similarity index 100% rename from tests/source/higher_categories_thesis.tex rename to tests/large/source/higher_categories_thesis.tex diff --git a/tests/source/masters_dissertation.tex b/tests/large/source/masters_dissertation.tex similarity index 100% rename from tests/source/masters_dissertation.tex rename to tests/large/source/masters_dissertation.tex diff --git a/tests/source/ociamthesis.cls b/tests/large/source/ociamthesis.cls similarity index 100% rename from tests/source/ociamthesis.cls rename to tests/large/source/ociamthesis.cls diff --git a/tests/source/phd_dissertation.tex b/tests/large/source/phd_dissertation.tex similarity index 100% rename from tests/source/phd_dissertation.tex rename to tests/large/source/phd_dissertation.tex diff --git a/tests/source/phd_dissertation_refs.bib b/tests/large/source/phd_dissertation_refs.bib similarity index 100% rename from tests/source/phd_dissertation_refs.bib rename to tests/large/source/phd_dissertation_refs.bib diff --git a/tests/source/tikz_network.sty b/tests/large/source/tikz_network.sty similarity index 100% rename from tests/source/tikz_network.sty rename to tests/large/source/tikz_network.sty diff --git a/tests/target/cam-thesis.cls b/tests/large/target/cam-thesis.cls similarity index 100% rename from tests/target/cam-thesis.cls rename to tests/large/target/cam-thesis.cls diff --git a/tests/target/higher_categories_thesis.bib b/tests/large/target/higher_categories_thesis.bib similarity index 100% rename from tests/target/higher_categories_thesis.bib rename to tests/large/target/higher_categories_thesis.bib diff --git a/tests/target/higher_categories_thesis.tex b/tests/large/target/higher_categories_thesis.tex similarity index 100% rename from tests/target/higher_categories_thesis.tex rename to tests/large/target/higher_categories_thesis.tex diff --git a/tests/target/masters_dissertation.tex b/tests/large/target/masters_dissertation.tex similarity index 100% rename from tests/target/masters_dissertation.tex rename to tests/large/target/masters_dissertation.tex diff --git a/tests/target/ociamthesis.cls b/tests/large/target/ociamthesis.cls similarity index 100% rename from tests/target/ociamthesis.cls rename to tests/large/target/ociamthesis.cls diff --git a/tests/target/phd_dissertation.tex b/tests/large/target/phd_dissertation.tex similarity index 100% rename from tests/target/phd_dissertation.tex rename to tests/large/target/phd_dissertation.tex diff --git a/tests/target/phd_dissertation_refs.bib b/tests/large/target/phd_dissertation_refs.bib similarity index 100% rename from tests/target/phd_dissertation_refs.bib rename to tests/large/target/phd_dissertation_refs.bib diff --git a/tests/target/tikz_network.sty b/tests/large/target/tikz_network.sty similarity index 100% rename from tests/target/tikz_network.sty rename to tests/large/target/tikz_network.sty From 656ee0f508050cc9bd477b3b619c7d56d3359152 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 16:45:16 +0100 Subject: [PATCH 09/26] Add initial re-wrapping test file --- src/tests.rs | 3 ++- tests/source/rewrap.tex | 8 ++++++++ tests/target/rewrap.tex | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/source/rewrap.tex create mode 100644 tests/target/rewrap.tex diff --git a/src/tests.rs b/src/tests.rs index ade9399..6ada708 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -116,8 +116,9 @@ fn test_short() { //"puthesis.cls", //"quiver.sty", //"readme.tex", + "rewrap.tex", //"sections.tex", - "short_document.tex", + // "short_document.tex", //"tikz_network.sty", //"unicode.tex", //"verbatim.tex", diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex new file mode 100644 index 0000000..028ea32 --- /dev/null +++ b/tests/source/rewrap.tex @@ -0,0 +1,8 @@ +\documentclass{article} + +\begin{document} + +This is a line that is not so long +and continues afterwards, so it should be re-wrapped. + +\end{document} \ No newline at end of file diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex new file mode 100644 index 0000000..d0b1a00 --- /dev/null +++ b/tests/target/rewrap.tex @@ -0,0 +1,8 @@ +\documentclass{article} + +\begin{document} + +This is a line that is not so long and continues afterwards, so it +should be re-wrapped. + +\end{document} From 3d8e1f6a6d3a9d1cb2a65596e98b073b5a00f246 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 9 Dec 2024 17:41:28 +0100 Subject: [PATCH 10/26] WIP: Initial wrapping logic --- src/format.rs | 11 +++++++++++ src/wrap.rs | 15 +++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/format.rs b/src/format.rs index c3df61b..86b681d 100644 --- a/src/format.rs +++ b/src/format.rs @@ -124,6 +124,17 @@ pub fn format_file( indent_length, args, ) { + // Remove the next line from the queue and replace it after + // removing the re-wrapped text. + let (linum_old, next_line) = queue.pop_front().unwrap(); // Doesn't panic because we can re-wrap. + queue.push_front(( + linum_old, + next_line[rewrap_point + 1..].to_owned(), + )); + + // Append the re-wrapped words to the current line + line = [line.as_str(), " ", &next_line[0..rewrap_point]] + .concat(); } // Lastly, apply the indent if the line didn't need wrapping. diff --git a/src/wrap.rs b/src/wrap.rs index 8ec3ae7..89b572a 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -120,9 +120,15 @@ pub fn can_rewrap( indent_length: usize, args: &Args, ) -> Option { - // Return early if wrapping is not enabled or if there is no next line to - // re-wrap from - if !args.wrap || next_line.is_none() { + // Perform some early return checks + if !args.wrap || current_line.is_empty() || next_line.is_none() { + return None; + } + + // Doesn't panic because None causes early return + let next_line: &str = next_line.unwrap().trim_start(); + + if next_line.is_empty() { return None; } @@ -132,9 +138,6 @@ pub fn can_rewrap( // Sanity check that the current line is short enough debug_assert!(current_line_length <= args.wraplen.into()); - // Doesn't panic because None causes early return - let next_line: &str = next_line.unwrap().trim_start(); - // Previous line ensures `next_line` is trimmed. 0 is passed for // `indent_length` because we mostly care about the wrap points at the start // of the line From 44fff9ce093ebc85ae5a00d5f86061a770114ed5 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 08:45:03 +0100 Subject: [PATCH 11/26] Add two-to-one re-wrap test case --- src/tests.rs | 4 +--- tests/source/rewrap.tex | 3 +++ tests/target/rewrap.tex | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 6ada708..04d05e1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -125,14 +125,12 @@ fn test_short() { //"wgu-cv.cls", //"wrap.tex", ]; - let mut fail = false; for file in files { if !test_file( &format!("tests/source/{file}"), &format!("tests/target/{file}"), ) { - fail = true; + panic!("Failed in {file}"); } } - assert!(!fail, "Some tests failed"); } diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index 028ea32..b2b53e6 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -5,4 +5,7 @@ This is a line that is not so long and continues afterwards, so it should be re-wrapped. +This is an even shorter line +that should be re-wrapped onto one line. + \end{document} \ No newline at end of file diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex index d0b1a00..5ee069d 100644 --- a/tests/target/rewrap.tex +++ b/tests/target/rewrap.tex @@ -5,4 +5,6 @@ This is a line that is not so long and continues afterwards, so it should be re-wrapped. +This is an even shorter line that should be re-wrapped onto one line. + \end{document} From 57e2f03ef76d751674f21c933730b15cfd7b31ac Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 22:51:49 +0100 Subject: [PATCH 12/26] Add environment re-wrap test case --- tests/source/rewrap.tex | 6 ++++++ tests/target/rewrap.tex | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index b2b53e6..2a4b2f7 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -8,4 +8,10 @@ This is an even shorter line that should be re-wrapped onto one line. +This is a line with some space. +\begin{definition} + And the \textbackslash{}begin command, or the line after it, should + not re-wrap. +\end{definition} + \end{document} \ No newline at end of file diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex index 5ee069d..199e67c 100644 --- a/tests/target/rewrap.tex +++ b/tests/target/rewrap.tex @@ -7,4 +7,10 @@ This is an even shorter line that should be re-wrapped onto one line. +This is a line with some space. +\begin{definition} + And the \textbackslash{}begin command, or the line after it, should + not re-wrap. +\end{definition} + \end{document} From 6163289cb424165f9cfbcc8c75b06aea0b5bc664 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 23:03:53 +0100 Subject: [PATCH 13/26] Add idempotent re-wrap test case --- tests/source/rewrap.tex | 9 +++++++++ tests/target/rewrap.tex | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index 2a4b2f7..2ee36e2 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -2,6 +2,15 @@ \begin{document} +% Text that should not re-wrap + +This is a normal line that is just long enough to reach the minimum length +and it should not be re-wrapped to maintain consistency. + +This paragraph was originally written as a long one. +% However, this sentence was commented out. +So now, it should not be re-wrapped. + This is a line that is not so long and continues afterwards, so it should be re-wrapped. diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex index 199e67c..33322f9 100644 --- a/tests/target/rewrap.tex +++ b/tests/target/rewrap.tex @@ -2,6 +2,15 @@ \begin{document} +% Text that should not re-wrap + +This is a normal line that is just long enough to reach the minimum length +and it should not be re-wrapped to maintain consistency. + +This paragraph was originally written as a long one. +% However, this sentence was commented out. +So now, it should not be re-wrapped. + This is a line that is not so long and continues afterwards, so it should be re-wrapped. From 077e0483f20267ab9f1dd25c2c264a5d8510d053 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 23:04:51 +0100 Subject: [PATCH 14/26] Make EOL a valid re-wrap position --- src/format.rs | 11 +++++++---- src/wrap.rs | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/format.rs b/src/format.rs index 86b681d..2d3a271 100644 --- a/src/format.rs +++ b/src/format.rs @@ -127,14 +127,17 @@ pub fn format_file( // Remove the next line from the queue and replace it after // removing the re-wrapped text. let (linum_old, next_line) = queue.pop_front().unwrap(); // Doesn't panic because we can re-wrap. - queue.push_front(( - linum_old, - next_line[rewrap_point + 1..].to_owned(), - )); // Append the re-wrapped words to the current line line = [line.as_str(), " ", &next_line[0..rewrap_point]] .concat(); + + // Select the line left after re-wrapping + let next_line = next_line[rewrap_point..].trim_start(); + // Add to the queue if there text left in the next line + if !next_line.is_empty() { + queue.push_front((linum_old, next_line.to_owned())); + } } // Lastly, apply the indent if the line didn't need wrapping. diff --git a/src/wrap.rs b/src/wrap.rs index 89b572a..7aed397 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -33,10 +33,13 @@ fn find_wrap_points( let wrap_boundary = usize::from(args.wrapmin) - indent_length; + let mut reached_boundary = false; + // Return *byte* index rather than *char* index. for (i, c) in line.char_indices() { line_width += 1; if line_width > wrap_boundary && !wrap_points.is_empty() { + reached_boundary = true; break; } if c == ' ' && prev_char != Some('\\') { @@ -48,6 +51,9 @@ fn find_wrap_points( } prev_char = Some(c); } + if !reached_boundary { + wrap_points.push(line_width); + } if wrap_points.is_empty() { return None; From 94e2aefa2a321c98fa699f2a876274b11676ca53 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 23:13:18 +0100 Subject: [PATCH 15/26] Don't re-wrap from or into splitting lines --- src/wrap.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 7aed397..0158e9f 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -4,6 +4,7 @@ use crate::args::*; use crate::comments::*; use crate::format::*; use crate::logging::*; +use crate::regexes::RE_SPLITTING; use log::Level; use log::LevelFilter; @@ -126,15 +127,25 @@ pub fn can_rewrap( indent_length: usize, args: &Args, ) -> Option { - // Perform some early return checks - if !args.wrap || current_line.is_empty() || next_line.is_none() { + // Early return checks + if + // If we don't wrap, are on an empty line, or there is no next line, + !args.wrap || current_line.is_empty() || next_line.is_none() + // or if the current line starts with a splitting command + || RE_SPLITTING.is_match(current_line) + { return None; } // Doesn't panic because None causes early return let next_line: &str = next_line.unwrap().trim_start(); - if next_line.is_empty() { + if next_line.is_empty() + // Re-wrapping comes after splitting, so if `next_line` contains a splitting + // command, then it's at the start, and it shouldn't be rewrapped to the + // previous line + || RE_SPLITTING.is_match(next_line) + { return None; } From 085d67067eeac799f5454e7de6485f39277cc717 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 10 Dec 2024 23:23:32 +0100 Subject: [PATCH 16/26] Add multi-line re-wrap test case --- tests/source/rewrap.tex | 7 +++++++ tests/target/rewrap.tex | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index 2ee36e2..eb0c097 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -11,12 +11,19 @@ % However, this sentence was commented out. So now, it should not be re-wrapped. +% Text that should re-wrap + This is a line that is not so long and continues afterwards, so it should be re-wrapped. This is an even shorter line that should be re-wrapped onto one line. +This is +a few short lines +that should wrap +into one. + This is a line with some space. \begin{definition} And the \textbackslash{}begin command, or the line after it, should diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex index 33322f9..3325ae2 100644 --- a/tests/target/rewrap.tex +++ b/tests/target/rewrap.tex @@ -11,11 +11,15 @@ % However, this sentence was commented out. So now, it should not be re-wrapped. +% Text that should re-wrap + This is a line that is not so long and continues afterwards, so it should be re-wrapped. This is an even shorter line that should be re-wrapped onto one line. +This is a few short lines that should wrap into one. + This is a line with some space. \begin{definition} And the \textbackslash{}begin command, or the line after it, should From 14049f2daa6e84e487f5a55ce5a3a8167455d9c0 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Wed, 11 Dec 2024 15:44:54 +0100 Subject: [PATCH 17/26] Add re-wrap test case for items --- tests/source/rewrap.tex | 9 +++++++++ tests/target/rewrap.tex | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index eb0c097..59ba5fa 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -30,4 +30,13 @@ not re-wrap. \end{definition} +Environments with items should re-wrap onto lines with items, but not re-wrap +lines from lines containing items. +\begin{itemize} + \item This is a short line which can take +more words, and they should be moved there, and the line should also be +correctly indented. + \item However, this line should not be re-wrapped onto the previous one. +\end{itemize} + \end{document} \ No newline at end of file diff --git a/tests/target/rewrap.tex b/tests/target/rewrap.tex index 3325ae2..c6d8387 100644 --- a/tests/target/rewrap.tex +++ b/tests/target/rewrap.tex @@ -26,4 +26,13 @@ not re-wrap. \end{definition} +Environments with items should re-wrap onto lines with items, but not re-wrap +lines from lines containing items. +\begin{itemize} + \item This is a short line which can take more words, and they + should be moved there, and the line should also be correctly + indented. + \item However, this line should not be re-wrapped onto the previous one. +\end{itemize} + \end{document} From c44b60f7b606f43d5764343657f8eca83d9363dd Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Wed, 11 Dec 2024 16:05:43 +0100 Subject: [PATCH 18/26] Don't wrap lines into comments or from comments --- src/wrap.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 0158e9f..b115ce1 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -131,8 +131,10 @@ pub fn can_rewrap( if // If we don't wrap, are on an empty line, or there is no next line, !args.wrap || current_line.is_empty() || next_line.is_none() - // or if the current line starts with a splitting command + // or if the current line starts with a splitting command, || RE_SPLITTING.is_match(current_line) + // or if the current line contains a comment, + || find_comment_index(current_line).is_some() { return None; } @@ -158,20 +160,30 @@ pub fn can_rewrap( // Previous line ensures `next_line` is trimmed. 0 is passed for // `indent_length` because we mostly care about the wrap points at the start // of the line - let Some(potential_rewrap_points) = find_wrap_points(next_line, 0, args) + let Some(candidate_rewrap_points) = find_wrap_points(next_line, 0, args) else { // Early return if the next line does not contain any wrap points return None; }; + // Get an optional comment index from the next line + let maybe_comment_index = find_comment_index(next_line); + let mut rewrap_point = None; + for candidate_point in candidate_rewrap_points { + // If the next line contains a comment, stop considering re-wrap points + // later than the comment index. + if let Some(comment_index) = maybe_comment_index { + if candidate_point >= comment_index { + break; + } + } - for candidate_rewrap_point in potential_rewrap_points { - let candidate_length = current_line_length - + next_line[0..candidate_rewrap_point].chars().count(); + let candidate_length = + current_line_length + next_line[0..candidate_point].chars().count(); if candidate_length + indent_length <= args.wrapmin.into() { - rewrap_point = Some(candidate_rewrap_point); + rewrap_point = Some(candidate_point); } } From afedb95cd4c38a47a22fa04d2bc02e6ee72f194a Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Wed, 11 Dec 2024 16:08:54 +0100 Subject: [PATCH 19/26] Re-queue current line for further re-wrapping --- src/format.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/format.rs b/src/format.rs index 2d3a271..4ac1888 100644 --- a/src/format.rs +++ b/src/format.rs @@ -134,10 +134,18 @@ pub fn format_file( // Select the line left after re-wrapping let next_line = next_line[rewrap_point..].trim_start(); + // Add to the queue if there text left in the next line if !next_line.is_empty() { queue.push_front((linum_old, next_line.to_owned())); } + + // Push the current line in the queue for further potential + // re-wrapping + queue.push_front((linum_old, line)); + + // Continue the loop to avoid writing the current line for now + continue; } // Lastly, apply the indent if the line didn't need wrapping. From 1241da6b6a69bdaef06ea04b69aaa54724af027d Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Thu, 12 Dec 2024 09:40:36 +0100 Subject: [PATCH 20/26] Re-wrap onto lines containing items --- src/format.rs | 1 + src/wrap.rs | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/format.rs b/src/format.rs index 4ac1888..78a5461 100644 --- a/src/format.rs +++ b/src/format.rs @@ -120,6 +120,7 @@ pub fn format_file( } } else if let Some(rewrap_point) = can_rewrap( line.trim_start(), + &pattern, queue.front().map(|(_, next_line)| next_line.as_str()), indent_length, args, diff --git a/src/wrap.rs b/src/wrap.rs index b115ce1..bc502a2 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -123,17 +123,18 @@ pub fn apply_wrap<'a>( /// `args.wraplen`. pub fn can_rewrap( current_line: &str, + current_pattern: &Pattern, next_line: Option<&str>, indent_length: usize, args: &Args, ) -> Option { // Early return checks if - // If we don't wrap, are on an empty line, or there is no next line, + // we don't wrap, are on an empty line, or there is no next line, !args.wrap || current_line.is_empty() || next_line.is_none() - // or if the current line starts with a splitting command, - || RE_SPLITTING.is_match(current_line) - // or if the current line contains a comment, + // or the current line starts with a splitting command, + || (current_pattern.contains_splitting && !current_pattern.contains_item) + // or the current line contains a comment, || find_comment_index(current_line).is_some() { return None; From ccdbc4284d973a19a03b685f1b4a10bc8aed6549 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Thu, 12 Dec 2024 10:03:07 +0100 Subject: [PATCH 21/26] Amend re-wrap test to check trimming --- tests/source/rewrap.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/source/rewrap.tex b/tests/source/rewrap.tex index 59ba5fa..56e3231 100644 --- a/tests/source/rewrap.tex +++ b/tests/source/rewrap.tex @@ -35,7 +35,7 @@ \begin{itemize} \item This is a short line which can take more words, and they should be moved there, and the line should also be -correctly indented. + correctly indented. \item However, this line should not be re-wrapped onto the previous one. \end{itemize} From f2df0b46b29a10581416ae226443672b96468f0e Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Thu, 12 Dec 2024 11:36:44 +0100 Subject: [PATCH 22/26] Fix trimming issue --- src/format.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/format.rs b/src/format.rs index 78a5461..c856832 100644 --- a/src/format.rs +++ b/src/format.rs @@ -129,12 +129,19 @@ pub fn format_file( // removing the re-wrapped text. let (linum_old, next_line) = queue.pop_front().unwrap(); // Doesn't panic because we can re-wrap. + let trimmed_next_line = next_line.trim_start(); + // Append the re-wrapped words to the current line - line = [line.as_str(), " ", &next_line[0..rewrap_point]] - .concat(); + line = [ + line.as_str(), + " ", + &trimmed_next_line[0..rewrap_point], + ] + .concat(); // Select the line left after re-wrapping - let next_line = next_line[rewrap_point..].trim_start(); + let next_line = + trimmed_next_line[rewrap_point..].trim_start(); // Add to the queue if there text left in the next line if !next_line.is_empty() { From 3267fa7e9ff2aaa5ab5d189cc6c57ebb1e271728 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 16 Dec 2024 16:45:40 +0100 Subject: [PATCH 23/26] Create test for pattern detection --- src/format.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/format.rs b/src/format.rs index c856832..92376e8 100644 --- a/src/format.rs +++ b/src/format.rs @@ -307,3 +307,18 @@ pub fn run(args: &Args, logs: &mut Vec) -> u8 { } exit_code } + +#[cfg(test)] +mod tests { + use super::Pattern; + + #[test] + fn new_pattern() { + let pattern = + Pattern::new("\\begin{enumerate} \\end{enumerate} \\item "); + assert!(pattern.contains_env_begin); + assert!(pattern.contains_env_end); + assert!(pattern.contains_item); + assert!(pattern.contains_splitting); + } +} From 01a07860f148e85f0b38c9b1bbc8a6624f6ff28d Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Mon, 16 Dec 2024 16:47:24 +0100 Subject: [PATCH 24/26] Refactor pattern creation --- src/format.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/format.rs b/src/format.rs index 92376e8..84214b9 100644 --- a/src/format.rs +++ b/src/format.rs @@ -247,6 +247,7 @@ impl State { } /// Record whether a line contains certain patterns to avoid recomputing +#[derive(Default)] pub struct Pattern { /// Whether a begin environment pattern is present pub contains_env_begin: bool, @@ -261,22 +262,17 @@ pub struct Pattern { impl Pattern { /// Check if a string contains patterns pub fn new(s: &str) -> Self { + let mut pattern = Self::default(); + // If splitting does not match, no patterns are present if RE_SPLITTING.is_match(s) { - Self { - contains_env_begin: s.contains(ENV_BEGIN), - contains_env_end: s.contains(ENV_END), - contains_item: s.contains(ITEM), - contains_splitting: true, - } - } else { - Self { - contains_env_begin: false, - contains_env_end: false, - contains_item: false, - contains_splitting: false, - } + pattern.contains_env_begin = s.contains(ENV_BEGIN); + pattern.contains_env_end = s.contains(ENV_END); + pattern.contains_item = s.contains(ITEM); + pattern.contains_splitting = true; } + + pattern } } From d47147db5e5a09723d2ca507546dd52314d9b8f4 Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Tue, 17 Dec 2024 11:09:27 +0100 Subject: [PATCH 25/26] Move pattern detection to its own module --- src/format.rs | 47 +---------------------------------------------- src/indent.rs | 1 + src/main.rs | 1 + src/pattern.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/subs.rs | 1 + src/verbatim.rs | 1 + src/wrap.rs | 1 + 7 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 src/pattern.rs diff --git a/src/format.rs b/src/format.rs index 84214b9..a95ece1 100644 --- a/src/format.rs +++ b/src/format.rs @@ -4,8 +4,8 @@ use crate::args::*; use crate::ignore::*; use crate::indent::*; use crate::logging::*; +use crate::pattern::Pattern; use crate::read::*; -use crate::regexes::{ENV_BEGIN, ENV_END, ITEM, RE_SPLITTING}; use crate::subs::*; use crate::verbatim::*; use crate::wrap::*; @@ -246,36 +246,6 @@ impl State { } } -/// Record whether a line contains certain patterns to avoid recomputing -#[derive(Default)] -pub struct Pattern { - /// Whether a begin environment pattern is present - pub contains_env_begin: bool, - /// Whether an end environment pattern is present - pub contains_env_end: bool, - /// Whether an item pattern is present - pub contains_item: bool, - /// Whether a splitting pattern is present - pub contains_splitting: bool, -} - -impl Pattern { - /// Check if a string contains patterns - pub fn new(s: &str) -> Self { - let mut pattern = Self::default(); - - // If splitting does not match, no patterns are present - if RE_SPLITTING.is_match(s) { - pattern.contains_env_begin = s.contains(ENV_BEGIN); - pattern.contains_env_end = s.contains(ENV_END); - pattern.contains_item = s.contains(ITEM); - pattern.contains_splitting = true; - } - - pattern - } -} - /// Ensure that the indentation returns to zero at the end of the file const fn indents_return_to_zero(state: &State) -> bool { state.indent.actual == 0 @@ -303,18 +273,3 @@ pub fn run(args: &Args, logs: &mut Vec) -> u8 { } exit_code } - -#[cfg(test)] -mod tests { - use super::Pattern; - - #[test] - fn new_pattern() { - let pattern = - Pattern::new("\\begin{enumerate} \\end{enumerate} \\item "); - assert!(pattern.contains_env_begin); - assert!(pattern.contains_env_end); - assert!(pattern.contains_item); - assert!(pattern.contains_splitting); - } -} diff --git a/src/indent.rs b/src/indent.rs index 589c273..5d1cf5c 100644 --- a/src/indent.rs +++ b/src/indent.rs @@ -4,6 +4,7 @@ use crate::args::*; use crate::comments::*; use crate::format::*; use crate::logging::*; +use crate::pattern::Pattern; use crate::regexes::*; use core::cmp::max; use log::Level; diff --git a/src/main.rs b/src/main.rs index 34572e2..af8f195 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ mod format; mod ignore; mod indent; mod logging; +mod pattern; mod read; mod regexes; mod subs; diff --git a/src/pattern.rs b/src/pattern.rs new file mode 100644 index 0000000..8bbcc7e --- /dev/null +++ b/src/pattern.rs @@ -0,0 +1,46 @@ +use crate::regexes::*; + +/// Record whether a line contains certain patterns to avoid recomputing +#[derive(Default)] +pub struct Pattern { + /// Whether a begin environment pattern is present + pub contains_env_begin: bool, + /// Whether an end environment pattern is present + pub contains_env_end: bool, + /// Whether an item pattern is present + pub contains_item: bool, + /// Whether a splitting pattern is present + pub contains_splitting: bool, +} + +impl Pattern { + /// Check if a string contains patterns + pub fn new(s: &str) -> Self { + let mut pattern = Self::default(); + + // If splitting does not match, no patterns are present + if RE_SPLITTING.is_match(s) { + pattern.contains_env_begin = s.contains(ENV_BEGIN); + pattern.contains_env_end = s.contains(ENV_END); + pattern.contains_item = s.contains(ITEM); + pattern.contains_splitting = true; + } + + pattern + } +} + +#[cfg(test)] +mod tests { + use super::Pattern; + + #[test] + fn new_pattern() { + let pattern = + Pattern::new("\\begin{enumerate} \\end{enumerate} \\item "); + assert!(pattern.contains_env_begin); + assert!(pattern.contains_env_end); + assert!(pattern.contains_item); + assert!(pattern.contains_splitting); + } +} diff --git a/src/subs.rs b/src/subs.rs index 71b55f3..3bb4de2 100644 --- a/src/subs.rs +++ b/src/subs.rs @@ -4,6 +4,7 @@ use crate::args::*; use crate::comments::*; use crate::format::*; use crate::logging::*; +use crate::pattern::Pattern; use crate::regexes::*; use crate::LINE_END; use log::Level; diff --git a/src/verbatim.rs b/src/verbatim.rs index 17b34c8..2261425 100644 --- a/src/verbatim.rs +++ b/src/verbatim.rs @@ -2,6 +2,7 @@ use crate::format::*; use crate::logging::*; +use crate::pattern::Pattern; use crate::regexes::*; use log::Level::Warn; diff --git a/src/wrap.rs b/src/wrap.rs index bc502a2..1c6a355 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -4,6 +4,7 @@ use crate::args::*; use crate::comments::*; use crate::format::*; use crate::logging::*; +use crate::pattern::Pattern; use crate::regexes::RE_SPLITTING; use log::Level; use log::LevelFilter; From b4549da273abef3727b0a98a4ec99c781e197e7a Mon Sep 17 00:00:00 2001 From: Cyprien de Saint Guilhem Date: Sat, 21 Dec 2024 11:04:47 +0000 Subject: [PATCH 26/26] Add module documentation --- src/pattern.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pattern.rs b/src/pattern.rs index 8bbcc7e..9dfaea5 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -1,3 +1,5 @@ +//! Detecting patterns within lines + use crate::regexes::*; /// Record whether a line contains certain patterns to avoid recomputing