From 6380a4dfa44bee3be79210e5a0287d4f0353fc55 Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Mon, 9 May 2022 14:26:01 +0100 Subject: [PATCH] improve file explorer watch --- lapce-data/src/command.rs | 2 +- lapce-data/src/data.rs | 134 +++++++----------------- lapce-data/src/explorer.rs | 89 ++++++++++++---- lapce-data/src/picker.rs | 36 ++++++- lapce-proxy/src/dispatch.rs | 61 +++++++---- lapce-rpc/src/file.rs | 6 +- lapce-rpc/src/proxy.rs | 11 +- lapce-ui/src/explorer.rs | 24 +---- lapce-ui/src/picker.rs | 198 ++---------------------------------- lapce-ui/src/tab.rs | 23 ++--- 10 files changed, 214 insertions(+), 370 deletions(-) diff --git a/lapce-data/src/command.rs b/lapce-data/src/command.rs index cbe03d57..deb45eac 100644 --- a/lapce-data/src/command.rs +++ b/lapce-data/src/command.rs @@ -383,7 +383,7 @@ pub enum LapceUICommand { FilterKeymaps(String, Arc>, Arc>), UpdatePickerPwd(PathBuf), UpdatePickerItems(PathBuf, HashMap), - UpdateExplorerItems(usize, PathBuf, Vec), + UpdateExplorerItems(PathBuf, HashMap, bool), UpdateInstalledPlugins(HashMap), UpdatePluginDescriptions(Vec), RequestLayout, diff --git a/lapce-data/src/data.rs b/lapce-data/src/data.rs index 73947d71..13ca6e7f 100644 --- a/lapce-data/src/data.rs +++ b/lapce-data/src/data.rs @@ -25,8 +25,7 @@ selection::Selection, }; use lapce_rpc::{ - file::FileNodeItem, plugin::PluginDescription, source_control::FileDiff, - terminal::TermId, + plugin::PluginDescription, source_control::FileDiff, terminal::TermId, }; use lsp_types::{ CodeActionOrCommand, Diagnostic, Position, ProgressToken, TextEdit, @@ -1039,37 +1038,12 @@ pub fn run_workbench_command( if let Some(node) = picker.root.get_file_node(&picker.pwd) { if !node.read { let tab_id = self.id; - let path = node.path_buf.clone(); let event_sink = ctx.get_external_handle(); - self.proxy.read_dir( + FilePickerData::read_dir( &node.path_buf, - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result< - Vec, - serde_json::Error, - > = serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdatePickerItems( - path, - items - .iter() - .map(|item| { - ( - item.path_buf - .clone(), - item.clone(), - ) - }) - .collect(), - ), - Target::Widget(tab_id), - ); - } - } - }), + tab_id, + &self.proxy, + event_sink, ); } } @@ -1110,37 +1084,12 @@ pub fn run_workbench_command( if let Some(node) = picker.root.get_file_node(&picker.pwd) { if !node.read { let tab_id = self.id; - let path = node.path_buf.clone(); let event_sink = ctx.get_external_handle(); - self.proxy.read_dir( + FilePickerData::read_dir( &node.path_buf, - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result< - Vec, - serde_json::Error, - > = serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdatePickerItems( - path, - items - .iter() - .map(|item| { - ( - item.path_buf - .clone(), - item.clone(), - ) - }) - .collect(), - ), - Target::Widget(tab_id), - ); - } - } - }), + tab_id, + &self.proxy, + event_sink, ); } } @@ -1668,30 +1617,7 @@ pub fn read_picker_pwd(&mut self, ctx: &mut EventCtx) { let path = self.picker.pwd.clone(); let event_sink = ctx.get_external_handle(); let tab_id = self.id; - self.proxy.read_dir( - &path.clone(), - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result, serde_json::Error> = - serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdatePickerItems( - path, - items - .iter() - .map(|item| { - (item.path_buf.clone(), item.clone()) - }) - .collect(), - ), - Target::Widget(tab_id), - ); - } - } - }), - ); + FilePickerData::read_dir(&path, tab_id, &self.proxy, event_sink); } pub fn set_picker_pwd(&mut self, pwd: PathBuf) { @@ -1729,27 +1655,39 @@ pub fn set_picker_pwd(&mut self, pwd: PathBuf) { } } - pub fn handle_file_change(&mut self, event: ¬ify::Event) { - if let Some(workspace) = - Arc::make_mut(&mut self.file_explorer).workspace.as_mut() - { + pub fn handle_file_change(&mut self, ctx: &mut EventCtx, event: ¬ify::Event) { + if self.file_explorer.workspace.is_some() { match &event.kind { - notify::EventKind::Create(creat_kind) => { + notify::EventKind::Create(_) + | notify::EventKind::Modify(notify::event::ModifyKind::Name(_)) + | notify::EventKind::Remove(_) => { for path in event.paths.iter() { - workspace.add_child( - path, - creat_kind == ¬ify::event::CreateKind::Folder, - ); - } - } - notify::EventKind::Remove(_) => { - for path in event.paths.iter() { - workspace.remove_child(path); + if let Some(path) = path.parent() { + FileExplorerData::read_dir( + path, + false, + self.id, + &self.proxy, + ctx.get_external_handle(), + ); + } } } _ => {} } } + + // let doc = self + // .main_split + // .local_docs + // .get_mut(&LocalBufferKind::Search) + // .unwrap(); + // let pattern = doc.buffer().text().to_string(); + // ctx.submit_command(Command::new( + // LAPCE_UI_COMMAND, + // LapceUICommand::UpdateSearch(pattern), + // Target::Widget(self.id), + // )); } } diff --git a/lapce-data/src/explorer.rs b/lapce-data/src/explorer.rs index 1f5af3b2..5904ad84 100644 --- a/lapce-data/src/explorer.rs +++ b/lapce-data/src/explorer.rs @@ -8,6 +8,7 @@ use include_dir::{include_dir, Dir}; use lapce_rpc::file::FileNodeItem; +use lapce_rpc::proxy::ReadDirResponse; use crate::data::LapceWorkspace; use crate::proxy::LapceProxy; @@ -46,29 +47,9 @@ pub fn new( children: HashMap::new(), children_open_count: 0, }); - let index = 0; let path = path.clone(); std::thread::spawn(move || { - proxy.read_dir( - &path.clone(), - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result, serde_json::Error> = - serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdateExplorerItems( - index, - path.clone(), - items, - ), - Target::Widget(tab_id), - ); - } - } - }), - ); + Self::read_dir(&path, true, tab_id, &proxy, event_sink); }); } Self { @@ -133,6 +114,72 @@ pub fn get_node_mut(&mut self, path: &Path) -> Option<&mut FileNodeItem> { } Some(node) } + + pub fn update_children( + &mut self, + path: &Path, + children: HashMap, + expand: bool, + ) -> Option<()> { + let node = self.workspace.as_mut()?.get_file_node_mut(path)?; + + let removed_paths: Vec = node + .children + .keys() + .filter(|p| !children.contains_key(*p)) + .map(PathBuf::from) + .collect(); + for path in removed_paths { + node.children.remove(&path); + } + + for (path, child) in children.into_iter() { + if !node.children.contains_key(&path) { + node.children.insert(child.path_buf.clone(), child); + } + } + + node.read = true; + if expand { + node.open = true; + } + + for p in path.ancestors() { + self.update_node_count(p); + } + + Some(()) + } + + pub fn read_dir( + path: &Path, + expand: bool, + tab_id: WidgetId, + proxy: &LapceProxy, + event_sink: ExtEventSink, + ) { + let path = PathBuf::from(path); + let local_path = path.clone(); + proxy.read_dir( + &local_path, + Box::new(move |result| { + if let Ok(res) = result { + let path = path.clone(); + let resp: Result = + serde_json::from_value(res); + if let Ok(resp) = resp { + let _ = event_sink.submit_command( + LAPCE_UI_COMMAND, + LapceUICommand::UpdateExplorerItems( + path, resp.items, expand, + ), + Target::Widget(tab_id), + ); + } + } + }), + ); + } } pub fn get_item_children( diff --git a/lapce-data/src/picker.rs b/lapce-data/src/picker.rs index 01724fbf..3a1b3620 100644 --- a/lapce-data/src/picker.rs +++ b/lapce-data/src/picker.rs @@ -3,8 +3,13 @@ path::{Path, PathBuf}, }; -use druid::WidgetId; -use lapce_rpc::file::FileNodeItem; +use druid::{ExtEventSink, Target, WidgetId}; +use lapce_rpc::{file::FileNodeItem, proxy::ReadDirResponse}; + +use crate::{ + command::{LapceUICommand, LAPCE_UI_COMMAND}, + proxy::LapceProxy, +}; #[derive(Clone)] pub struct FilePickerData { @@ -73,6 +78,33 @@ pub fn init_home(&mut self, home: &Path) { self.root = current_file_node; self.pwd = home.to_path_buf(); } + + pub fn read_dir( + path: &Path, + tab_id: WidgetId, + proxy: &LapceProxy, + event_sink: ExtEventSink, + ) { + let path = PathBuf::from(path); + let local_path = path.clone(); + proxy.read_dir( + &local_path, + Box::new(move |result| { + if let Ok(res) = result { + let path = path.clone(); + let resp: Result = + serde_json::from_value(res); + if let Ok(resp) = resp { + let _ = event_sink.submit_command( + LAPCE_UI_COMMAND, + LapceUICommand::UpdatePickerItems(path, resp.items), + Target::Widget(tab_id), + ); + } + } + }), + ); + } } impl Default for FilePickerData { diff --git a/lapce-proxy/src/dispatch.rs b/lapce-proxy/src/dispatch.rs index 59c4eb87..bb176066 100644 --- a/lapce-proxy/src/dispatch.rs +++ b/lapce-proxy/src/dispatch.rs @@ -15,7 +15,7 @@ use lapce_rpc::buffer::{BufferHeadResponse, BufferId, NewBufferResponse}; use lapce_rpc::core::CoreNotification; use lapce_rpc::file::FileNodeItem; -use lapce_rpc::proxy::{ProxyNotification, ProxyRequest}; +use lapce_rpc::proxy::{ProxyNotification, ProxyRequest, ReadDirResponse}; use lapce_rpc::source_control::{DiffInfo, FileDiff}; use lapce_rpc::terminal::TermId; use lapce_rpc::{self, Call, RequestId, RpcObject}; @@ -95,12 +95,9 @@ fn handle_event(&mut self, event: notify::Result) { notify::EventKind::Create(_) | notify::EventKind::Modify(_) | notify::EventKind::Remove(_) => { - let notification = - serde_json::to_value(&CoreNotification::FileChange { - event, - }) - .unwrap(); - self.send_rpc_notification(notification); + self.send_rpc_notification(CoreNotification::FileChange { + event, + }); if let Some(workspace) = self.workspace.lock().clone() { if let Some(diff) = git_diff_new(&workspace) { @@ -271,8 +268,28 @@ pub fn respond(&self, id: RequestId, result: Result) { let _ = self.sender.send(resp); } - pub fn send_rpc_notification(&self, notification: Value) { - let _ = self.sender.send(notification); + pub fn respond_rpc( + &self, + id: RequestId, + result: Result, + ) { + let mut resp = json!({ "id": id }); + match result { + Ok(v) => resp["result"] = serde_json::to_value(v).unwrap(), + Err(e) => { + resp["error"] = json!({ + "code": 0, + "message": format!("{}",e), + }) + } + } + let _ = self.sender.send(resp); + } + + pub fn send_rpc_notification(&self, notification: T) { + let _ = self + .sender + .send(serde_json::to_value(notification).unwrap()); } pub fn send_notification(&self, method: &str, params: Value) { @@ -510,21 +527,27 @@ fn handle_request(&self, id: RequestId, rpc: ProxyRequest) { .into_iter() .filter_map(|entry| { entry - .map(|e| FileNodeItem { - path_buf: e.path(), - is_dir: e.path().is_dir(), - open: false, - read: false, - children: HashMap::new(), - children_open_count: 0, + .map(|e| { + ( + e.path(), + FileNodeItem { + path_buf: e.path(), + is_dir: e.path().is_dir(), + open: false, + read: false, + children: HashMap::new(), + children_open_count: 0, + }, + ) }) .ok() }) - .collect::>(); - serde_json::to_value(items).unwrap() + .collect::>(); + + ReadDirResponse { items } }) .map_err(|e| anyhow!(e)); - local_dispatcher.respond(id, result); + local_dispatcher.respond_rpc(id, result); }); } GetFiles { .. } => { diff --git a/lapce-rpc/src/file.rs b/lapce-rpc/src/file.rs index 3460c484..152fbba7 100644 --- a/lapce-rpc/src/file.rs +++ b/lapce-rpc/src/file.rs @@ -110,15 +110,15 @@ pub fn get_file_node_mut(&mut self, path: &Path) -> Option<&mut FileNodeItem> { node } - pub fn remove_child(&mut self, path: &Path) -> Option<()> { + pub fn remove_child(&mut self, path: &Path) -> Option { let parent = path.parent()?; let node = self.get_file_node_mut(parent)?; - node.children.remove(path)?; + let node = node.children.remove(path)?; for p in path.ancestors() { self.update_node_count(p); } - Some(()) + Some(node) } pub fn add_child(&mut self, path: &Path, is_dir: bool) -> Option<()> { diff --git a/lapce-rpc/src/proxy.rs b/lapce-rpc/src/proxy.rs index 71ec5ddc..b0c42e53 100644 --- a/lapce-rpc/src/proxy.rs +++ b/lapce-rpc/src/proxy.rs @@ -1,12 +1,12 @@ -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use lsp_types::{CompletionItem, Position}; use serde::{Deserialize, Serialize}; use xi_rope::RopeDelta; use crate::{ - buffer::BufferId, plugin::PluginDescription, source_control::FileDiff, - terminal::TermId, + buffer::BufferId, file::FileNodeItem, plugin::PluginDescription, + source_control::FileDiff, terminal::TermId, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -111,3 +111,8 @@ pub enum ProxyRequest { buffer_id: BufferId, }, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ReadDirResponse { + pub items: HashMap, +} diff --git a/lapce-ui/src/explorer.rs b/lapce-ui/src/explorer.rs index cd24c5ad..69b196fc 100644 --- a/lapce-ui/src/explorer.rs +++ b/lapce-ui/src/explorer.rs @@ -411,27 +411,13 @@ fn event( node.open = !node.open; } else { let tab_id = data.id; - let path = node.path_buf.clone(); let event_sink = ctx.get_external_handle(); - data.proxy.read_dir( + FileExplorerData::read_dir( &node.path_buf, - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result< - Vec, - serde_json::Error, - > = serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdateExplorerItems( - index, path, items, - ), - Target::Widget(tab_id), - ); - } - } - }), + true, + tab_id, + &data.proxy, + event_sink, ); } let path = node.path_buf.clone(); diff --git a/lapce-ui/src/picker.rs b/lapce-ui/src/picker.rs index 41376d0d..96e0184f 100644 --- a/lapce-ui/src/picker.rs +++ b/lapce-ui/src/picker.rs @@ -1,8 +1,4 @@ -use std::{ - collections::HashMap, - path::{Path, PathBuf}, - sync::Arc, -}; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; use druid::{ kurbo::Line, @@ -15,6 +11,7 @@ command::{LapceUICommand, LAPCE_UI_COMMAND}, config::{Config, LapceTheme}, data::LapceTabData, + picker::FilePickerData, }; use lapce_rpc::file::FileNodeItem; @@ -26,131 +23,6 @@ tab::LapceButton, }; -#[derive(Clone)] -pub struct FilePickerData { - pub widget_id: WidgetId, - pub editor_view_id: WidgetId, - pub active: bool, - root: FileNodeItem, - pub home: PathBuf, - pub pwd: PathBuf, -} - -impl FilePickerData { - pub fn new() -> Self { - let root = FileNodeItem { - path_buf: PathBuf::from("/"), - is_dir: true, - read: false, - open: false, - children: HashMap::new(), - children_open_count: 0, - }; - let home = PathBuf::from("/"); - let pwd = PathBuf::from("/"); - Self { - widget_id: WidgetId::next(), - editor_view_id: WidgetId::next(), - active: false, - root, - home, - pwd, - } - } - - pub fn set_item_children( - &mut self, - path: &Path, - children: HashMap, - ) { - if let Some(node) = self.get_file_node_mut(path) { - node.open = true; - node.read = true; - node.children = children; - } - - for p in path.ancestors() { - self.update_node_count(&PathBuf::from(p)); - } - } - - pub fn init_home(&mut self, home: &Path) { - self.home = home.to_path_buf(); - let mut current_file_node = FileNodeItem { - path_buf: home.to_path_buf(), - is_dir: true, - read: false, - open: false, - children: HashMap::new(), - children_open_count: 0, - }; - let mut current_path = home.to_path_buf(); - - let mut ancestors = home.ancestors(); - ancestors.next(); - - for p in ancestors { - let mut file_node = FileNodeItem { - path_buf: PathBuf::from(p), - is_dir: true, - read: false, - open: true, - children: HashMap::new(), - children_open_count: 0, - }; - file_node - .children - .insert(current_path.clone(), current_file_node.clone()); - current_file_node = file_node; - current_path = PathBuf::from(p); - } - self.root = current_file_node; - self.pwd = home.to_path_buf(); - } - - pub fn get_file_node_mut(&mut self, path: &Path) -> Option<&mut FileNodeItem> { - let mut node = Some(&mut self.root); - - let ancestors = path.ancestors().collect::>(); - for p in ancestors[..ancestors.len() - 1].iter().rev() { - node = Some(node?.children.get_mut(&PathBuf::from(p))?); - } - node - } - - pub fn get_file_node(&self, path: &Path) -> Option<&FileNodeItem> { - let mut node = Some(&self.root); - - let ancestors = path.ancestors().collect::>(); - for p in ancestors[..ancestors.len() - 1].iter().rev() { - node = Some(node?.children.get(&PathBuf::from(p))?); - } - node - } - - pub fn update_node_count(&mut self, path: &Path) -> Option<()> { - let node = self.get_file_node_mut(path)?; - if node.is_dir { - if node.open { - node.children_open_count = node - .children - .iter() - .map(|(_, item)| item.children_open_count + 1) - .sum::(); - } else { - node.children_open_count = 0; - } - } - None - } -} - -impl Default for FilePickerData { - fn default() -> Self { - Self::new() - } -} - pub struct FilePicker { widget_id: WidgetId, pwd: WidgetPod>>, @@ -476,37 +348,12 @@ fn mouse_down( node.open = !node.open; } else { let tab_id = data.id; - let path = node.path_buf.clone(); let event_sink = ctx.get_external_handle(); - data.proxy.read_dir( + FilePickerData::read_dir( &node.path_buf, - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result< - Vec, - serde_json::Error, - > = serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdatePickerItems( - path, - items - .iter() - .map(|item| { - ( - item.path_buf - .clone(), - item.clone(), - ) - }) - .collect(), - ), - Target::Widget(tab_id), - ); - } - } - }), + tab_id, + &data.proxy, + event_sink, ); } } @@ -519,37 +366,12 @@ fn mouse_down( // double click self.last_left_click = None; let tab_id = data.id; - let path = node.path_buf.clone(); let event_sink = ctx.get_external_handle(); - data.proxy.read_dir( + FilePickerData::read_dir( &node.path_buf, - Box::new(move |result| { - if let Ok(res) = result { - let resp: Result< - Vec, - serde_json::Error, - > = serde_json::from_value(res); - if let Ok(items) = resp { - let _ = event_sink.submit_command( - LAPCE_UI_COMMAND, - LapceUICommand::UpdatePickerItems( - path, - items - .iter() - .map(|item| { - ( - item.path_buf - .clone(), - item.clone(), - ) - }) - .collect(), - ), - Target::Widget(tab_id), - ); - } - } - }), + tab_id, + &data.proxy, + event_sink, ); let pwd = node.path_buf.clone(); picker.index = 0; diff --git a/lapce-ui/src/tab.rs b/lapce-ui/src/tab.rs index 44230470..98c9624e 100644 --- a/lapce-ui/src/tab.rs +++ b/lapce-ui/src/tab.rs @@ -457,7 +457,7 @@ fn event( ctx.set_handled(); } LapceUICommand::FileChange(event) => { - data.handle_file_change(event); + data.handle_file_change(ctx, event); ctx.set_handled(); } LapceUICommand::CloseTerminal(id) => { @@ -957,22 +957,13 @@ fn event( .set_item_children(path, items.clone()); ctx.set_handled(); } - LapceUICommand::UpdateExplorerItems(_index, path, items) => { + LapceUICommand::UpdateExplorerItems(path, items, expand) => { let file_explorer = Arc::make_mut(&mut data.file_explorer); - if let Some(node) = file_explorer.get_node_mut(path) { - node.children = items - .iter() - .map(|item| (item.path_buf.clone(), item.clone())) - .collect(); - node.read = true; - node.open = true; - node.children_open_count = node.children.len(); - } - if let Some(paths) = file_explorer.node_tree(path) { - for path in paths.iter() { - file_explorer.update_node_count(path); - } - } + file_explorer.update_children( + path, + items.to_owned(), + *expand, + ); ctx.set_handled(); } _ => (),