Auto reload changed files
This commit is contained in:
+63
@@ -17,6 +17,12 @@ use crate::view::{CanvasView, Clipboard, EditTarget, InsertRequest};
|
||||
/// How long a status message stays on screen.
|
||||
const STATUS_SECONDS: f64 = 5.0;
|
||||
|
||||
/// How often the files behind file nodes are looked at to see whether
|
||||
/// something outside this editor changed them. Often enough that a file saved
|
||||
/// in another program appears to update by itself, rarely enough that it is a
|
||||
/// handful of `stat` calls a second and no more.
|
||||
const FILE_CHECK_SECONDS: f64 = 1.0;
|
||||
|
||||
/// An action waiting for the user to decide what to do about unsaved changes.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum Pending {
|
||||
@@ -39,6 +45,7 @@ pub struct App {
|
||||
show_about: bool,
|
||||
show_shortcuts: bool,
|
||||
title: String,
|
||||
last_file_check: f64,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -57,6 +64,7 @@ impl App {
|
||||
show_about: false,
|
||||
show_shortcuts: false,
|
||||
title: String::new(),
|
||||
last_file_check: 0.0,
|
||||
};
|
||||
match open {
|
||||
Some(path) => app.open_path(&path),
|
||||
@@ -646,6 +654,52 @@ impl App {
|
||||
self.set_status(message, ctx);
|
||||
}
|
||||
|
||||
/// Looks for changes made to the files behind file nodes by something
|
||||
/// other than this editor, every [`FILE_CHECK_SECONDS`].
|
||||
///
|
||||
/// A file with no unsaved edit here is read again and the node showing it
|
||||
/// follows along, which is what a file node is for. A file edited here is
|
||||
/// left alone and marked on its card instead, because the edit is the one
|
||||
/// thing that cannot be read back from disk.
|
||||
fn check_files(&mut self, ctx: &Context) {
|
||||
if !self.view.files.is_watching() {
|
||||
return;
|
||||
}
|
||||
ctx.request_repaint_after(std::time::Duration::from_secs_f64(FILE_CHECK_SECONDS));
|
||||
let now = ctx.input(|i| i.time);
|
||||
if now - self.last_file_check < FILE_CHECK_SECONDS {
|
||||
return;
|
||||
}
|
||||
self.last_file_check = now;
|
||||
|
||||
let changes = self.view.files.check_disk();
|
||||
if changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
for path in &changes.reloaded {
|
||||
ctx.forget_image(&crate::nodes::file_uri(path));
|
||||
}
|
||||
self.view.reload_editor(&changes.reloaded);
|
||||
|
||||
let mut parts = Vec::new();
|
||||
if !changes.reloaded.is_empty() {
|
||||
parts.push(match changes.reloaded.len() {
|
||||
1 => format!("Reloaded {}", name_of(&changes.reloaded[0])),
|
||||
n => format!("Reloaded {n} files changed on disk"),
|
||||
});
|
||||
}
|
||||
if !changes.conflicts.is_empty() {
|
||||
parts.push(match changes.conflicts.len() {
|
||||
1 => format!(
|
||||
"{} changed on disk, kept the edit here",
|
||||
name_of(&changes.conflicts[0])
|
||||
),
|
||||
n => format!("{n} files changed on disk, kept the edits here"),
|
||||
});
|
||||
}
|
||||
self.set_status(parts.join(" \u{2014} "), ctx);
|
||||
}
|
||||
|
||||
// -- chrome -----------------------------------------------------------
|
||||
|
||||
fn menu_bar(&mut self, ui: &mut Ui, ctx: &Context) {
|
||||
@@ -1064,6 +1118,7 @@ impl eframe::App for App {
|
||||
self.update_title(&ctx);
|
||||
self.handle_shortcuts(&ctx);
|
||||
self.handle_dropped_files(&ctx);
|
||||
self.check_files(&ctx);
|
||||
|
||||
// Closing the window with unsaved changes asks first.
|
||||
if ctx.input(|i| i.viewport().close_requested()) && !self.quitting {
|
||||
@@ -1145,6 +1200,14 @@ const SHORTCUTS: &[(&str, &str)] = &[
|
||||
("Ctrl+0 / Ctrl+1", "Zoom to fit / actual size"),
|
||||
];
|
||||
|
||||
/// The file name of `path` for a status message, falling back to the whole
|
||||
/// path for the odd one that has none.
|
||||
fn name_of(path: &Path) -> String {
|
||||
path.file_name()
|
||||
.map(|name| name.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|| path.display().to_string())
|
||||
}
|
||||
|
||||
fn consume(ctx: &Context, modifiers: Modifiers, key: Key) -> bool {
|
||||
ctx.input_mut(|i| i.consume_shortcut(&KeyboardShortcut::new(modifiers, key)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user