mdBook/src/renderer/html_handlebars/helpers/playpen.rs

207 lines
6.1 KiB
Rust
Raw Normal View History

use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Read;
pub fn render_playpen<P: AsRef<Path>>(s: &str, path: P) -> String {
// When replacing one thing in a string by something with a different length,
// the indices after that will not correspond,
// we therefore have to store the difference to correct this
let mut previous_end_index = 0;
let mut replaced = String::new();
for playpen in find_playpens(s, path) {
if playpen.escaped {
replaced.push_str(&s[previous_end_index..playpen.start_index - 1]);
replaced.push_str(&s[playpen.start_index..playpen.end_index]);
previous_end_index = playpen.end_index;
continue;
}
// Check if the file exists
if !playpen.rust_file.exists() || !playpen.rust_file.is_file() {
2016-08-14 21:40:08 +08:00
warn!("[-] No file exists for {{{{#playpen }}}}\n {}", playpen.rust_file.to_str().unwrap());
continue;
}
// Open file & read file
let mut file = if let Ok(f) = File::open(&playpen.rust_file) {
f
} else {
continue;
};
let mut file_content = String::new();
if file.read_to_string(&mut file_content).is_err() {
continue;
};
let mut editable = "";
if playpen.editable {
editable = ",editable";
}
let replacement = String::new() + "``` rust" + editable + "\n" + &file_content + "\n```\n";
replaced.push_str(&s[previous_end_index..playpen.start_index]);
replaced.push_str(&replacement);
previous_end_index = playpen.end_index;
// println!("Playpen{{ {}, {}, {:?}, {} }}", playpen.start_index,
// playpen.end_index, playpen.rust_file,
// playpen.editable);
}
replaced.push_str(&s[previous_end_index..]);
replaced
}
2015-12-31 19:00:09 +08:00
#[derive(PartialOrd, PartialEq, Debug)]
struct Playpen {
start_index: usize,
end_index: usize,
rust_file: PathBuf,
editable: bool,
escaped: bool,
}
fn find_playpens<P: AsRef<Path>>(s: &str, base_path: P) -> Vec<Playpen> {
let base_path = base_path.as_ref();
let mut playpens = vec![];
for (i, _) in s.match_indices("{{#playpen") {
debug!("[*]: find_playpen");
let mut escaped = false;
if i > 0 {
if let Some(c) = s[i - 1..].chars().nth(0) {
if c == '\\' {
escaped = true
}
}
}
// DON'T forget the "+ i" else you have an index out of bounds error !!
let end_i = if let Some(n) = s[i..].find("}}") {
n
} else {
continue;
} + i + 2;
debug!("s[{}..{}] = {}", i, end_i, s[i..end_i].to_string());
// If there is nothing between "{{#playpen" and "}}" skip
if end_i - 2 - (i + 10) < 1 {
continue;
}
if s[i + 10..end_i - 2].trim().is_empty() {
continue;
}
debug!("{}", s[i + 10..end_i - 2].to_string());
// Split on whitespaces
let params: Vec<&str> = s[i + 10..end_i - 2].split_whitespace().collect();
let editable = params
.get(1)
.map(|p| p.find("editable").is_some())
.unwrap_or(false);
playpens.push(Playpen {
start_index: i,
end_index: end_i,
rust_file: base_path.join(PathBuf::from(params[0])),
editable: editable,
escaped: escaped,
})
}
playpens
}
2015-12-31 19:00:09 +08:00
// ---------------------------------------------------------------------------------
2015-12-31 19:00:09 +08:00
// Tests
//
#[test]
fn test_find_playpens_no_playpen() {
let s = "Some random text without playpen...";
assert!(find_playpens(s, "") == vec![]);
2015-12-31 19:00:09 +08:00
}
#[test]
fn test_find_playpens_partial_playpen() {
let s = "Some random text with {{#playpen...";
assert!(find_playpens(s, "") == vec![]);
2015-12-31 19:00:09 +08:00
}
#[test]
fn test_find_playpens_empty_playpen() {
let s = "Some random text with {{#playpen}} and {{#playpen }}...";
assert!(find_playpens(s, "") == vec![]);
2015-12-31 19:00:09 +08:00
}
#[test]
fn test_find_playpens_simple_playpen() {
let s = "Some random text with {{#playpen file.rs}} and {{#playpen test.rs }}...";
println!("\nOUTPUT: {:?}\n", find_playpens(s, ""));
2015-12-31 19:00:09 +08:00
assert!(find_playpens(s, "") ==
vec![Playpen {
start_index: 22,
end_index: 42,
rust_file: PathBuf::from("file.rs"),
editable: false,
escaped: false,
},
Playpen {
start_index: 47,
end_index: 68,
rust_file: PathBuf::from("test.rs"),
editable: false,
escaped: false,
}]);
2015-12-31 19:00:09 +08:00
}
#[test]
fn test_find_playpens_complex_playpen() {
let s = "Some random text with {{#playpen file.rs editable}} and {{#playpen test.rs editable }}...";
println!("\nOUTPUT: {:?}\n", find_playpens(s, "dir"));
2015-12-31 19:00:09 +08:00
assert!(find_playpens(s, "dir") ==
vec![Playpen {
start_index: 22,
end_index: 51,
rust_file: PathBuf::from("dir/file.rs"),
editable: true,
escaped: false,
},
Playpen {
start_index: 56,
end_index: 86,
rust_file: PathBuf::from("dir/test.rs"),
editable: true,
escaped: false,
}]);
}
#[test]
fn test_find_playpens_escaped_playpen() {
let s = "Some random text with escaped playpen \\{{#playpen file.rs editable}} ...";
println!("\nOUTPUT: {:?}\n", find_playpens(s, ""));
assert!(find_playpens(s, "") ==
vec![Playpen {
start_index: 39,
end_index: 68,
rust_file: PathBuf::from("file.rs"),
editable: true,
escaped: true,
}]);
2015-12-31 19:00:09 +08:00
}