diff --git a/helix-term/src/handlers/auto_save.rs b/helix-term/src/handlers/auto_save.rs index d3f7f6fc124ad..a8a292436026f 100644 --- a/helix-term/src/handlers/auto_save.rs +++ b/helix-term/src/handlers/auto_save.rs @@ -4,36 +4,68 @@ use anyhow::Ok; use arc_swap::access::Access; use helix_event::{register_hook, send_blocking}; -use helix_view::{events::DocumentDidChange, handlers::Handlers, Editor}; +use helix_view::{ + document::Mode, + events::DocumentDidChange, + handlers::{AutoSaveEvent, Handlers}, + Editor, +}; use tokio::time::Instant; use crate::{ commands, compositor, + events::OnModeSwitch, job::{self, Jobs}, }; #[derive(Debug)] -pub(super) struct AutoSaveHandler; +pub(super) struct AutoSaveHandler { + save_pending: bool, +} impl AutoSaveHandler { pub fn new() -> AutoSaveHandler { - AutoSaveHandler + AutoSaveHandler { + save_pending: false, + } } } impl helix_event::AsyncHook for AutoSaveHandler { - type Event = u64; + type Event = AutoSaveEvent; fn handle_event( &mut self, - timeout: Self::Event, - _: Option, + event: Self::Event, + existing_debounce: Option, ) -> Option { - Some(Instant::now() + Duration::from_millis(timeout)) + match event { + Self::Event::DocumentChanged { debounce } => { + self.save_pending = true; + Some(Instant::now() + Duration::from_millis(debounce)) + } + Self::Event::LeftInsertMode => { + if existing_debounce.is_some() { + // If the change happened more recently than the debounce, let the + // debounce run down before saving. + existing_debounce + } else { + // Otherwise if there is a save pending, save immediately. + if self.save_pending { + self.finish_debounce(); + } + None + } + } + } } fn finish_debounce(&mut self) { - job::dispatch_blocking(move |editor, _| request_auto_save(editor)) + job::dispatch_blocking(move |editor, _| { + if editor.mode() != Mode::Insert { + request_auto_save(editor) + } + }) } } @@ -54,7 +86,20 @@ pub(super) fn register_hooks(handlers: &Handlers) { register_hook!(move |event: &mut DocumentDidChange<'_>| { let config = event.doc.config.load(); if config.auto_save.after_delay.enable { - send_blocking(&tx, config.auto_save.after_delay.timeout); + send_blocking( + &tx, + AutoSaveEvent::DocumentChanged { + debounce: config.auto_save.after_delay.timeout, + }, + ); + } + Ok(()) + }); + + let tx = handlers.auto_save.clone(); + register_hook!(move |event: &mut OnModeSwitch<'_, '_>| { + if event.cx.editor.config().auto_save.after_delay.enable && event.old_mode == Mode::Insert { + send_blocking(&tx, AutoSaveEvent::LeftInsertMode); } Ok(()) }); diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs index 352abb8813068..9cd50ceab4e2b 100644 --- a/helix-view/src/handlers.rs +++ b/helix-view/src/handlers.rs @@ -7,11 +7,17 @@ use crate::{DocumentId, Editor, ViewId}; pub mod dap; pub mod lsp; +#[derive(Debug)] +pub enum AutoSaveEvent { + DocumentChanged { debounce: u64 }, + LeftInsertMode, +} + pub struct Handlers { // only public because most of the actual implementation is in helix-term right now :/ pub completions: Sender, pub signature_hints: Sender, - pub auto_save: Sender, + pub auto_save: Sender, } impl Handlers {