mindmap 0.1.2

Search your notes at the speed of thought
use std::path::PathBuf;

extern crate fs2;

use crate::{config::MindmapConfig, files, utils};
use anyhow::Result;
use colored::Colorize;
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};

pub struct MindmapWatcher {
    watcher: RecommendedWatcher,
    rx: std::sync::mpsc::Receiver<notify::Result<Event>>,
    config: MindmapConfig,
}

impl MindmapWatcher {
    pub fn handle_create_event(
        &self,
        kind: notify::event::CreateKind,
        paths: Vec<PathBuf>,
    ) -> Result<()> {
        let path_str = paths.first().expect("Path should exist");
        let path = PathBuf::from(path_str);
        if kind == notify::event::CreateKind::File {
            files::recompute_file(&path, &self.config)?;
            println!("File created: {:?}", path);
        }
        Ok(())
    }

    pub fn handle_modify_event(
        &self,
        kind: notify::event::ModifyKind,
        paths: Vec<PathBuf>,
    ) -> Result<()> {
        let path_str = paths.first().expect("Path should exist");
        let path = PathBuf::from(path_str);
        match kind {
            notify::event::ModifyKind::Data(_data) => {
                files::recompute_file(&path, &self.config)?;
                println!("File modified: {:?}", path);
            }
            notify::event::ModifyKind::Name(_name) => {
                if path.exists() {
                    files::recompute_file(&path, &self.config)?;
                    println!("File renamed: {:?}", path);
                } else {
                    files::delete_file(&path, &self.config)?;
                    println!("File deleted: {:?}", path);
                }
            }
            _ => {}
        }
        Ok(())
    }

    pub fn handle_remove_event(
        &self,
        kind: notify::event::RemoveKind,
        paths: Vec<PathBuf>,
    ) -> Result<()> {
        let path_str = paths.first().expect("Path should exist");
        let path = PathBuf::from(path_str);
        if kind == notify::event::RemoveKind::File {
            println!("File removed: {:?}", path);
            files::delete_file(&path, &self.config)?;
        }
        Ok(())
    }

    pub fn handle_event(&self, event: Event) -> Result<()> {
        match event.kind {
            EventKind::Create(kind) => self.handle_create_event(kind, event.paths),
            EventKind::Modify(kind) => self.handle_modify_event(kind, event.paths),
            EventKind::Remove(kind) => self.handle_remove_event(kind, event.paths),
            _ => Ok(()),
        }
    }

    pub fn new(config: MindmapConfig) -> Self {
        let (tx, rx) = std::sync::mpsc::channel();
        let watcher =
            RecommendedWatcher::new(tx, Config::default()).expect("Failed to create watcher");
        Self {
            watcher,
            rx,
            config,
        }
    }

    pub fn watch(&mut self) -> Result<()> {
        utils::acquire_lock(&self.config.watcher.lock_path)?;

        println!("{}", "Watching files...".blue());
        self.watcher
            .watch(&self.config.data_dir, RecursiveMode::Recursive)?;

        for res in &self.rx {
            match res {
                Ok(event) => {
                    let _ = &self.handle_event(event);
                }
                Err(error) => println!("Error: {:?}", error),
            }
        }

        Ok(())
    }
}