mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-23 03:07:13 +00:00
ported patterns mean in rust what they mean in python
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use regex::Regex;
|
||||
use textkit::pattern::SPACE;
|
||||
|
||||
fn pattern(source: &str) -> Regex {
|
||||
Regex::new(source).expect("a valid pattern")
|
||||
@@ -21,23 +22,24 @@ static LINK: LazyLock<Regex> = LazyLock::new(|| pattern(r"\[([^\]]*)\]\([^)]*\)"
|
||||
static BRACKETED: LazyLock<Regex> = LazyLock::new(|| pattern(r"\[([^\]]+)\]\{[^}]*\}"));
|
||||
|
||||
/// A trailing `{.attr}` block.
|
||||
static ATTRIBUTE_TAIL: LazyLock<Regex> = LazyLock::new(|| pattern(r"\s*\{[^}]*\}\s*$"));
|
||||
static ATTRIBUTE_TAIL: LazyLock<Regex> =
|
||||
LazyLock::new(|| pattern(&format!(r"{SPACE}*\{{[^}}]*\}}{SPACE}*$")));
|
||||
|
||||
/// Any inline tag. Broader than the one used on body text, because a heading
|
||||
/// has no code fences to protect.
|
||||
static TAG: LazyLock<Regex> = LazyLock::new(|| pattern(r"<[^>]+>"));
|
||||
|
||||
static SPACE_RUN: LazyLock<Regex> = LazyLock::new(|| pattern(r"\s+"));
|
||||
static SPACE_RUN: LazyLock<Regex> = LazyLock::new(|| pattern(&format!(r"{SPACE}+")));
|
||||
|
||||
/// A heading line, and the text after its hashes.
|
||||
static HEADING: LazyLock<Regex> = LazyLock::new(|| pattern(r"^(#{1,6})\s+(.*)$"));
|
||||
static HEADING: LazyLock<Regex> = LazyLock::new(|| pattern(&format!(r"^(#{{1,6}}){SPACE}+(.*)$")));
|
||||
|
||||
/// A page anchor: `<span id="…page42">`, `<a id="page-42">`, and the rest of
|
||||
/// the shapes an EPUB uses to say where a printed page began.
|
||||
pub static PAGE_ANCHOR: LazyLock<Regex> = LazyLock::new(|| {
|
||||
pattern(
|
||||
r#"(?i)<(?:span|a|div)\b[^>]*\bid\s*=\s*["'][^"']*?page[-_]?(\d+)[^"']*["'][^>]*>(?:</(?:span|a|div)>)?"#,
|
||||
)
|
||||
pattern(&format!(
|
||||
r#"(?i)<(?:span|a|div)\b[^>]*\bid{SPACE}*={SPACE}*["'][^"']*?page[-_]?(\d+)[^"']*["'][^>]*>(?:</(?:span|a|div)>)?"#
|
||||
))
|
||||
});
|
||||
|
||||
/// Clean one heading's text.
|
||||
|
||||
+19
-12
@@ -16,7 +16,6 @@ use corpus_core::exit;
|
||||
#[command(
|
||||
version,
|
||||
about,
|
||||
long_about = None,
|
||||
after_help = "\
|
||||
Example:
|
||||
|
||||
@@ -32,9 +31,9 @@ fn main() -> ExitCode {
|
||||
|
||||
let markdown = match read(args.path.as_deref()) {
|
||||
Ok(markdown) => markdown,
|
||||
Err(e) => {
|
||||
eprintln!("mdscrub: {e}");
|
||||
return ExitCode::from(exit::IO);
|
||||
Err((code, why)) => {
|
||||
eprintln!("mdscrub: {why}");
|
||||
return ExitCode::from(code);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,13 +49,21 @@ fn main() -> ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
fn read(path: Option<&Path>) -> std::io::Result<String> {
|
||||
match path {
|
||||
Some(path) => std::fs::read_to_string(path),
|
||||
None => {
|
||||
let mut markdown = String::new();
|
||||
std::io::stdin().read_to_string(&mut markdown)?;
|
||||
Ok(markdown)
|
||||
/// Read the input, distinguishing a file that cannot be read from one that
|
||||
/// is not text: the first is an I/O failure and the second is bad input, and
|
||||
/// a caller routing on the exit code needs to tell them apart.
|
||||
fn read(path: Option<&Path>) -> Result<String, (u8, String)> {
|
||||
let bytes = match path {
|
||||
Some(path) => {
|
||||
std::fs::read(path).map_err(|e| (exit::IO, format!("{}: {e}", path.display())))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let mut bytes = Vec::new();
|
||||
std::io::stdin()
|
||||
.read_to_end(&mut bytes)
|
||||
.map(|_| bytes)
|
||||
.map_err(|e| (exit::IO, e.to_string()))
|
||||
}
|
||||
}?;
|
||||
String::from_utf8(bytes).map_err(|e| (exit::DATA, format!("input is not UTF-8: {e}")))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user