zagens_runtime/repl/
sandbox.rs1pub fn has_repl_block(text: &str) -> bool {
10 text.contains("```repl")
11}
12
13pub fn extract_repl_blocks(text: &str) -> Vec<ReplBlock> {
15 let mut blocks = Vec::new();
16 let mut rest = text;
17
18 while let Some(start_idx) = rest.find("```repl") {
19 let after_fence = &rest[start_idx..];
20 let code_start = after_fence.find('\n').unwrap_or(after_fence.len());
21 let code_region = &after_fence[code_start..];
22 let Some(end_offset) = code_region.find("\n```") else {
23 break;
24 };
25 let code = code_region[..end_offset].to_string();
26 let global_start = text.len() - rest.len() + start_idx;
27 let global_end = global_start + code_start + end_offset + 3;
28 blocks.push(ReplBlock {
29 code,
30 start_offset: global_start,
31 end_offset: global_end,
32 });
33 rest = &after_fence[code_start + end_offset + 4..];
34 }
35
36 blocks
37}
38
39#[derive(Debug, Clone)]
41pub struct ReplBlock {
42 pub code: String,
43 pub start_offset: usize,
44 pub end_offset: usize,
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn has_repl_block_detects_fence() {
53 assert!(has_repl_block("some text ```repl\ncode\n``` more"));
54 assert!(!has_repl_block("no repl here ```python\ncode\n```"));
55 assert!(!has_repl_block("just text"));
56 }
57
58 #[test]
59 fn extract_repl_blocks_single() {
60 let text = "before\n```repl\nprint('hello')\n```\nafter";
61 let blocks = extract_repl_blocks(text);
62 assert_eq!(blocks.len(), 1);
63 assert_eq!(blocks[0].code.trim(), "print('hello')");
64 }
65
66 #[test]
67 fn extract_repl_blocks_multiple() {
68 let text = "```repl\ncode1\n```\nmid\n```repl\ncode2\n```\nend";
69 let blocks = extract_repl_blocks(text);
70 assert_eq!(blocks.len(), 2);
71 assert_eq!(blocks[0].code.trim(), "code1");
72 assert_eq!(blocks[1].code.trim(), "code2");
73 }
74
75 #[test]
76 fn extract_repl_blocks_empty_when_none() {
77 let blocks = extract_repl_blocks("no blocks here");
78 assert!(blocks.is_empty());
79 }
80}