Add WIP change detection

change-detection
trivernis 2 years ago
parent 817c2a7e6d
commit eda2ae2f18
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

90
Cargo.lock generated

@ -140,6 +140,16 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "crossbeam-channel"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.11" version = "0.8.11"
@ -260,6 +270,18 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "filetime"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"windows-sys",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -275,6 +297,15 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.24" version = "0.3.24"
@ -483,6 +514,7 @@ dependencies = [
"ignore", "ignore",
"indoc", "indoc",
"log", "log",
"notify",
"once_cell", "once_cell",
"pulldown-cmark", "pulldown-cmark",
"serde", "serde",
@ -594,6 +626,26 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3"
[[package]]
name = "inotify"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
dependencies = [
"bitflags",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -618,6 +670,26 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "kqueue"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
dependencies = [
"bitflags",
"libc",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -699,6 +771,24 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "notify"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
dependencies = [
"bitflags",
"crossbeam-channel",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"mio",
"walkdir",
"winapi",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.45"

@ -66,6 +66,7 @@ serde = { version = "1.0", features = ["derive"] }
# ripgrep for global search # ripgrep for global search
grep-regex = "0.1.10" grep-regex = "0.1.10"
grep-searcher = "0.1.10" grep-searcher = "0.1.10"
notify = "5.0.0"
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }

@ -1370,6 +1370,7 @@ impl Component for EditorView {
if let Some(explore) = self.explorer.as_mut() { if let Some(explore) = self.explorer.as_mut() {
if !explore.content.is_focus() && config.explorer.is_embed() { if !explore.content.is_focus() && config.explorer.is_embed() {
explore.content.handle_changes(cx).unwrap();
let current_doc = view!(cx.editor).doc; let current_doc = view!(cx.editor).doc;
let current_doc = cx.editor.document(current_doc).unwrap(); let current_doc = cx.editor.document(current_doc).unwrap();
if let Some(path) = current_doc.path() { if let Some(path) = current_doc.path() {

@ -11,9 +11,10 @@ use helix_view::{
input::{Event, KeyEvent}, input::{Event, KeyEvent},
Editor, Editor,
}; };
use std::borrow::Cow; use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::cmp::Ordering;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::{borrow::Cow, sync::mpsc::channel};
use std::{cmp::Ordering, sync::mpsc::Receiver};
use tui::{ use tui::{
buffer::Buffer as Surface, buffer::Buffer as Surface,
text::{Span, Spans}, text::{Span, Spans},
@ -238,39 +239,6 @@ impl TreeItem for FileInfo {
} }
} }
// #[derive(Default, Debug, Clone)]
// struct PathState {
// root: PathBuf,
// sub_items: Vec<FileInfo>,
// selected: usize,
// save_view: (usize, usize), // (selected, row)
// row: usize,
// col: usize,
// max_len: usize,
// }
// impl PathState {
// fn mkdir(&mut self, dir: &str) -> Result<()> {
// self.new_path(dir, FileType::Dir)
// }
// fn create_file(&mut self, f: &str) -> Result<()> {
// self.new_path(f, FileType::File)
// }
// fn remove_current_file(&mut self) -> Result<()> {
// let item = &self.sub_items[self.selected];
// std::fs::remove_file(item.path_with_root(&self.root))?;
// self.sub_items.remove(self.selected);
// if self.selected >= self.sub_items.len() {
// self.selected = self.sub_items.len() - 1;
// }
// Ok(())
// }
// }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
enum PromptAction { enum PromptAction {
Search(bool), // search next/search pre Search(bool), // search next/search pre
@ -304,12 +272,17 @@ pub struct Explorer {
on_next_key: Option<Box<dyn FnMut(&mut Context, &mut Self, &KeyEvent) -> EventResult>>, on_next_key: Option<Box<dyn FnMut(&mut Context, &mut Self, &KeyEvent) -> EventResult>>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
repeat_motion: Option<Box<dyn FnMut(&mut Self, PromptAction, &mut Context) + 'static>>, repeat_motion: Option<Box<dyn FnMut(&mut Self, PromptAction, &mut Context) + 'static>>,
watcher: RecommendedWatcher,
io_events: Receiver<Result<notify::Event, notify::Error>>,
} }
impl Explorer { impl Explorer {
pub fn new(cx: &mut Context) -> Result<Self> { pub fn new(cx: &mut Context) -> Result<Self> {
let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into()); let current_root = std::env::current_dir().unwrap_or_else(|_| "./".into());
let items = Self::get_items(current_root.clone(), cx)?; let items = Self::get_items(current_root.clone(), cx)?;
let (mut watcher, receiver) = Self::create_watcher()?;
watcher.watch(&current_root, RecursiveMode::Recursive)?;
Ok(Self { Ok(Self {
tree: Tree::build_tree(items) tree: Tree::build_tree(items)
.with_enter_fn(Self::toggle_current) .with_enter_fn(Self::toggle_current)
@ -318,6 +291,8 @@ impl Explorer {
repeat_motion: None, repeat_motion: None,
prompt: None, prompt: None,
on_next_key: None, on_next_key: None,
watcher,
io_events: receiver,
}) })
} }
@ -339,25 +314,20 @@ impl Explorer {
.with_enter_fn(Self::toggle_current) .with_enter_fn(Self::toggle_current)
.with_folded_fn(Self::fold_current); .with_folded_fn(Self::fold_current);
tree.insert_current_level(parent); tree.insert_current_level(parent);
let (mut watcher, receiver) = Self::create_watcher()?;
watcher.watch(&current_root, RecursiveMode::Recursive)?;
Ok(Self { Ok(Self {
tree, tree,
state: State::new(true, current_root), state: State::new(true, current_root),
repeat_motion: None, repeat_motion: None,
prompt: None, prompt: None,
on_next_key: None, on_next_key: None,
watcher,
io_events: receiver,
}) })
// let mut root = vec![, FileInfo::root(p)];
} }
// pub fn new_with_uri(uri: String) -> Result<Self> {
// // support remote file?
// let p = Path::new(&uri);
// ensure!(p.exists(), "path: {uri} is not exist");
// ensure!(p.is_dir(), "path: {uri} is not dir");
// Ok(Self::default().with_list(get_sub(p, None)?))
// }
pub fn focus(&mut self) { pub fn focus(&mut self) {
self.state.focus = true self.state.focus = true
} }
@ -381,6 +351,24 @@ impl Explorer {
Ok(items) Ok(items)
} }
pub fn handle_changes(&mut self, cx: &mut Context) -> Result<()> {
if let Ok(o) = self.io_events.try_recv() {
match o {
Ok(_) => self.refresh(cx),
Err(e) => Err(e.into()),
}
} else {
Ok(())
}
}
fn refresh(&mut self, cx: &mut Context) -> Result<()> {
let items = Self::get_items(self.state.current_root.clone(), cx)?;
self.tree.replace_with_new_items(items);
Ok(())
}
fn render_preview(&mut self, area: Rect, surface: &mut Surface, editor: &Editor) { fn render_preview(&mut self, area: Rect, surface: &mut Surface, editor: &Editor) {
if area.height <= 2 || area.width < 60 { if area.height <= 2 || area.width < 60 {
return; return;
@ -422,6 +410,28 @@ impl Explorer {
} }
} }
fn watch(&mut self, path: &Path) -> Result<()> {
self.watcher.watch(path, RecursiveMode::Recursive)?;
Ok(())
}
fn unwatch(&mut self, path: &Path) -> Result<()> {
self.watcher.unwatch(path)?;
Ok(())
}
fn create_watcher() -> Result<(
RecommendedWatcher,
Receiver<Result<notify::Event, notify::Error>>,
)> {
let (tx, rx) = channel();
let watcher = RecommendedWatcher::new(tx, Config::default())?;
Ok((watcher, rx))
}
fn new_search_prompt(&mut self, search_next: bool) { fn new_search_prompt(&mut self, search_next: bool) {
self.tree.save_view(); self.tree.save_view();
self.prompt = Some(( self.prompt = Some((

Loading…
Cancel
Save