Browse Source

utilities/ProgressSpinner: add interval field and new spinners

lazy_fetch
Manos Pitsidianakis 11 months ago
parent
commit
48d4343082
Signed by: epilys GPG Key ID: 73627C2F690DF710
  1. 92
      docs/meli.conf.5
  2. 18
      src/components/utilities.rs
  3. 130
      src/components/utilities/widgets.rs
  4. 10
      src/conf/terminal.rs

92
docs/meli.conf.5

@ -1039,49 +1039,67 @@ This setting can be toggled with
String to show in status bar if mouse is active.
.\" default value
.Pq Em 🖱️
.It Ic progress_spinner_sequence Ar Either \&< Integer, [String] \&>
Choose between 30-something built in sequences (integers between 0-30) or define your own list of strings for the progress spinner animation.
.It Ic progress_spinner_sequence Ar Either \&< Integer, ProgressSpinner \&>
Choose between 37 built in sequences (integers between 0-36) or define your own list of strings for the progress spinner animation.
Set to an empty array to disable the progress spinner.
.\" default value
.Pq Em 19
.Pq Em 20
.Pp
Builtin sequences are:
.Bd -literal
0 ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
1 ["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"]
2 ["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"]
3 ["○", "◔", "◐", "◕", "⬤"]
4 ["□", "◱", "◧", "▣", "■"]
5 ["□", "◱", "▨", "▩", "■"]
6 ["□", "◱", "▥", "▦", "■"]
7 ["░", "▒", "▓", "█"]
8 ["░", "█"]
9 ["⬜", "⬛"]
10 ["▱", "▰"]
11 ["▭", "◼"]
12 ["▯", "▮"]
13 ["◯", "⬤"]
14 ["⚪", "⚫"]
15 ["▖", "▗", "▘", "▝", "▞", "▚", "▙", "▟", "▜", "▛"]
16 ["|", "/", "-", "\\"]
17 [".", "o", "O", "@", "*"]
18 ["◡◡", "⊙⊙", "◠◠", "⊙⊙"]
19 ["◜ ", " ◝", " ◞", "◟ "]
10 ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"]
11 ["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"]
22 ["▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"]
23 ["▖", "▘", "▝", "▗"]
24 ["▌", "▀", "▐", "▄"]
25 ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"]
26 ["◢", "◣", "◤", "◥"]
27 ["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]
28 ["⢎⡰", "⢎⡡", "⢎⡑", "⢎⠱", "⠎⡱", "⢊⡱", "⢌⡱", "⢆⡱"]
29 [".", "o", "O", "°", "O", "o", "."]
0 ["-", "\\", "|", "/"]
1 ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
2 ["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"]
3 ["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"]
4 ["○", "◔", "◐", "◕", "⬤"]
5 ["□", "◱", "◧", "▣", "■"]
6 ["□", "◱", "▨", "▩", "■"]
7 ["□", "◱", "▥", "▦", "■"]
8 ["░", "▒", "▓", "█"]
9 ["░", "█"]
10 ["⬜", "⬛"]
11 ["▱", "▰"]
12 ["▭", "◼"]
13 ["▯", "▮"]
14 ["◯", "⬤"]
15 ["⚪", "⚫"]
16 ["▖", "▗", "▘", "▝", "▞", "▚", "▙", "▟", "▜", "▛"]
17 ["|", "/", "-", "\\"]
18 [".", "o", "O", "@", "*"]
19 ["◡◡", "⊙⊙", "◠◠", "⊙⊙"]
20 ["◜ ", " ◝", " ◞", "◟ "]
21 ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"]
22 ["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"]
23 [ "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉" ]
24 ["▖", "▘", "▝", "▗"]
25 ["▌", "▀", "▐", "▄"]
26 ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"]
27 ["◢", "◣", "◤", "◥"]
28 ["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]
29 ["⢎⡰", "⢎⡡", "⢎⡑", "⢎⠱", "⠎⡱", "⢊⡱", "⢌⡱", "⢆⡱"]
30 [".", "o", "O", "°", "O", "o", "."]
31 ["㊂", "㊀", "㊁"]
32 ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "]
33 [ "🕛 ", "🕐 ", "🕑 ", "🕒 ", "🕓 ", "🕔 ", "🕕 ", "🕖 ", "🕗 ", "🕘 ", "🕙 ", "🕚 " ]
34 ["🌍 ", "🌎 ", "🌏 "]
35 [ "[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", "[ ]", "[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]" ]
36 ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "]
.Ed
Or, define an array of strings each consisting of a frame in the progress sequence indicator:
.Pp
Or, define an array of strings each consisting of a frame in the progress sequence indicator for a custom spinner:
.Bl -tag -width 36n
.It Ic interval_ms Ar u64
.Pq Em optional
Frame interval.
.\" default value
.Pq 50
.It Ic frames Ar [String]
The animation frames.
.El
.Pp
Example:
.Bd -literal
# 𝄈⡂″⡈߳܃⢂:߳̈⢁܄ː“⢐″„⠑։ ⡁⡈;ܹ⡂։𝂬̤⡂꞉⣀ܹ⢁⠊𝄈⠉⠑ܸ̈׃ ;⢐;߳⠡܉˸⠒߳꞉⁚𝂬⠑⠒܅⠊;⠔⠢܄ ”⠉ֵ”⢂⢁̈⁚⠊˸⠌ܸ̤⣀𝂬⠤⠨⠢‥¨ ⡠܉꞉꞉⠑׃⠑⡐⠨؛ܸ܆„ܹ⡈⢁;⢄܄؛ ܲ⢄⠡⡁‥؛ܲ⢂“⢈։⠔⢄”꞉܉⠔
# Taken from @SmoothUnicode@botsin.space
progress_spinner_sequence = ["։","𝄈","⡂","″","⡈߳","܃","⢂",":߳̈","⢁","܄","ː","“","⢐","″","„","⠑","։"," ","⡁","⡈",";ܹ","⡂","։","𝂬̤","⡂","꞉","⣀ܹ","⢁","⠊","𝄈","⠉","⠑ܸ̈","׃"," ",";","⢐",";߳","⠡","܉","˸","⠒߳","꞉","⁚","𝂬","⠑","⠒","܅","⠊",";","⠔","⠢","܄"," ","”","⠉ֵ","”","⢂","⢁̈","⁚","⠊","˸","⠌ܸ̤","⣀","𝂬","⠤","⠨","⠢","‥","¨"," ","⡠","܉","꞉","꞉","⠑","׃","⠑","⡐","⠨","؛ܸ","܆","„ܹ","⡈","⢁",";","⢄܄","؛"," ܲ","⢄","⠡","⡁","‥","؛ܲ","⢂","“","⢈","։","⠔","⢄","”","꞉","܉","⠔"]
progress_spinner_sequence = { interval_ms = 150, frames = [ "-", "=", "≡" ] }
.Ed
.El
.Sh LOG

18
src/components/utilities.rs

@ -78,13 +78,16 @@ impl fmt::Display for StatusBar {
impl StatusBar {
pub fn new(context: &Context, container: Box<dyn Component>) -> Self {
let mut progress_spinner = ProgressSpinner::new(19, context);
let mut progress_spinner = ProgressSpinner::new(20, context);
match context.settings.terminal.progress_spinner_sequence.as_ref() {
Some(conf::terminal::ProgressSpinnerSequence::Integer(k)) => {
progress_spinner.set_kind(*k);
}
Some(conf::terminal::ProgressSpinnerSequence::Custom(ref s)) => {
progress_spinner.set_custom_kind(s.clone());
Some(conf::terminal::ProgressSpinnerSequence::Custom {
ref frames,
ref interval_ms,
}) => {
progress_spinner.set_custom_kind(frames.clone(), *interval_ms);
}
None => {}
}
@ -472,13 +475,16 @@ impl Component for StatusBar {
match event {
UIEvent::ConfigReload { old_settings: _ } => {
let mut progress_spinner = ProgressSpinner::new(19, context);
let mut progress_spinner = ProgressSpinner::new(20, context);
match context.settings.terminal.progress_spinner_sequence.as_ref() {
Some(conf::terminal::ProgressSpinnerSequence::Integer(k)) => {
progress_spinner.set_kind(*k);
}
Some(conf::terminal::ProgressSpinnerSequence::Custom(ref s)) => {
progress_spinner.set_custom_kind(s.clone());
Some(conf::terminal::ProgressSpinnerSequence::Custom {
ref frames,
ref interval_ms,
}) => {
progress_spinner.set_custom_kind(frames.clone(), *interval_ms);
}
None => {}
}

130
src/components/utilities/widgets.rs

@ -22,6 +22,7 @@
use super::*;
use std::borrow::Cow;
use std::collections::HashMap;
use std::time::Duration;
type AutoCompleteFn = Box<dyn Fn(&Context, &str) -> Vec<AutoCompleteEntry> + Send + Sync>;
@ -1238,54 +1239,93 @@ pub struct ProgressSpinner {
}
impl ProgressSpinner {
pub const KINDS: [&'static [&'static str]; 30] = [
&["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"],
&["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"],
&["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"],
&["○", "◔", "◐", "◕", "⬤"],
&["□", "◱", "◧", "▣", "■"],
&["□", "◱", "▨", "▩", "■"],
&["□", "◱", "▥", "▦", "■"],
&["░", "▒", "▓", "█"],
&["░", "█"],
&["⬜", "⬛"],
&["▱", "▰"],
&["▭", "◼"],
&["▯", "▮"],
&["◯", "⬤"],
&["⚪", "⚫"],
&["▖", "▗", "▘", "▝", "▞", "▚", "▙", "▟", "▜", "▛"],
&["|", "/", "-", "\\"],
&[".", "o", "O", "@", "*"],
&["◡◡", "⊙⊙", "◠◠", "⊙⊙"],
&["◜ ", " ◝", " ◞", "◟ "],
&["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"],
&["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"],
&[
"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉",
],
&["▖", "▘", "▝", "▗"],
&["▌", "▀", "▐", "▄"],
&["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"],
&["◢", "◣", "◤", "◥"],
&["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"],
&["⢎⡰", "⢎⡡", "⢎⡑", "⢎⠱", "⠎⡱", "⢊⡱", "⢌⡱", "⢆⡱"],
&[".", "o", "O", "°", "O", "o", "."],
pub const KINDS: [(Duration, &'static [&'static str]); 37] = [
(Duration::from_millis(130), &["-", "\\", "|", "/"]),
(Self::INTERVAL, &["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]),
(Self::INTERVAL, &["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"]),
(Self::INTERVAL, &["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"]),
(Self::INTERVAL, &["○", "◔", "◐", "◕", "⬤"]),
(Self::INTERVAL, &["□", "◱", "◧", "▣", "■"]),
(Self::INTERVAL, &["□", "◱", "▨", "▩", "■"]),
(Self::INTERVAL, &["□", "◱", "▥", "▦", "■"]),
(Self::INTERVAL, &["░", "▒", "▓", "█"]),
(Self::INTERVAL, &["░", "█"]),
(Self::INTERVAL, &["⬜", "⬛"]),
(Self::INTERVAL, &["▱", "▰"]),
(Self::INTERVAL, &["▭", "◼"]),
(Self::INTERVAL, &["▯", "▮"]),
(Self::INTERVAL, &["◯", "⬤"]),
(Self::INTERVAL, &["⚪", "⚫"]),
(
Self::INTERVAL,
&["▖", "▗", "▘", "▝", "▞", "▚", "▙", "▟", "▜", "▛"],
),
(Self::INTERVAL, &["|", "/", "-", "\\"]),
(Self::INTERVAL, &[".", "o", "O", "@", "*"]),
(Self::INTERVAL, &["◡◡", "⊙⊙", "◠◠", "⊙⊙"]),
(Self::INTERVAL, &["◜ ", " ◝", " ◞", "◟ "]),
(Self::INTERVAL, &["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"]),
(
Self::INTERVAL,
&["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"],
),
(
Self::INTERVAL,
&[
"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉",
],
),
(Self::INTERVAL, &["▖", "▘", "▝", "▗"]),
(Self::INTERVAL, &["▌", "▀", "▐", "▄"]),
(Self::INTERVAL, &["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"]),
(Self::INTERVAL, &["◢", "◣", "◤", "◥"]),
(Self::INTERVAL, &["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]),
(
Self::INTERVAL,
&["⢎⡰", "⢎⡡", "⢎⡑", "⢎⠱", "⠎⡱", "⢊⡱", "⢌⡱", "⢆⡱"],
),
(Self::INTERVAL, &[".", "o", "O", "°", "O", "o", "."]),
(Duration::from_millis(100), &["㊂", "㊀", "㊁"]),
(
Duration::from_millis(100),
&["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "],
),
(
Duration::from_millis(100),
&[
"🕛 ", "🕐 ", "🕑 ", "🕒 ", "🕓 ", "🕔 ", "🕕 ", "🕖 ", "🕗 ", "🕘 ", "🕙 ", "🕚 ",
],
),
(Duration::from_millis(100), &["🌍 ", "🌎 ", "🌏 "]),
(
Duration::from_millis(80),
&[
"[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", "[ ]",
"[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]",
],
),
(
Duration::from_millis(80),
&["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "],
),
];
const INTERVAL: std::time::Duration = std::time::Duration::from_millis(50);
pub const INTERVAL_MS: u64 = 50;
const INTERVAL: std::time::Duration = std::time::Duration::from_millis(Self::INTERVAL_MS);
pub fn new(kind: usize, context: &Context) -> Self {
let timer = context
.job_executor
.clone()
.create_timer(Self::INTERVAL, Self::INTERVAL);
let kind = kind % Self::KINDS.len();
let width = Self::KINDS[kind]
.1
.iter()
.map(|f| f.grapheme_len())
.max()
.unwrap_or(0);
let interval = Self::KINDS[kind].0;
let timer = context
.job_executor
.clone()
.create_timer(interval, interval);
let mut theme_attr = crate::conf::value(context, "status.bar");
if !context.settings.terminal.use_color() {
theme_attr.attrs |= Attr::REVERSE;
@ -1310,21 +1350,25 @@ impl ProgressSpinner {
pub fn set_kind(&mut self, kind: usize) {
self.stage = 0;
self.width = Self::KINDS[kind % Self::KINDS.len()]
.1
.iter()
.map(|f| f.grapheme_len())
.max()
.unwrap_or(0);
self.kind = Ok(kind % Self::KINDS.len());
let interval = Self::KINDS[kind % Self::KINDS.len()].0;
self.timer.set_interval(interval);
self.dirty = true;
}
pub fn set_custom_kind(&mut self, custom: Vec<String>) {
pub fn set_custom_kind(&mut self, frames: Vec<String>, interval: u64) {
self.stage = 0;
self.width = custom.iter().map(|f| f.grapheme_len()).max().unwrap_or(0);
self.width = frames.iter().map(|f| f.grapheme_len()).max().unwrap_or(0);
if self.width == 0 {
self.stop();
}
self.kind = Err(custom);
self.kind = Err(frames);
self.timer.set_interval(Duration::from_millis(interval));
self.dirty = true;
}
@ -1356,7 +1400,7 @@ impl Component for ProgressSpinner {
if self.active {
write_string_to_grid(
match self.kind.as_ref() {
Ok(kind) => Self::KINDS[*kind][self.stage].as_ref(),
Ok(kind) => (Self::KINDS[*kind].1)[self.stage].as_ref(),
Err(custom) => custom[self.stage].as_ref(),
},
grid,
@ -1377,7 +1421,7 @@ impl Component for ProgressSpinner {
UIEvent::Timer(id) if *id == self.timer.id() => {
match self.kind.as_ref() {
Ok(kind) => {
self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[*kind].len());
self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[*kind].1.len());
}
Err(custom) => {
self.stage = (self.stage + 1).wrapping_rem(custom.len());

10
src/conf/terminal.rs

@ -114,7 +114,15 @@ impl DotAddressable for TerminalSettings {
#[serde(untagged)]
pub enum ProgressSpinnerSequence {
Integer(usize),
Custom(Vec<String>),
Custom {
frames: Vec<String>,
#[serde(default = "interval_ms_val")]
interval_ms: u64,
},
}
const fn interval_ms_val() -> u64 {
crate::components::utilities::ProgressSpinner::INTERVAL_MS
}
impl DotAddressable for ProgressSpinnerSequence {}
Loading…
Cancel
Save