summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/plugins/watch_filesystem.rs
blob: 9ac0a320c272c6da3fb745721454b3ed9384b596 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use super::PluginInstruction;
use std::path::PathBuf;

use crate::thread_bus::ThreadSenders;
use std::path::Path;
use std::time::Duration;

use zellij_utils::notify_debouncer_full::{
    new_debouncer,
    notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher},
    DebounceEventResult, Debouncer, FileIdMap,
};
use zellij_utils::{data::Event, errors::prelude::Result};

const DEBOUNCE_DURATION_MS: u64 = 500;

pub fn watch_filesystem(
    senders: ThreadSenders,
    zellij_cwd: &Path,
) -> Result<Debouncer<RecommendedWatcher, FileIdMap>> {
    let path_prefix_in_plugins = PathBuf::from("/host");
    let current_dir = PathBuf::from(zellij_cwd);
    let mut debouncer = new_debouncer(
        Duration::from_millis(DEBOUNCE_DURATION_MS),
        None,
        move |result: DebounceEventResult| match result {
            Ok(events) => {
                let mut create_events = vec![];
                let mut read_events = vec![];
                let mut update_events = vec![];
                let mut delete_events = vec![];
                for event in events {
                    match event.kind {
                        EventKind::Access(_) => read_events.push(event),
                        EventKind::Create(_) => create_events.push(event),
                        EventKind::Modify(_) => update_events.push(event),
                        EventKind::Remove(_) => delete_events.push(event),
                        _ => {},
                    }
                }
                let create_paths: Vec<PathBuf> = create_events
                    .drain(..)
                    .map(|e| {
                        e.paths
                            .iter()
                            .map(|p| {
                                let stripped_prefix_path =
                                    p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
                                path_prefix_in_plugins.join(stripped_prefix_path)
                            })
                            .collect()
                    })
                    .collect();
                let read_paths: Vec<PathBuf> = read_events
                    .drain(..)
                    .map(|e| {
                        e.paths
                            .iter()
                            .map(|p| {
                                let stripped_prefix_path =
                                    p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
                                path_prefix_in_plugins.join(stripped_prefix_path)
                            })
                            .collect()
                    })
                    .collect();
                let update_paths: Vec<PathBuf> = update_events
                    .drain(..)
                    .map(|e| {
                        e.paths
                            .iter()
                            .map(|p| {
                                let stripped_prefix_path =
                                    p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
                                path_prefix_in_plugins.join(stripped_prefix_path)
                            })
                            .collect()
                    })
                    .collect();
                let delete_paths: Vec<PathBuf> = delete_events
                    .drain(..)
                    .map(|e| {
                        e.paths
                            .iter()
                            .map(|p| {
                                let stripped_prefix_path =
                                    p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
                                path_prefix_in_plugins.join(stripped_prefix_path)
                            })
                            .collect()
                    })
                    .collect();
                let _ = senders.send_to_plugin(PluginInstruction::Update(vec![
                    (None, None, Event::FileSystemRead(read_paths)),
                    (None, None, Event::FileSystemCreate(create_paths)),
                    (None, None, Event::FileSystemUpdate(update_paths)),
                    (None, None, Event::FileSystemDelete(delete_paths)),
                ]));
            },
            Err(errors) => errors
                .iter()
                .for_each(|error| log::error!("watch error: {error:?}")),
        },
    )?;

    debouncer
        .watcher()
        .watch(zellij_cwd, RecursiveMode::Recursive)?;
    Ok(debouncer)
}