summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-10-14 20:07:39 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-10-14 20:07:39 +0300
commit4e72b6552a0ed174e6ce000f5bb8b4cd66ccb43e (patch)
tree4097ae88ff8c6be5b59ddb38e1926cc57719fb48
parent310d02042f1f02ff79af8dd115546806c85dbe91 (diff)
conf: add setting for progress spinner
Choose between 30-something built in sequences (integers between 0-30) or define your own list of strings for the progress spinner animation. Default: 0
-rw-r--r--src/components/utilities.rs56
-rw-r--r--src/components/utilities/widgets.rs80
-rw-r--r--src/conf/terminal.rs15
3 files changed, 122 insertions, 29 deletions
diff --git a/src/components/utilities.rs b/src/components/utilities.rs
index 146010df..313f63be 100644
--- a/src/components/utilities.rs
+++ b/src/components/utilities.rs
@@ -654,6 +654,17 @@ impl fmt::Display for StatusBar {
impl StatusBar {
pub fn new(context: &Context, container: Box<dyn Component>) -> Self {
+ let mut progress_spinner = ProgressSpinner::new(0);
+ 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());
+ }
+ None => {}
+ }
+
StatusBar {
container,
status: String::with_capacity(256),
@@ -667,12 +678,13 @@ impl StatusBar {
height: 1,
id: ComponentId::new_v4(),
auto_complete: AutoComplete::new(Vec::new()),
- progress_spinner: ProgressSpinner::new(1),
+ progress_spinner,
in_progress_jobs: HashSet::default(),
done_jobs: HashSet::default(),
cmd_history: crate::command::history::old_cmd_history(),
}
}
+
fn draw_status_bar(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
let mut attribute = crate::conf::value(context, "status.bar");
if !context.settings.terminal.use_color() {
@@ -706,7 +718,10 @@ impl StatusBar {
}
}
- let (x, y) = bottom_right!(area);
+ let (mut x, y) = bottom_right!(area);
+ if self.progress_spinner.is_active() {
+ x = x.saturating_sub(1 + self.progress_spinner.width);
+ }
for (idx, c) in self.display_buffer.chars().rev().enumerate() {
if let Some(cell) = grid.get_mut(x.saturating_sub(idx).saturating_sub(1), y) {
cell.set_ch(c);
@@ -714,6 +729,16 @@ impl StatusBar {
break;
}
}
+ if self.progress_spinner.is_dirty() {
+ self.progress_spinner.draw(
+ grid,
+ (
+ pos_dec(bottom_right!(area), (self.progress_spinner.width, 0)),
+ bottom_right!(area),
+ ),
+ context,
+ );
+ }
context.dirty_areas.push_back(area);
}
@@ -763,26 +788,16 @@ impl Component for StatusBar {
context,
);
- if self.progress_spinner.is_dirty() {
- self.progress_spinner.draw(
- grid,
- (
- (get_x(bottom_right).saturating_sub(1), get_y(bottom_right)),
- bottom_right,
- ),
- context,
- );
- }
-
- if self.mode != UIMode::Command && !self.is_dirty() {
- return;
- }
self.dirty = false;
self.draw_status_bar(
grid,
(set_y(upper_left, get_y(bottom_right)), bottom_right),
context,
);
+
+ if self.mode != UIMode::Command && !self.is_dirty() {
+ return;
+ }
match self.mode {
UIMode::Normal => {}
UIMode::Command => {
@@ -1020,7 +1035,11 @@ impl Component for StatusBar {
match event {
UIEvent::ChangeMode(m) => {
let offset = self.status.find('|').unwrap_or_else(|| self.status.len());
- self.status.replace_range(..offset, &format!("{} {}", m,
+ self.status.replace_range(
+ ..offset,
+ &format!(
+ "{} {}",
+ m,
if self.mouse {
context
.settings
@@ -1032,7 +1051,8 @@ impl Component for StatusBar {
} else {
""
},
- ));
+ ),
+ );
self.set_dirty(true);
self.container.set_dirty(true);
self.mode = *m;
diff --git a/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs
index 0b17d24e..823a379c 100644
--- a/src/components/utilities/widgets.rs
+++ b/src/components/utilities/widgets.rs
@@ -1049,18 +1049,17 @@ impl ScrollBar {
#[derive(Debug)]
pub struct ProgressSpinner {
- //total_work: usize,
- //finished: usize,
timer: crate::timer::PosixTimer,
stage: usize,
- kind: usize,
+ pub kind: std::result::Result<usize, Vec<String>>,
+ pub width: usize,
active: bool,
dirty: bool,
id: ComponentId,
}
impl ProgressSpinner {
- const KINDS: [&'static [&'static str]; 15] = [
+ pub const KINDS: [&'static [&'static str]; 30] = [
&["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"],
&["⣀", "⣄", "⣤", "⣦", "⣶", "⣷", "⣿"],
&["⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"],
@@ -1076,10 +1075,26 @@ impl ProgressSpinner {
&["▯", "▮"],
&["◯", "⬤"],
&["⚪", "⚫"],
+ &["▖", "▗", "▘", "▝", "▞", "▚", "▙", "▟", "▜", "▛"],
+ &["|", "/", "-", "\\"],
+ &[".", "o", "O", "@", "*"],
+ &["◡◡", "⊙⊙", "◠◠", "⊙⊙"],
+ &["◜ ", " ◝", " ◞", "◟ "],
+ &["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"],
+ &["▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃"],
+ &[
+ "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉",
+ ],
+ &["▖", "▘", "▝", "▗"],
+ &["▌", "▀", "▐", "▄"],
+ &["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"],
+ &["◢", "◣", "◤", "◥"],
+ &["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"],
+ &["⢎⡰", "⢎⡡", "⢎⡑", "⢎⠱", "⠎⡱", "⢊⡱", "⢌⡱", "⢆⡱"],
+ &[".", "o", "O", "°", "O", "o", "."],
];
const INTERVAL: std::time::Duration = std::time::Duration::from_millis(50);
- const VALUE: std::time::Duration = std::time::Duration::from_millis(500);
pub fn new(kind: usize) -> Self {
let timer = crate::timer::PosixTimer::new_with_signal(
@@ -1088,22 +1103,50 @@ impl ProgressSpinner {
nix::sys::signal::Signal::SIGALRM,
)
.unwrap();
- debug!("Requested timer {:?} for ProgressSpinner", timer.si_value);
+ let kind = kind % Self::KINDS.len();
+ let width = Self::KINDS[kind]
+ .iter()
+ .map(|f| f.grapheme_len())
+ .max()
+ .unwrap_or(0);
ProgressSpinner {
timer,
stage: 0,
- kind: kind % Self::KINDS.len(),
+ kind: Ok(kind),
+ width,
dirty: true,
active: false,
id: ComponentId::new_v4(),
}
}
+ pub fn is_active(&self) -> bool {
+ self.active
+ }
+
+ pub fn set_kind(&mut self, kind: usize) {
+ self.stage = 0;
+ self.width = Self::KINDS[kind % Self::KINDS.len()]
+ .iter()
+ .map(|f| f.grapheme_len())
+ .max()
+ .unwrap_or(0);
+ self.kind = Ok(kind % Self::KINDS.len());
+ self.dirty = true;
+ }
+
+ pub fn set_custom_kind(&mut self, custom: Vec<String>) {
+ self.stage = 0;
+ self.width = custom.iter().map(|f| f.grapheme_len()).max().unwrap_or(0);
+ self.kind = Err(custom);
+ self.dirty = true;
+ }
+
pub fn start(&mut self) {
self.active = true;
self.timer
.set_interval(Self::INTERVAL)
- .set_value(Self::VALUE)
+ .set_value(Self::INTERVAL)
.rearm()
}
@@ -1117,6 +1160,12 @@ impl ProgressSpinner {
}
}
+impl Drop for ProgressSpinner {
+ fn drop(&mut self) {
+ self.stop();
+ }
+}
+
impl fmt::Display for ProgressSpinner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "progress bar")
@@ -1129,10 +1178,19 @@ impl Component for ProgressSpinner {
let theme_attr = crate::conf::value(context, "status.bar");
clear_area(grid, area, theme_attr);
if self.active {
- let stage = self.stage;
- self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[self.kind].len());
write_string_to_grid(
- Self::KINDS[self.kind][stage],
+ match self.kind.as_ref() {
+ Ok(kind) => {
+ let stage = self.stage;
+ self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[*kind].len());
+ Self::KINDS[*kind][stage].as_ref()
+ }
+ Err(custom) => {
+ let stage = self.stage;
+ self.stage = (self.stage + 1).wrapping_rem(custom.len());
+ custom[stage].as_ref()
+ }
+ },
grid,
theme_attr.fg,
theme_attr.bg,
diff --git a/src/conf/terminal.rs b/src/conf/terminal.rs
index 2138f171..781d72aa 100644
--- a/src/conf/terminal.rs
+++ b/src/conf/terminal.rs
@@ -47,6 +47,11 @@ pub struct TerminalSettings {
pub window_title: Option<String>,
#[serde(deserialize_with = "non_empty_string")]
pub file_picker_command: Option<String>,
+ /// Choose between 30-something built in sequences (integers between 0-30) or define your own
+ /// list of strings for the progress spinner animation.
+ /// Default: 0
+ #[serde(default)]
+ pub progress_spinner_sequence: Option<ProgressSpinnerSequence>,
}
impl Default for TerminalSettings {
@@ -60,6 +65,7 @@ impl Default for TerminalSettings {
mouse_flag: Some("🖱️ ".to_string()),
window_title: Some("meli".to_string()),
file_picker_command: None,
+ progress_spinner_sequence: None,
}
}
}
@@ -100,3 +106,12 @@ impl DotAddressable for TerminalSettings {
}
}
}
+
+#[derive(Debug, Deserialize, Clone, Serialize)]
+#[serde(untagged)]
+pub enum ProgressSpinnerSequence {
+ Integer(usize),
+ Custom(Vec<String>),
+}
+
+impl DotAddressable for ProgressSpinnerSequence {}