diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index b6dcf0aba7af..ff010d02cfb6 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -500,6 +500,16 @@ impl Application { } } + pub async fn handle_frame_tick(&mut self) { + let editor_view = self + .compositor + .find::() + .expect("expected at least one EditorView"); + if editor_view.spinners_mut().spinning() { + self.render().await; + } + } + pub fn handle_document_write(&mut self, doc_save_event: DocumentSavedEventResult) { let doc_save_event = match doc_save_event { Ok(event) => event, @@ -600,6 +610,9 @@ impl Application { return true; } } + EditorEvent::TickFrame => { + self.handle_frame_tick().await; + } } false diff --git a/helix-term/src/ui/spinner.rs b/helix-term/src/ui/spinner.rs index 1acf6bac805b..957375acebaf 100644 --- a/helix-term/src/ui/spinner.rs +++ b/helix-term/src/ui/spinner.rs @@ -19,6 +19,10 @@ impl ProgressSpinners { self.inner.remove(&id); } + pub fn spinning(&self) -> bool { + !self.inner.is_empty() + } + pub fn frame(&self, id: usize) -> Option<&str> { let start = self.inner.get(&id)?; let idx = diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 58f029ac74ae..7d5a184e7097 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -33,8 +33,9 @@ use tokio::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, oneshot, Notify, RwLock, }, - time::{sleep, Duration, Instant, Sleep}, + time::{interval, sleep, Duration, Instant, Sleep}, }; +use tokio_stream::wrappers::IntervalStream; use anyhow::{anyhow, bail, Error}; @@ -840,6 +841,7 @@ pub struct Editor { pub auto_pairs: Option, pub idle_timer: Pin>, + pub tick_frame: IntervalStream, pub last_motion: Option, pub last_completion: Option, @@ -884,6 +886,7 @@ pub enum EditorEvent { LanguageServerMessage((usize, Call)), DebuggerEvent(dap::Payload), IdleTimer, + TickFrame, } #[derive(Debug, Clone)] @@ -962,6 +965,7 @@ impl Editor { status_msg: None, autoinfo: None, idle_timer: Box::pin(sleep(conf.idle_timeout)), + tick_frame: IntervalStream::new(interval(Duration::from_millis(1000 / 60))), // 60 fps last_motion: None, last_completion: None, config, @@ -1597,7 +1601,8 @@ impl Editor { self.needs_redraw = true; let timeout = Instant::now() + Duration::from_millis(96); if timeout < self.idle_timer.deadline() { - self.idle_timer.as_mut().reset(timeout) + self.idle_timer.as_mut().reset(timeout); + self.tick_frame.as_mut().reset(); } } } @@ -1605,6 +1610,10 @@ impl Editor { _ = &mut self.idle_timer => { return EditorEvent::IdleTimer } + + _ = &mut self.tick_frame.next() => { + return EditorEvent::TickFrame + } } } }