HTML export, plain text and rich copy read each paragraph, heading, cell and HTML block through the component's MarkdownReader (pin 1251221). Emoji, alerts, the TOC and inline tags match visual mode. Footnotes sit in place as [n]; link titles are not written. Three review rounds failed; round 3's one finding (a scan per footnote over open marks) is fixed with a growth regression, unreviewed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
27 lines
878 B
Rust
27 lines
878 B
Rust
//! Addresses, read as browsers read them.
|
|
|
|
/// A plain, web or mail address, read as browsers do.
|
|
pub(super) fn safe(url: &str) -> bool {
|
|
// Browsers trim spaces and controls, then drop tabs and newlines.
|
|
let read: String = url
|
|
.trim_matches(|ch: char| ch <= ' ')
|
|
.chars()
|
|
.filter(|ch| !matches!(ch, '\t' | '\n' | '\r'))
|
|
.collect();
|
|
match scheme(&read) {
|
|
None => true,
|
|
Some(scheme) => ["http", "https", "mailto"].contains(&scheme.to_lowercase().as_str()),
|
|
}
|
|
}
|
|
|
|
/// An address's scheme, when it has one.
|
|
pub(super) fn scheme(url: &str) -> Option<&str> {
|
|
let end = url.find(':')?;
|
|
let name = &url[..end];
|
|
let plain = name
|
|
.chars()
|
|
.all(|ch| ch.is_ascii_alphanumeric() || "+-.".contains(ch));
|
|
// A drive letter is a path, not a scheme.
|
|
(plain && name.len() > 1).then_some(name)
|
|
}
|