rullst_core/error_console/
parser.rs1use serde::{Deserialize, Serialize};
4use std::fs;
5use std::path::Path;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct StackFrame {
10 pub file: String,
12 pub line: u32,
14 pub function: String,
16}
17
18#[cfg_attr(mutants, mutants::skip)]
20pub fn find_source_location(bt_str: &str) -> Option<(String, u32)> {
21 for line in bt_str.lines() {
22 let trimmed = line.trim();
23 if trimmed.contains("at ")
24 && (trimmed.contains("/src/")
25 || trimmed.contains("\\src\\")
26 || trimmed.contains("/examples/")
27 || trimmed.contains("\\examples\\")
28 || trimmed.contains("/tests/")
29 || trimmed.contains("\\tests\\"))
30 {
31 if let Some(pos) = trimmed.find("at ") {
33 let path_part = &trimmed[pos + 3..];
34 if let Some((file, line_str)) = path_part.rsplit_once(':')
35 && let Ok(line_num) = line_str.trim().parse::<u32>()
36 {
37 return Some((file.trim().to_string(), line_num));
38 }
39 }
40 }
41 }
42 None
43}
44
45#[cfg_attr(mutants, mutants::skip)]
47pub fn extract_source_context(
48 file_path: &str,
49 target_line: u32,
50 range: u32,
51) -> Option<Vec<(u32, String, bool)>> {
52 let project_root = std::env::current_dir()
53 .map(|cwd| cwd.canonicalize().unwrap_or(cwd))
54 .ok()?;
55
56 let target_path = Path::new(file_path);
57 if target_path
58 .components()
59 .any(|c| matches!(c, std::path::Component::ParentDir))
60 {
61 return None;
62 }
63
64 let absolute_path = project_root.join(target_path);
65
66 let canonical = absolute_path.canonicalize().ok()?;
67 if !canonical.starts_with(&project_root) {
68 return None;
69 }
70
71 let content = fs::read_to_string(&canonical).ok()?;
72 let lines: Vec<&str> = content.lines().collect();
73
74 let total_lines = lines.len() as u32;
75 let start = if target_line > range {
76 target_line - range
77 } else {
78 1
79 };
80 let end = std::cmp::min(target_line + range, total_lines);
81
82 let mut context = Vec::new();
83 for i in start..=end {
84 if i >= 1 && i <= total_lines {
85 let line_content = lines[(i - 1) as usize].to_string();
86 let is_target = i == target_line;
87 context.push((i, line_content, is_target));
88 }
89 }
90 Some(context)
91}