reovim_kernel/panic/
recovery.rs1use std::{fmt::Write, path::PathBuf};
8
9#[derive(Debug)]
11pub struct RecoverySnapshot {
12 pub unsaved_buffers: Vec<UnsavedBuffer>,
14 pub timestamp: std::time::SystemTime,
16}
17
18#[derive(Debug)]
20pub struct UnsavedBuffer {
21 pub id: u32,
23 pub path: Option<PathBuf>,
25 pub content_hash: u64,
27 pub line_count: usize,
29}
30
31#[must_use]
35pub fn recovery_dir() -> PathBuf {
36 reovim_arch::dirs::data_local_dir()
37 .unwrap_or_else(|| PathBuf::from("."))
38 .join("reovim")
39 .join("recovery")
40}
41
42pub fn save_buffer_for_recovery(
69 buffer_id: u32,
70 original_path: Option<&std::path::Path>,
71 content: &str,
72) -> std::io::Result<PathBuf> {
73 let dir = recovery_dir();
74 std::fs::create_dir_all(&dir)?;
75
76 let filename = format!(
77 "buffer-{}-{}.txt",
78 buffer_id,
79 std::time::SystemTime::now()
80 .duration_since(std::time::UNIX_EPOCH)
81 .map_or(0, |d| d.as_secs())
82 );
83
84 let path = dir.join(&filename);
85
86 let mut output = String::new();
88 writeln!(output, "# Recovery file for buffer {buffer_id}").ok();
89 if let Some(orig) = original_path {
90 writeln!(output, "# Original path: {}", orig.display()).ok();
91 }
92 writeln!(output, "# Lines: {}", content.lines().count()).ok();
93 output.push_str("# ---\n");
94 output.push_str(content);
95
96 std::fs::write(&path, output)?;
97 Ok(path)
98}
99
100#[cfg_attr(coverage_nightly, coverage(off))]
110pub fn list_recovery_files() -> std::io::Result<Vec<PathBuf>> {
111 let dir = recovery_dir();
112 if !dir.exists() {
113 return Ok(Vec::new());
114 }
115
116 let mut files: Vec<(PathBuf, std::time::SystemTime)> = Vec::new();
117
118 for entry in std::fs::read_dir(dir)? {
119 let entry = entry?;
120 let path = entry.path();
121 if path.extension().is_some_and(|e| e == "txt")
122 && let Ok(meta) = std::fs::metadata(&path)
123 && let Ok(modified) = meta.modified()
124 {
125 files.push((path, modified));
126 }
127 }
128
129 files.sort_by_key(|b| std::cmp::Reverse(b.1));
131
132 Ok(files.into_iter().map(|(p, _)| p).collect())
133}
134
135#[cfg_attr(coverage_nightly, coverage(off))]
153pub fn cleanup_old_recovery_files(max_age_secs: u64) -> std::io::Result<usize> {
154 let now = std::time::SystemTime::now();
155 let mut removed = 0;
156
157 for path in list_recovery_files()? {
158 if let Ok(meta) = std::fs::metadata(&path)
159 && let Ok(modified) = meta.modified()
160 && let Ok(age) = now.duration_since(modified)
161 && age.as_secs() > max_age_secs
162 {
163 std::fs::remove_file(&path)?;
164 removed += 1;
165 }
166 }
167
168 Ok(removed)
169}