-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor lib into smaller modules #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,64 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //! Thematic break formatting utilities. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use regex::Regex; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::wrap::is_fence; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub const THEMATIC_BREAK_LEN: usize = 70; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static THEMATIC_BREAK_RE: std::sync::LazyLock<Regex> = std::sync::LazyLock::new(|| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Regex::new(r"^[ ]{0,3}((?:[ \t]*\*){3,}|(?:[ \t]*-){3,}|(?:[ \t]*_){3,})[ \t]*$").unwrap() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static THEMATIC_BREAK_LINE: std::sync::LazyLock<String> = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::sync::LazyLock::new(|| "_".repeat(THEMATIC_BREAK_LEN)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[must_use] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn format_breaks(lines: &[String]) -> Vec<String> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut out = Vec::with_capacity(lines.len()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut in_code = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for line in lines { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if is_fence(line) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in_code = !in_code; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.push(line.clone()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !in_code && THEMATIC_BREAK_RE.is_match(line.trim_end()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.push(THEMATIC_BREAK_LINE.clone()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.push(line.clone()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mod tests { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use super::*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn basic_formatting() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let input = vec!["foo", "***", "bar"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .into_iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(str::to_string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect::<Vec<_>>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let expected = vec![ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "foo".to_string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "_".repeat(THEMATIC_BREAK_LEN), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "bar".to_string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(format_breaks(&input), expected); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn ignores_fenced_code() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let input = vec!["```", "---", "```"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .into_iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(str::to_string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect::<Vec<_>>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(format_breaks(&input), input); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+44
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Simplify test data construction. Use #[test]
fn basic_formatting() {
- let input = vec!["foo", "***", "bar"]
- .into_iter()
- .map(str::to_string)
- .collect::<Vec<_>>();
+ let input = vec!["foo".to_string(), "***".to_string(), "bar".to_string()];
let expected = vec![
"foo".to_string(),
"_".repeat(THEMATIC_BREAK_LEN),
"bar".to_string(),
];
assert_eq!(format_breaks(&input), expected);
}
#[test]
fn ignores_fenced_code() {
- let input = vec!["```", "---", "```"]
- .into_iter()
- .map(str::to_string)
- .collect::<Vec<_>>();
+ let input = vec!["```".to_string(), "---".to_string(), "```".to_string()];
assert_eq!(format_breaks(&input), input);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //! File helpers for rewriting Markdown documents. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use std::{fs, path::Path}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::process::{process_stream, process_stream_no_wrap}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Rewrite a file in place with wrapped tables. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// # Errors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Returns an error if reading or writing the file fails. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn rewrite(path: &Path) -> std::io::Result<()> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let text = fs::read_to_string(path)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let lines: Vec<String> = text.lines().map(str::to_string).collect(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let fixed = process_stream(&lines); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::write(path, fixed.join("\n") + "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Rewrite a file in place without wrapping text. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// # Errors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Returns an error if reading or writing the file fails. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn rewrite_no_wrap(path: &Path) -> std::io::Result<()> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let text = fs::read_to_string(path)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let lines: Vec<String> = text.lines().map(str::to_string).collect(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let fixed = process_stream_no_wrap(&lines); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::write(path, fixed.join("\n") + "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+11
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Extract common logic to reduce duplication. Both functions share identical logic except for the processing function call. Extract the common pattern to adhere to DRY principles. +fn rewrite_impl(path: &Path, wrap: bool) -> std::io::Result<()> {
+ let text = fs::read_to_string(path)?;
+ let lines: Vec<String> = text.lines().map(str::to_string).collect();
+ let fixed = if wrap {
+ process_stream(&lines)
+ } else {
+ process_stream_no_wrap(&lines)
+ };
+ fs::write(path, fixed.join("\n") + "\n")
+}
+
pub fn rewrite(path: &Path) -> std::io::Result<()> {
- let text = fs::read_to_string(path)?;
- let lines: Vec<String> = text.lines().map(str::to_string).collect();
- let fixed = process_stream(&lines);
- fs::write(path, fixed.join("\n") + "\n")
+ rewrite_impl(path, true)
}
pub fn rewrite_no_wrap(path: &Path) -> std::io::Result<()> {
- let text = fs::read_to_string(path)?;
- let lines: Vec<String> = text.lines().map(str::to_string).collect();
- let fixed = process_stream_no_wrap(&lines);
- fs::write(path, fixed.join("\n") + "\n")
+ rewrite_impl(path, false)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mod tests { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use tempfile::tempdir; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use super::*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn rewrite_roundtrip() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let dir = tempdir().unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let file = dir.path().join("sample.md"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::write(&file, "|A|B|\n|1|2|").unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rewrite(&file).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let out = fs::read_to_string(&file).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert!(out.contains("| A | B |")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn rewrite_no_wrap_roundtrip() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let dir = tempdir().unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let file = dir.path().join("sample.md"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fs::write(&file, "|A|B|\n|1|2|").unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rewrite_no_wrap(&file).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let out = fs::read_to_string(&file).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert_eq!(out, "| A | B |\n| 1 | 2 |\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+54
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 🛠️ Refactor suggestion Add tests for error scenarios. The current tests only cover successful operations. Add tests for I/O error scenarios such as non-existent files and permission errors. Would you like me to generate comprehensive error handling tests for file I/O operations? 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Optimize to avoid unnecessary string clones.
The function clones every line regardless of whether it needs modification. Use
Cow<str>or conditionally clone only when replacing thematic breaks.Alternatively, return
Vec<Cow<'_, str>>to avoid cloning unchanged lines entirely.🤖 Prompt for AI Agents