use once_cell::sync::Lazy;
use regex::Regex;
pub fn md_comment(text: &str) -> String {
format!("<!-- {} -->", text)
}
pub const WARNING: &str =
"<!-- \u{26A0}\u{FE0F} This content is auto-generated by `markdown-code-runner`. -->";
pub const SKIP: &str = "<!-- CODE:SKIP -->";
pub const CODE_COMMENT_PYTHON_START: &str = "<!-- CODE:START -->";
pub const CODE_COMMENT_BASH_START: &str = "<!-- CODE:BASH:START -->";
pub const CODE_COMMENT_END: &str = "<!-- CODE:END -->";
pub const OUTPUT_START: &str = "<!-- OUTPUT:START -->";
pub const OUTPUT_END: &str = "<!-- OUTPUT:END -->";
pub static SKIP_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- CODE:SKIP -->").unwrap());
pub static CODE_COMMENT_PYTHON_START_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- CODE:START -->").unwrap());
pub static CODE_COMMENT_BASH_START_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- CODE:BASH:START -->").unwrap());
pub static CODE_COMMENT_END_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- CODE:END -->").unwrap());
pub static OUTPUT_START_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- OUTPUT:START -->").unwrap());
pub static OUTPUT_END_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)<!-- OUTPUT:END -->").unwrap());
pub static CODE_BACKTICKS_START_PATTERN: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^(?P<spaces>\s*)```(?P<language>\w+)\s+markdown-code-runner").unwrap()
});
pub static CODE_BACKTICKS_END_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^(?P<spaces>\s*)```\s*$").unwrap());
pub fn is_skip(line: &str) -> bool {
SKIP_PATTERN.is_match(line)
}
pub fn is_output_start(line: &str) -> Option<regex::Match<'_>> {
OUTPUT_START_PATTERN.find(line)
}
pub fn is_output_end(line: &str) -> bool {
OUTPUT_END_PATTERN.is_match(line)
}
pub fn is_code_comment_python_start(line: &str) -> Option<regex::Match<'_>> {
CODE_COMMENT_PYTHON_START_PATTERN.find(line)
}
pub fn is_code_comment_bash_start(line: &str) -> Option<regex::Match<'_>> {
CODE_COMMENT_BASH_START_PATTERN.find(line)
}
pub fn is_code_comment_end(line: &str) -> bool {
CODE_COMMENT_END_PATTERN.is_match(line)
}
pub fn is_code_backticks_start(line: &str) -> Option<regex::Captures<'_>> {
CODE_BACKTICKS_START_PATTERN.captures(line)
}
pub fn is_code_backticks_end(line: &str) -> bool {
CODE_BACKTICKS_END_PATTERN.is_match(line)
}
pub fn remove_md_comment(line: &str) -> Option<String> {
let trimmed = line.trim();
if trimmed.starts_with("<!-- ") && trimmed.ends_with(" -->") {
Some(trimmed[5..trimmed.len() - 4].to_string())
} else {
None
}
}
pub fn get_indent(line: &str) -> String {
let trimmed = line.trim_start();
line[..line.len() - trimmed.len()].to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_md_comment() {
assert_eq!(md_comment("test"), "<!-- test -->");
}
#[test]
fn test_remove_md_comment() {
assert_eq!(
remove_md_comment("<!-- This is a comment -->"),
Some("This is a comment".to_string())
);
assert_eq!(remove_md_comment("This is not a comment"), None);
}
#[test]
fn test_is_skip() {
assert!(is_skip("<!-- CODE:SKIP -->"));
assert!(is_skip(" <!-- CODE:SKIP -->"));
assert!(!is_skip("some text"));
}
#[test]
fn test_get_indent() {
assert_eq!(get_indent(" hello"), " ");
assert_eq!(get_indent("hello"), "");
assert_eq!(get_indent("\t\thello"), "\t\t");
}
#[test]
fn test_is_code_backticks_start() {
let caps = is_code_backticks_start("```python markdown-code-runner");
assert!(caps.is_some());
let caps = caps.unwrap();
assert_eq!(&caps["language"], "python");
let caps = is_code_backticks_start(" ```bash markdown-code-runner filename=test.sh");
assert!(caps.is_some());
let caps = caps.unwrap();
assert_eq!(&caps["language"], "bash");
assert_eq!(&caps["spaces"], " ");
assert!(is_code_backticks_start("```python").is_none());
}
}