aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-term/src/ui/mod.rs2
-rw-r--r--helix-term/src/ui/spinner.rs75
2 files changed, 77 insertions, 0 deletions
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs
index e0177b7c..c062bffe 100644
--- a/helix-term/src/ui/mod.rs
+++ b/helix-term/src/ui/mod.rs
@@ -5,6 +5,7 @@ mod menu;
mod picker;
mod popup;
mod prompt;
+mod spinner;
mod text;
pub use completion::Completion;
@@ -14,6 +15,7 @@ pub use menu::Menu;
pub use picker::Picker;
pub use popup::Popup;
pub use prompt::{Prompt, PromptEvent};
+pub use spinner::{ProgressSpinners, Spinner};
pub use text::Text;
pub use tui::layout::Rect;
diff --git a/helix-term/src/ui/spinner.rs b/helix-term/src/ui/spinner.rs
new file mode 100644
index 00000000..e8a43b48
--- /dev/null
+++ b/helix-term/src/ui/spinner.rs
@@ -0,0 +1,75 @@
+use std::{collections::HashMap, time::SystemTime};
+
+#[derive(Default, Debug)]
+pub struct ProgressSpinners {
+ inner: HashMap<usize, Spinner>,
+}
+
+impl ProgressSpinners {
+ pub fn get(&self, id: usize) -> Option<&Spinner> {
+ self.inner.get(&id)
+ }
+
+ pub fn get_or_create(&mut self, id: usize) -> &mut Spinner {
+ self.inner.entry(id).or_insert_with(Spinner::default)
+ }
+}
+
+impl Default for Spinner {
+ fn default() -> Self {
+ Self::dots(80)
+ }
+}
+
+#[derive(Debug)]
+pub struct Spinner {
+ frames: Vec<&'static str>,
+ count: usize,
+ start: Option<SystemTime>,
+ interval: u64,
+}
+
+impl Spinner {
+ /// Creates a new spinner with `frames` and `interval`.
+ /// Expects the frames count and interval to be greater than 0.
+ pub fn new(frames: Vec<&'static str>, interval: u64) -> Self {
+ let count = frames.len();
+ assert!(count > 0);
+ assert!(interval > 0);
+
+ Self {
+ frames,
+ count,
+ interval,
+ start: None,
+ }
+ }
+
+ pub fn dots(interval: u64) -> Self {
+ Self::new(vec!["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"], interval)
+ }
+
+ pub fn start(&mut self) {
+ self.start = Some(SystemTime::now());
+ }
+
+ pub fn frame(&self) -> Option<&str> {
+ let idx = (self
+ .start
+ .map(|time| SystemTime::now().duration_since(time))?
+ .ok()?
+ .as_millis()
+ / self.interval as u128) as usize
+ % self.count;
+
+ self.frames.get(idx).copied()
+ }
+
+ pub fn stop(&mut self) {
+ self.start = None;
+ }
+
+ pub fn is_stopped(&self) -> bool {
+ self.start.is_none()
+ }
+}