Packages
rbt_weave
0.2.64
0.2.67
0.2.66
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.57
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Graph conflict detection and image processing NIFs for OSINT knowledge graphs, powered by Rust.
Current section
Files
Jump to
Current section
Files
crates/weave-content/src/html/escape.rs
//! HTML escaping, truncation, and inline markdown rendering.
use pulldown_cmark::{Event, Options, Parser, Tag, TagEnd};
pub(crate) fn truncate(s: &str, max: usize) -> String {
if s.len() <= max {
s.to_string()
} else {
let truncated: String = s.chars().take(max.saturating_sub(3)).collect();
format!("{truncated}...")
}
}
pub(crate) fn escape(s: &str) -> String {
s.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
}
pub(crate) fn escape_attr(s: &str) -> String {
escape(s)
}
/// Convert a `snake_case` enum value to Title Case for display.
/// Custom values prefixed with `custom:` are returned as-is.
pub(crate) fn format_enum(s: &str) -> String {
if let Some(custom) = s.strip_prefix("custom:") {
return custom.to_string();
}
s.split('_')
.map(|word| {
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(c) => {
let upper: String = c.to_uppercase().collect();
upper + chars.as_str()
}
}
})
.collect::<Vec<_>>()
.join(" ")
}
/// Render inline markdown to HTML, stripping block-level wrappers.
///
/// Supports bold, italic, links, and inline code. Block-level elements
/// (paragraphs, headings, lists) are flattened to their inline content.
pub(crate) fn render_inline_markdown(s: &str) -> String {
let parser = Parser::new_ext(s, Options::empty());
let mut out = String::with_capacity(s.len());
for event in parser {
match event {
Event::Text(text) => out.push_str(&escape(&text)),
Event::Code(code) => {
out.push_str("<code>");
out.push_str(&escape(&code));
out.push_str("</code>");
}
Event::Start(Tag::Strong) => out.push_str("<strong>"),
Event::End(TagEnd::Strong) => out.push_str("</strong>"),
Event::Start(Tag::Emphasis) => out.push_str("<em>"),
Event::End(TagEnd::Emphasis) => out.push_str("</em>"),
Event::Start(Tag::Link { dest_url, .. }) => {
out.push_str(&format!(
"<a href=\"{}\" rel=\"noopener noreferrer\">",
escape_attr(&dest_url)
));
}
Event::End(TagEnd::Link) => out.push_str("</a>"),
Event::SoftBreak | Event::HardBreak => out.push(' '),
_ => {}
}
}
out
}