summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqkzk <qu3nt1n@gmail.com>2023-10-16 22:38:58 +0200
committerqkzk <qu3nt1n@gmail.com>2023-10-16 22:38:58 +0200
commit2e1a2d2b71d9064fb1c73acf7460b3530060ea5c (patch)
treec7b74d063598bc707155157c0b615fd4aad4669f
parentf7f79df8262ad9d9d154324d1fc4b395bdf071dd (diff)
refresh every 10 seconds. WIP
refresh every 10 seconds. If no file in current dir has changed, nothing happens. BUT... if something changed, the whole view is refreshed, reseting the selected file :( It still needs some amelioration
-rw-r--r--development.md6
-rw-r--r--src/action_map.rs2
-rw-r--r--src/event_dispatch.rs2
-rw-r--r--src/event_exec.rs5
-rw-r--r--src/main.rs68
-rw-r--r--src/status.rs7
-rw-r--r--src/tab.rs9
7 files changed, 94 insertions, 5 deletions
diff --git a/development.md b/development.md
index bd86122..c637d2d 100644
--- a/development.md
+++ b/development.md
@@ -574,7 +574,11 @@ New view: Tree ! Toggle with 't', fold with 'z'. Navigate normally.
- [x] skim fuzzy find (ctrl-f) starts from current dir, not current selected file
- [x] open/file pick flagged files if there are, use selected file instead
- [x] regroup openers when opening multiple files.
-- [ ] refresh after a while
+- [ ] refresh every 10 seconds. If no file in current dir has changed, nothing happens.
+
+ BUT... if something changed, the whole view is refreshed, reseting the selected file :(
+
+ It still needs some amelioration
## TODO
diff --git a/src/action_map.rs b/src/action_map.rs
index cd829ee..05f3a08 100644
--- a/src/action_map.rs
+++ b/src/action_map.rs
@@ -70,6 +70,7 @@ pub enum ActionMap {
PageUp,
Preview,
Quit,
+ RefreshIfNeeded,
RefreshView,
RegexMatch,
RemoteMount,
@@ -166,6 +167,7 @@ impl ActionMap {
ActionMap::PageUp => EventAction::page_up(current_tab, colors),
ActionMap::Preview => EventAction::preview(status, colors),
ActionMap::Quit => EventAction::quit(current_tab),
+ ActionMap::RefreshIfNeeded => EventAction::refresh_if_needed(status),
ActionMap::RefreshView => EventAction::refreshview(status, colors),
ActionMap::RegexMatch => EventAction::regex_match(current_tab),
ActionMap::RemoteMount => EventAction::remote_mount(current_tab),
diff --git a/src/event_dispatch.rs b/src/event_dispatch.rs
index eabc4ba..fe22932 100644
--- a/src/event_dispatch.rs
+++ b/src/event_dispatch.rs
@@ -52,7 +52,7 @@ impl EventDispatcher {
status.click(row, col, current_height, colors)?;
LeaveMode::right_click(status, colors)?;
}
- Event::User(_) => status.refresh_status(colors)?,
+ Event::User(_) => status.refresh_if_needed()?,
Event::Resize { width, height } => status.resize(width, height)?,
Event::Key(Key::Char(c)) => self.char(status, c, colors)?,
Event::Key(key) => self.key_matcher(status, key, colors)?,
diff --git a/src/event_exec.rs b/src/event_exec.rs
index fc29493..a1b8cb6 100644
--- a/src/event_exec.rs
+++ b/src/event_exec.rs
@@ -816,6 +816,11 @@ impl EventAction {
status.refresh_status(colors)
}
+ pub fn refresh_if_needed(status: &mut Status) -> Result<()> {
+ status.encrypted_devices.update()?;
+ status.refresh_if_needed()
+ }
+
/// Display mediainfo details of an image
pub fn mediainfo(tab: &mut Tab) -> Result<()> {
if !is_program_in_path(MEDIAINFO) {
diff --git a/src/main.rs b/src/main.rs
index 713b42f..bf7d75d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,8 @@
+use std::borrow::BorrowMut;
+use std::sync::mpsc::{self, TryRecvError};
use std::sync::Arc;
+use std::thread;
+use std::time::Duration;
use anyhow::Result;
use log::info;
@@ -29,6 +33,10 @@ struct FM {
/// Since most are generated the first time an extension is met,
/// we need to hold this.
colors: Colors,
+ /// Refresher is used to force a refresh when a file has been modified externally.
+ /// It send `Event::User(())` every 10 seconds.
+ /// It also has a `mpsc::Sender` to send a quit message and reset the cursor.
+ refresher: Refresher,
}
impl FM {
@@ -37,7 +45,8 @@ impl FM {
/// an `EventDispatcher`,
/// a `Status`,
/// a `Display`,
- /// some `Colors`.
+ /// some `Colors`,
+ /// a `Refresher`.
/// It reads and drops the configuration from the config file.
/// If the config can't be parsed, it exits with error code 1.
fn start() -> Result<Self> {
@@ -54,8 +63,15 @@ impl FM {
});
let help = Help::from_keybindings(&config.binds, &opener)?.help;
let display = Display::new(term.clone());
- let status = Status::new(display.height()?, term, help, opener, &config.settings)?;
+ let status = Status::new(
+ display.height()?,
+ term.clone(),
+ help,
+ opener,
+ &config.settings,
+ )?;
let colors = config.colors.clone();
+ let refresher = Refresher::spawn(term);
drop(config);
Ok(Self {
event_reader,
@@ -63,6 +79,7 @@ impl FM {
status,
display,
colors,
+ refresher,
})
}
@@ -109,13 +126,58 @@ impl FM {
fn quit(self) -> Result<()> {
self.display.show_cursor()?;
let final_path = self.status.selected_path_str().to_owned();
- drop(self);
+ self.refresher.quit()?;
print_on_quit(&final_path);
info!("fm is shutting down");
Ok(())
}
}
+/// Allows refresh if the current path has been modified externally.
+struct Refresher {
+ /// Sender of messages, used to terminate the thread properly
+ tx: mpsc::Sender<()>,
+ /// Handle to the `term::Event` sender thread.
+ handle: thread::JoinHandle<()>,
+}
+
+impl Refresher {
+ /// Spawn a constantly thread sending refresh event to the terminal.
+ /// It also listen to a receiver for quit messages.
+ fn spawn(mut term: Arc<tuikit::term::Term>) -> Self {
+ let (tx, rx) = mpsc::channel();
+ let mut counter: u8 = 0;
+ let handle = thread::spawn(move || loop {
+ match rx.try_recv() {
+ Ok(_) | Err(TryRecvError::Disconnected) => {
+ log::info!("terminating refresher");
+ let _ = term.show_cursor(true);
+ return;
+ }
+ Err(TryRecvError::Empty) => {}
+ }
+ counter += 1;
+ thread::sleep(Duration::from_millis(100));
+ if counter >= 10 * 10 {
+ counter = 0;
+ let event = tuikit::prelude::Event::User(());
+ if term.borrow_mut().send_event(event).is_err() {
+ break;
+ }
+ }
+ });
+ Self { tx, handle }
+ }
+
+ /// Send a quit message to the receiver, signaling it to quit.
+ /// Join the refreshing thread which should be terminated.
+ fn quit(self) -> Result<()> {
+ self.tx.send(())?;
+ let _ = self.handle.join();
+ Ok(())
+ }
+}
+
/// Exit the application and log a message.
/// Used when the config can't be read.
fn exit_wrong_config() -> ! {
diff --git a/src/status.rs b/src/status.rs
index aa48a50..54a8dc5 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -697,6 +697,13 @@ impl Status {
Ok(())
}
+ /// if the current selected folder has been modified less than 10 seconds
+ /// ago, the current view is refreshed
+ pub fn refresh_if_needed(&mut self) -> Result<()> {
+ self.selected().refresh_if_needed()?;
+ Ok(())
+ }
+
/// When a rezise event occurs, we may hide the second panel if the width
/// isn't sufficiant to display enough information.
/// We also need to know the new height of the terminal to start scrolling
diff --git a/src/tab.rs b/src/tab.rs
index fe3c8a6..d81dddf 100644
--- a/src/tab.rs
+++ b/src/tab.rs
@@ -146,6 +146,15 @@ impl Tab {
Ok(())
}
+ pub fn refresh_if_needed(&mut self) -> Result<()> {
+ if self.path_content.path.metadata()?.modified()?.elapsed()?
+ < std::time::Duration::new(10, 0)
+ {
+ self.refresh_view()?;
+ }
+ Ok(())
+ }
+
/// Move to the currently selected directory.
/// Fail silently if the current directory is empty or if the selected
/// file isn't a directory.