diff --git a/Cargo.lock b/Cargo.lock index 510f7e10..d1676e23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,6 +404,7 @@ dependencies = [ "clap", "html5ever", "markup5ever_rcdom", + "once_cell", "regex", "rstest", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 7c529e07..19afabb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" anyhow = "1" clap = { version = "4", features = ["derive"] } regex = "1" +once_cell = "1" html5ever = "0.27" markup5ever_rcdom = "0.3" unicode-width = ">=0.1, <0.2" diff --git a/README.md b/README.md index 0b5071d4..68db0695 100644 --- a/README.md +++ b/README.md @@ -13,26 +13,20 @@ making it safe to use on Markdown with mixed content. Install via Cargo: -Bash - ```bash cargo install mdtablefix ``` Or clone the repository and build from source: -Bash - ```bash cargo install --path . ``` ## Command-line usage -Bash - ```bash -mdtablefix [--wrap] [--renumber] [--breaks] [--ellipsis] [--in-place] [FILE...] +mdtablefix [--wrap] [--renumber] [--breaks] [--ellipsis] [--footnotes] [--in-place] [FILE...] ``` - When one or more file paths are provided, the corrected tables are printed to @@ -53,6 +47,9 @@ mdtablefix [--wrap] [--renumber] [--breaks] [--ellipsis] [--in-place] [FILE...] character (`…`). Longer runs are processed left-to-right, so any leftover dots are preserved. +- Use `--footnotes` to convert bare numeric references and the final numbered + list into GitHub-flavoured footnote links. + - Use `--in-place` to modify files in-place. - If no files are specified, input is read from stdin and output is written to @@ -62,8 +59,6 @@ mdtablefix [--wrap] [--renumber] [--breaks] [--ellipsis] [--in-place] [FILE...] Before: -Markdown - ```markdown |Character|Catchphrase|Pizza count| |---|---|---| |Speedy Cerviche|Here come the Samurai Pizza Cats!|lots| |Guido Anchovy|Slice and dice!|tons| @@ -72,8 +67,6 @@ come the Samurai Pizza Cats!|lots| |Guido Anchovy|Slice and dice!|tons| After running `mdtablefix`: -Markdown - ```markdown | Character | Catchphrase | Pizza count | | --------------- | --------------------------------- | ----------- | @@ -86,8 +79,6 @@ Markdown Before: -Markdown - ```markdown 1. The Big Cheese's evil plans. 4. Jerry Atric's schemes. @@ -102,8 +93,6 @@ A brief intermission for pizza. After running `mdtablefix --renumber`: -Markdown - ```markdown 1. The Big Cheese's evil plans. 2. Jerry Atric's schemes. @@ -121,8 +110,6 @@ A brief intermission for pizza. The crate provides helper functions for embedding the table reflow logic in your own Rust project: -Rust - ```rust use mdtablefix::{process_stream_opts, rewrite}; use std::path::Path; @@ -133,6 +120,7 @@ fn main() -> std::io::Result<()> { &lines, /* wrap = */ true, /* ellipsis = */ true, + /* footnotes = */ false, ); println!("{}", fixed.join("\n")); rewrite(Path::new("table.md"))?; @@ -140,9 +128,9 @@ fn main() -> std::io::Result<()> { } ``` -- `process_stream_opts(lines: &[String], wrap: bool, ellipsis: bool) -> - Vec` rewrites tables in memory, with optional paragraph wrapping and - ellipsis substitution. +- `process_stream_opts(lines, wrap, ellipsis, footnotes) -> Vec` + rewrites tables in memory, with optional paragraph wrapping, ellipsis + substitution, and footnote conversion. - `rewrite(path: &Path) -> std::io::Result<()>` modifies a Markdown file on disk in-place. diff --git a/docs/module-relationships.md b/docs/module-relationships.md index 2443a05d..1137d929 100644 --- a/docs/module-relationships.md +++ b/docs/module-relationships.md @@ -36,6 +36,10 @@ classDiagram <> +replace_ellipsis() } + class footnotes { + <> + +convert_footnotes() + } class process { <> +process_stream() @@ -63,11 +67,12 @@ classDiagram process ..> table : uses reflow_table process ..> wrap : uses wrap_text, is_fence process ..> ellipsis : uses replace_ellipsis + process ..> footnotes : uses convert_footnotes io ..> process : uses process_stream, process_stream_no_wrap ``` The `lib` module re-exports the public API from the other modules. The `ellipsis` module performs text normalisation. The `process` module provides streaming helpers that combine the lower-level functions, including ellipsis -replacement. The `io` module handles filesystem operations, delegating the text -processing to `process`. +replacement and footnote conversion. The `io` module handles filesystem +operations, delegating the text processing to `process`. diff --git a/src/footnotes.rs b/src/footnotes.rs new file mode 100644 index 00000000..790ea833 --- /dev/null +++ b/src/footnotes.rs @@ -0,0 +1,109 @@ +//! Footnote normalisation utilities. +//! +//! Converts bare numeric references in text to GitHub-flavoured Markdown +//! footnote links and rewrites the trailing numeric list into a footnote +//! block. Only the final contiguous list of footnotes is processed. + +use regex::{Captures, Regex}; + +static INLINE_FN_RE: std::sync::LazyLock = std::sync::LazyLock::new(|| { + Regex::new(r"(?P
^|[^0-9])(?P[.!?);:])(?P