1use std::{
2 collections::HashMap,
3 ops::Range,
4 path::{Path, PathBuf},
5};
6use tempdir::TempDir;
7
8pub fn temp_tree(tree: serde_json::Value) -> TempDir {
9 let dir = TempDir::new("").unwrap();
10 write_tree(dir.path(), tree);
11 dir
12}
13
14fn write_tree(path: &Path, tree: serde_json::Value) {
15 use serde_json::Value;
16 use std::fs;
17
18 if let Value::Object(map) = tree {
19 for (name, contents) in map {
20 let mut path = PathBuf::from(path);
21 path.push(name);
22 match contents {
23 Value::Object(_) => {
24 fs::create_dir(&path).unwrap();
25 write_tree(&path, contents);
26 }
27 Value::Null => {
28 fs::create_dir(&path).unwrap();
29 }
30 Value::String(contents) => {
31 fs::write(&path, contents).unwrap();
32 }
33 _ => {
34 panic!("JSON object must contain only objects, strings, or null");
35 }
36 }
37 }
38 } else {
39 panic!("You must pass a JSON object to this helper")
40 }
41}
42
43pub fn sample_text(rows: usize, cols: usize, start_char: char) -> String {
44 let mut text = String::new();
45 for row in 0..rows {
46 let c: char = (start_char as u32 + row as u32) as u8 as char;
47 let mut line = c.to_string().repeat(cols);
48 if row < rows - 1 {
49 line.push('\n');
50 }
51 text += &line;
52 }
53 text
54}
55
56pub fn marked_text_by(
57 marked_text: &str,
58 markers: Vec<char>,
59) -> (String, HashMap<char, Vec<usize>>) {
60 let mut extracted_markers: HashMap<char, Vec<usize>> = Default::default();
61 let mut unmarked_text = String::new();
62
63 for char in marked_text.chars() {
64 if markers.contains(&char) {
65 let char_offsets = extracted_markers.entry(char).or_insert(Vec::new());
66 char_offsets.push(unmarked_text.len());
67 } else {
68 unmarked_text.push(char);
69 }
70 }
71
72 (unmarked_text, extracted_markers)
73}
74
75pub fn marked_text(marked_text: &str) -> (String, Vec<usize>) {
76 let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['|']);
77 (unmarked_text, markers.remove(&'|').unwrap_or_else(Vec::new))
78}
79
80pub fn marked_text_ranges(
81 marked_text: &str,
82 range_markers: Vec<(char, char)>,
83) -> (String, Vec<Range<usize>>) {
84 let mut marker_chars = Vec::new();
85 for (start, end) in range_markers.iter() {
86 marker_chars.push(*start);
87 marker_chars.push(*end);
88 }
89 let (unmarked_text, markers) = marked_text_by(marked_text, marker_chars);
90 let ranges = range_markers
91 .iter()
92 .map(|(start_marker, end_marker)| {
93 let start = markers.get(start_marker).unwrap()[0];
94 let end = markers.get(end_marker).unwrap()[0];
95 start..end
96 })
97 .collect();
98 (unmarked_text, ranges)
99}