Skip to content

Commit

Permalink
Tick progress spinner at 60 fps
Browse files Browse the repository at this point in the history
Add a interval timer to main event loop. Check if there are any spinners
and do the spinning job without waiting for progress event so spinner
does not look stuck waiting for event.

Not sure if there is a better place to add this, I was looking at the
redraw notification but I think it is better to keep it separated so
in the future we can separate both easier.
  • Loading branch information
pickfire committed Mar 26, 2023
1 parent 353fa72 commit fb572fb
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
13 changes: 13 additions & 0 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,16 @@ impl Application {
}
}

pub async fn handle_frame_tick(&mut self) {
let editor_view = self
.compositor
.find::<ui::EditorView>()
.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,
Expand Down Expand Up @@ -600,6 +610,9 @@ impl Application {
return true;
}
}
EditorEvent::TickFrame => {
self.handle_frame_tick().await;
}
}

false
Expand Down
4 changes: 4 additions & 0 deletions helix-term/src/ui/spinner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
13 changes: 11 additions & 2 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -840,6 +841,7 @@ pub struct Editor {
pub auto_pairs: Option<AutoPairs>,

pub idle_timer: Pin<Box<Sleep>>,
pub tick_frame: IntervalStream,
pub last_motion: Option<Motion>,

pub last_completion: Option<CompleteAction>,
Expand Down Expand Up @@ -884,6 +886,7 @@ pub enum EditorEvent {
LanguageServerMessage((usize, Call)),
DebuggerEvent(dap::Payload),
IdleTimer,
TickFrame,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1597,14 +1601,19 @@ 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();
}
}
}

_ = &mut self.idle_timer => {
return EditorEvent::IdleTimer
}

_ = &mut self.tick_frame.next() => {
return EditorEvent::TickFrame
}
}
}
}
Expand Down

0 comments on commit fb572fb

Please sign in to comment.