refactor: module infrastructure avec comrak_renderer, file_repository, notify_watcher
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
use notify::EventKind;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::mpsc::RecvTimeoutError;
|
||||
use std::time::{Duration, Instant};
|
||||
use tauri::{AppHandle, Emitter};
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
struct FileChangedPayload {
|
||||
path: String,
|
||||
}
|
||||
|
||||
pub fn run_debounce_loop(
|
||||
rx: std::sync::mpsc::Receiver<notify::Result<notify::Event>>,
|
||||
app: AppHandle,
|
||||
) {
|
||||
let mut pending: HashMap<PathBuf, Instant> = HashMap::new();
|
||||
|
||||
loop {
|
||||
match rx.recv_timeout(Duration::from_millis(10)) {
|
||||
Ok(Ok(event)) => {
|
||||
if matches!(
|
||||
event.kind,
|
||||
EventKind::Modify(_) | EventKind::Create(_) | EventKind::Remove(_)
|
||||
) {
|
||||
for p in event.paths {
|
||||
if is_relevant_path(&p) {
|
||||
pending.insert(p, Instant::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Err(_)) => {}
|
||||
Err(RecvTimeoutError::Timeout) => {}
|
||||
Err(RecvTimeoutError::Disconnected) => break,
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let ready: Vec<PathBuf> = pending
|
||||
.iter()
|
||||
.filter(|(_, t)| now.duration_since(**t) >= Duration::from_millis(80))
|
||||
.map(|(p, _)| p.clone())
|
||||
.collect();
|
||||
|
||||
for p in ready {
|
||||
pending.remove(&p);
|
||||
let _ = app.emit(
|
||||
"file-changed",
|
||||
FileChangedPayload {
|
||||
path: p.to_string_lossy().to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_relevant_path(path: &Path) -> bool {
|
||||
if path
|
||||
.components()
|
||||
.any(|c| c.as_os_str().to_string_lossy().starts_with('.'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path.extension().is_some_and(|e| e == "md")
|
||||
}
|
||||
Reference in New Issue
Block a user