mirror of
https://github.com/lise-henry/crowbook
synced 2024-05-05 11:56:10 +02:00
cd1739382b
Mainly `indicatif` and `clap` needed work
289 lines
9.5 KiB
Rust
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();
|
|
}
|
|
}
|
|
}
|