1
0
Fork 0
mirror of https://github.com/lise-henry/crowbook synced 2024-05-05 11:56:10 +02:00
crowbook/src/lib/book_bars.rs
Geobert Quach cd1739382b chore: update dependencies
Mainly `indicatif` and `clap` needed work
2023-01-01 16:05:44 +00:00

289 lines
9.5 KiB
Rust

// Copyright (C) 2017-2022 Γ‰lisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
// Progress bars implementation. Moved into a different file so it is possible
// to make some dependencies (incidacitf) optional.
use crate::book::{Book, Crowbar, CrowbarState};
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::sync::Arc;
use std::time::Duration;
/// Store the progress bars needed for the book
pub struct Bars {
/// Whether or not to use emoji
pub emoji: bool,
/// Container for the progress bars
pub multibar: Option<Arc<MultiProgress>>,
/// Main progress bar (actually a spinner)
pub mainbar: Option<ProgressBar>,
/// Secondary bar
pub secondbar: Option<ProgressBar>,
// /// Guard for thread
// pub guard: Option<thread::JoinHandle<()>>,
/// Spinners for each renderier
pub spinners: Vec<ProgressBar>,
}
impl Bars {
/// Create a new bars storage
pub fn new() -> Bars {
Bars {
emoji: false,
multibar: None,
mainbar: None,
secondbar: None,
// guard: None,
spinners: vec![],
}
}
}
impl Default for Bars {
fn default() -> Self {
Self::new()
}
}
/// Return the style of a bar
impl Book {
/// Adds a progress bar where where info should be written.
///
/// See [indicatif doc](https://docs.rs/indicatif) for more information.
pub fn private_add_progress_bar(&mut self, emoji: bool) {
self.bars.emoji = emoji;
let multibar = Arc::new(MultiProgress::new());
self.bars.multibar = Some(multibar.clone());
let b = self
.bars
.multibar
.as_ref()
.unwrap()
.add(ProgressBar::new_spinner());
b.enable_steady_tick(Duration::from_millis(200));
self.bars.mainbar = Some(b);
// let sty = ProgressStyle::default_spinner()
// .tick_chars("πŸ•›πŸ•πŸ•‘πŸ•’πŸ•“πŸ•”πŸ•”πŸ••πŸ•–πŸ•—πŸ•˜πŸ•˜πŸ•™πŸ•šV")
// .tick_chars("/|\\-V")
// .template("{spinner:.dim.bold.yellow} {prefix} {wide_msg}");
self.bar_set_style(Crowbar::Main, CrowbarState::Running);
// self.bars.guard = Some(thread::spawn(move || {
// if let Err(_) = multibar.join() {
// error!(
// "{}",
// lformat!("could not display fancy UI, try running crowbook with --no-fancy")
// );
// }
// }));
}
/// Sets a finished message to the progress bar, if it is set
pub fn bar_finish(&self, bar: Crowbar, state: CrowbarState, msg: &str) {
self.bar_set_style(bar, state);
let pb = match bar {
Crowbar::Main => {
if let Some(ref bar) = self.bars.mainbar {
bar
} else {
return;
}
}
Crowbar::Second => {
if let Some(ref bar) = self.bars.secondbar {
bar
} else {
return;
}
}
Crowbar::Spinner(i) => {
if i < self.bars.spinners.len() {
&self.bars.spinners[i]
} else {
return;
}
}
};
match bar {
Crowbar::Second => pb.finish_and_clear(),
_ => pb.finish_with_message(msg.to_owned()),
};
}
/// Adds a secondary progress bar to display progress of book parsing
pub fn add_second_bar(&mut self, msg: &str, len: u64) {
if let Some(ref multibar) = self.bars.multibar {
let bar = multibar.add(ProgressBar::new(len));
self.bar_set_style(Crowbar::Second, CrowbarState::Running);
bar.set_message(msg.to_owned());
self.bars.secondbar = Some(bar);
}
}
/// Increment second bar
pub fn inc_second_bar(&self) {
if let Some(ref bar) = self.bars.secondbar {
bar.inc(1);
}
}
/// Adds a spinner labeled key to the multibar, and set mainbar to "rendering"
pub fn add_spinner_to_multibar(&mut self, key: &str) -> usize {
if let Some(ref multibar) = self.bars.multibar {
if let Some(ref mainbar) = self.bars.mainbar {
mainbar.set_message(lformat!("Rendering..."));
}
let bar = multibar.add(ProgressBar::new_spinner());
bar.enable_steady_tick(Duration::from_millis(200));
bar.set_message(lformat!("waiting..."));
bar.set_prefix(format!("{}:", key));
let i = self.bars.spinners.len();
self.bars.spinners.push(bar);
self.bar_set_style(Crowbar::Spinner(i), CrowbarState::Running);
i
} else {
0
}
}
pub fn bar_set_message(&self, bar: Crowbar, msg: &str) {
let bar = match bar {
Crowbar::Main => {
if let Some(ref bar) = self.bars.mainbar {
bar
} else {
return;
}
}
Crowbar::Second => {
if let Some(ref bar) = self.bars.secondbar {
bar
} else {
return;
}
}
Crowbar::Spinner(i) => {
if i < self.bars.spinners.len() {
&self.bars.spinners[i]
} else {
return;
}
}
};
bar.set_message(msg.to_owned());
}
/// Sets the style of a bar
fn bar_set_style(&self, bar: Crowbar, state: CrowbarState) {
let pb = match bar {
Crowbar::Main => {
if let Some(ref bar) = self.bars.mainbar {
bar
} else {
return;
}
}
Crowbar::Second => {
if let Some(ref bar) = self.bars.secondbar {
bar
} else {
return;
}
}
Crowbar::Spinner(i) => {
if i < self.bars.spinners.len() {
&self.bars.spinners[i]
} else {
return;
}
}
};
let emoji = self.bars.emoji;
let mut style = match bar {
Crowbar::Second => ProgressStyle::default_bar(),
_ => ProgressStyle::default_spinner(),
};
let color = match state {
CrowbarState::Running => "yellow",
CrowbarState::Success => "cyan",
CrowbarState::Error => "red",
};
let tick_chars = match (bar, emoji) {
(Crowbar::Main, false) | (Crowbar::Spinner(_), false) => "-\\|/",
(Crowbar::Main, true) => "πŸ•›πŸ•πŸ•‘πŸ•’πŸ•“πŸ•”πŸ•”πŸ••πŸ•–πŸ•—πŸ•˜πŸ•˜πŸ•™πŸ•š",
(Crowbar::Spinner(_), true) => "◐◓◑◒",
(_, _) => "",
};
let end_tick = match (state, emoji) {
(CrowbarState::Running, _) => "V",
(CrowbarState::Success, true) => "βœ”",
(CrowbarState::Error, true) => "❌",
(CrowbarState::Success, false) => "V",
(CrowbarState::Error, false) => "X",
};
match bar {
Crowbar::Second => {
style = style
.template("{bar:40.cyan/blue} {percent:>7} {wide_msg}")
.expect("Error in second progress bar style")
.progress_chars("##-");
}
bar => {
style = style.tick_chars(&format!("{}{}", tick_chars, end_tick));
match bar {
Crowbar::Spinner(_) => {
style = style
.template(&format!(
"{{spinner:.bold.{color}}} {{prefix}} {{wide_msg}}",
color = color
))
.expect("Error in spinner progress bar style");
}
_ => {
style = style
.template(&format!(
"{{spinner:.bold.{color}}} {{prefix}}{{wide_msg}}",
color = color
))
.expect("Error in progress bar style");
}
};
}
}
pb.set_style(style);
}
}
impl Drop for Book {
fn drop(&mut self) {
if let Some(ref bar) = self.bars.secondbar {
bar.finish_and_clear();
}
if let Some(ref bar) = self.bars.mainbar {
bar.finish();
// let guard = mem::replace(&mut self.bars.guard, None);
// guard.unwrap().join().unwrap();
}
}
}