-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
1,985 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "ml-progress" | ||
version = "0.1.0" | ||
license = "MIT" | ||
description = "Single line progress indicator for terminal/console." | ||
repository = "https://github.com/malaire/ml-progress" | ||
keywords = [ "cli", "console", "progress", "progressbar", "terminal" ] | ||
categories = [ "command-line-interface" ] | ||
edition = "2021" | ||
|
||
include = [ | ||
"/src", | ||
"LICENSE", | ||
"README.md", | ||
"build.rs", | ||
] | ||
|
||
[dependencies] | ||
parking_lot = "0.12.0" | ||
terminal_size = "0.1.17" | ||
|
||
[build-dependencies] | ||
readme-rustdocifier = "0.1.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,355 @@ | ||
# ml-progress | ||
|
||
Progress indicator for terminal/console. | ||
|
||
- single line | ||
- no ANSI escape codes, just `\r` | ||
- background thread for timely updates | ||
- opinionated syntax | ||
|
||
**Early version - this hasn't yet been tested properly.** | ||
|
||
## Usage | ||
|
||
1. Either | ||
- create [`Progress`] with [`progress!`] macro | ||
(if you don't need custom configuration) or | ||
- create [`ProgressBuilder`] with [`progress_builder!`] macro, | ||
set custom options, and then create [`Progress`] with [`build`]. | ||
2. During prosessing update state with [`inc`] and [`message`]. | ||
3. Finish using one of [`finish`], [`finish_and_clear`] | ||
or [`finish_at_current_pos`]. | ||
|
||
## Examples | ||
|
||
### Default items | ||
|
||
```rust | ||
use ml_progress::progress; | ||
|
||
let progress = progress!(10)?; | ||
for _ in 0..10 { | ||
// std::thread::sleep(std::time::Duration::from_millis(500)); | ||
progress.inc(1); | ||
} | ||
progress.finish(); | ||
|
||
# Ok::<(), ml_progress::Error>(()) | ||
``` | ||
|
||
```text | ||
##############################-------------------- 6/10 (2s) | ||
``` | ||
|
||
### Custom items | ||
|
||
```rust | ||
use ml_progress::progress; | ||
|
||
let progress = progress!( | ||
10; | ||
"[" percent "] " pos "/" total " " bar_fill " (" eta_hms ")" | ||
)?; | ||
for _ in 0..10 { | ||
// std::thread::sleep(std::time::Duration::from_millis(500)); | ||
progress.inc(1); | ||
} | ||
progress.finish(); | ||
|
||
# Ok::<(), ml_progress::Error>(()) | ||
``` | ||
|
||
```text | ||
[ 60%] 6/10 ########################----------------- (0:02) | ||
``` | ||
|
||
### Custom configuration | ||
|
||
```rust | ||
use ml_progress::progress_builder; | ||
|
||
let progress = progress_builder!( | ||
"[" percent "] " pos_group "/" total_group " " bar_fill " (" eta_hms ")" | ||
) | ||
.total(Some(10000)) | ||
.thousands_separator(",") | ||
.build()?; | ||
|
||
for _ in 0..10 { | ||
// std::thread::sleep(std::time::Duration::from_millis(500)); | ||
progress.inc(1000); | ||
} | ||
progress.finish(); | ||
|
||
# Ok::<(), ml_progress::Error>(()) | ||
``` | ||
|
||
```text | ||
[ 60%] 6,000/10,000 ###################-------------- (0:02) | ||
``` | ||
|
||
## Items | ||
|
||
Items are used with [`progress!`] and [`progress_builder!`] macros. | ||
|
||
- Each item is either a single token (e.g. `bar_fill`) | ||
or multiple tokens surrounded by parentheses (e.g. `(eta "{:2}{:1}")`). | ||
- Items are given without separators in between, except whitespace. | ||
- At most one `*_fill` item is allowed. | ||
|
||
### Summary | ||
|
||
Summary of all possible items. See below for further details. | ||
|
||
```ignore | ||
"foo" // "foo" | ||
bar_fill // "######----" | ||
eta // "5m" ; same as (eta "{}{}") | ||
(eta FORMAT NONE) // u64, &str | ||
eta_hms // "5:23" | ||
message_fill // "foo" | ||
percent // " 23%" ; same as (percent "{:3.0}%") | ||
(percent FORMAT NONE) // f64 | ||
pos // "1234567" ; same as (pos "{}" ) | ||
pos_group // "1 234 567" ; same as (pos "{:#}" ) | ||
pos_bin // "1.18 Mi" ; same as (pos_bin "{:#} {}") | ||
pos_dec // "1.23 M" ; same as (pos_dec "{:#} {}") | ||
(pos FORMAT) // u64 | ||
(pos_bin FORMAT) // f64, prefix | ||
(pos_dec FORMAT) // f64, prefix | ||
speed // "1234567" ; same as (speed "{:#}" ) | ||
speed_int // "1234567" ; same as (speed_int "{}" ) | ||
speed_group // "1 234 567" ; same as (speed_int "{:#}" ) | ||
speed_bin // "1.18 Mi" ; same as (speed_bin "{:#} {}") | ||
speed_dec // "1.23 M" ; same as (speed_dec "{:#} {}") | ||
(speed FORMAT NONE) // f64 | ||
(speed_int FORMAT NONE) // u64 | ||
(speed_bin FORMAT NONE) // f64, prefix | ||
(speed_dec FORMAT NONE) // f64, prefix | ||
total // "1234567" ; same as (total "{}" ) | ||
total_group // "1 234 567" ; same as (total "{:#}" ) | ||
total_bin // "1.18 Mi" ; same as (total_bin "{:#} {}") | ||
total_dec // "1.23 M" ; same as (total_dec "{:#} {}") | ||
(total FORMAT NONE) // u64 | ||
(total_bin FORMAT NONE) // f64, prefix | ||
(total_dec FORMAT NONE) // f64, prefix | ||
(|state| EXPR) | ||
``` | ||
|
||
`FORMAT` | ||
- Normal Rust format string with special handling of `#` "alternate" flag (see below). | ||
|
||
`NONE` | ||
- Literal value to be shown when value in question is `None`. | ||
- See corresponding functions of [`State`] about when values are `None`. | ||
- This is optional and can be left out. Default value is empty string. | ||
|
||
### Prefixes | ||
|
||
- Items ending with `_bin` use 1024-based binary prefixes (`Ki`, `Mi`, `Gi`, ...). | ||
- Items ending with `_dec` use 1000-based decimal prefixes (`k`, `M`, `G`, ...). | ||
|
||
If value is below 1024 or 1000 then prefix is empty string. | ||
|
||
### Alternate format | ||
|
||
When `#` "alternate" flag is used in `FORMAT`, | ||
following applies based on type: | ||
|
||
- `u64` is formatted with digits in groups of three. | ||
- Thousands separator can be set with [`ProgressBuilder::thousands_separator`], | ||
default is space. | ||
- e.g. `1234567` with `"{:#}"` is shown as `"1 234 567"` with default separator | ||
- `f64` | ||
- Format `precision` (default: 4) is considered "fit width" and value is | ||
shown with maximum number of decimals so that it fits this width, | ||
or with no decimals if fit is not possible. | ||
- With `pos_bin`, `pos_dec`, `total_bin` and `total_dec`: | ||
Amounts with empty prefix are shown with no decimals. | ||
- Examples | ||
- `1.2345` with `"{:#}"` is shown as `"1.23"` | ||
- `12.345` with `"{:#}"` is shown as `"12.3"` | ||
- `123.45` with `"{:#}"` is shown as `"123"` | ||
- `1234.5` with `"{:#}"` is shown as `"1235"` | ||
- `12345` with `"{:#}"` is shown as `"12345"` | ||
- `prefix` | ||
- `"{:#}"` shows empty prefix as-is | ||
and other prefixes with prepended space. | ||
|
||
### Literal | ||
|
||
```ignore | ||
"foo" // "foo" | ||
``` | ||
Shows given literal string. | ||
|
||
### `bar_fill` | ||
|
||
```ignore | ||
bar_fill // "######----" | ||
``` | ||
Shows progress bar which fills remaining space on the line. | ||
|
||
- Spaces are shown instead if `total` is `None`. | ||
|
||
### `eta` | ||
|
||
```ignore | ||
eta // "5m" ; same as (eta "{}{}") | ||
(eta FORMAT) // u64, &str | ||
(eta FORMAT NONE) | ||
``` | ||
Shows estimated time remaining in approximate format: amount and unit, | ||
or `NONE` if estimate is not available. | ||
|
||
- Amount is the number of full units, i.e. it's not rounded. | ||
- Unit can be `h` (hours), `m` (minutes) or `s` (seconds) | ||
|
||
### `eta_hms` | ||
|
||
```ignore | ||
eta_hms // "12:34:56" "0:56" | ||
``` | ||
Shows estimated time remaining as hours/minutes/seconds, | ||
or empty string if estimate is not available. | ||
|
||
- Depending on magnitude format is one of | ||
H:MM:SS, MM:SS or M:SS. | ||
- Value is the number of full seconds, i.e. it's not rounded. | ||
|
||
### `message_fill` | ||
|
||
```ignore | ||
message_fill // "foo" | ||
``` | ||
Shows the message set with [`Progress::message`][`message`], | ||
filling the remaining space on the line. | ||
|
||
### `percent` | ||
|
||
```ignore | ||
percent // " 23%" ; same as (percent "{:3.0}%") | ||
(percent FORMAT) // f64 | ||
(percent FORMAT NONE) | ||
``` | ||
Shows percentual completion or `NONE` if `total` is `None`. | ||
|
||
### `pos` | ||
|
||
```ignore | ||
pos // "1234567" ; same as (pos "{}" ) | ||
pos_group // "1 234 567" ; same as (pos "{:#}" ) | ||
pos_bin // "1.18 Mi" ; same as (pos_bin "{:#} {}") | ||
pos_dec // "1.23 M" ; same as (pos_dec "{:#} {}") | ||
(pos FORMAT) // u64 | ||
(pos_bin FORMAT) // f64, prefix | ||
(pos_dec FORMAT) // f64, prefix | ||
``` | ||
Shows position. | ||
- `pos` - as integer | ||
- `pos_group` - as integer, with digits in groups of three | ||
- `pos_bin` - as floating-point amount with binary prefix | ||
- `pos_dec` - as floating-point amount with decimal prefix | ||
|
||
### `speed` | ||
|
||
```ignore | ||
speed // "1234567" ; same as (speed "{:#}" ) | ||
speed_int // "1234567" ; same as (speed_int "{}" ) | ||
speed_group // "1 234 567" ; same as (speed_int "{:#}" ) | ||
speed_bin // "1.18 Mi" ; same as (speed_bin "{:#} {}") | ||
speed_dec // "1.23 M" ; same as (speed_dec "{:#} {}") | ||
(speed FORMAT) // f64 | ||
(speed FORMAT NONE) | ||
(speed_int FORMAT) // u64 | ||
(speed_int FORMAT NONE) | ||
(speed_bin FORMAT) // f64, prefix | ||
(speed_bin FORMAT NONE) | ||
(speed_dec FORMAT) // f64, prefix | ||
(speed_dec FORMAT NONE) | ||
``` | ||
Shows speed as steps per second or `NONE` if speed is not available. | ||
- `speed` - as floating-point | ||
- `speed_int` - as integer | ||
- `speed_group` - as integer, with digits in groups of three | ||
- `speed_bin` - as floating-point amount with binary prefix | ||
- `speed_dec` - as floating-point amount with decimal prefix | ||
|
||
### `total` | ||
|
||
```ignore | ||
total // "1234567" ; same as (total "{}" ) | ||
total_group // "1 234 567" ; same as (total "{:#}" ) | ||
total_bin // "1.18 Mi" ; same as (total_bin "{:#} {}") | ||
total_dec // "1.23 M" ; same as (total_dec "{:#} {}") | ||
(total FORMAT) // u64 | ||
(total FORMAT NONE) | ||
(total_bin FORMAT) // f64, prefix | ||
(total_bin FORMAT NONE) | ||
(total_dec FORMAT) // f64, prefix | ||
(total_dec FORMAT NONE) | ||
``` | ||
Shows total or `NONE` if `total` is `None`. | ||
- `total` - as integer | ||
- `total_group` - as integer, with digits in groups of three | ||
- `total_bin` - as floating-point amount with binary prefix | ||
- `total_dec` - as floating-point amount with decimal prefix | ||
|
||
### Custom item | ||
|
||
```ignore | ||
(|state| EXPR) | ||
``` | ||
Shows return value of given function | ||
which takes [`State`] as input and returns `String`. | ||
|
||
```ignore | ||
(|s| custom_eta(s)) // "12h 34m 56s" | ||
``` | ||
|
||
```no_run | ||
use ml_progress::State; | ||
fn custom_eta(state: &State) -> String { | ||
if let Some(eta) = state.eta() { | ||
let (h, m, s) = ml_progress::duration_hms(eta); | ||
if h > 0 { | ||
format!("{}h {}m {}s", h, m, s) | ||
} else if m > 0 { | ||
format!("{}m {}s", m, s) | ||
} else { | ||
format!("{}s", s) | ||
} | ||
} else { | ||
"".to_string() | ||
} | ||
} | ||
``` | ||
|
||
[`Progress`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html | ||
[`finish`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html#method.finish | ||
[`finish_and_clear`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html#method.finish_and_clear | ||
[`finish_at_current_pos`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html#method.finish_at_current_pos | ||
[`inc`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html#method.inc | ||
[`message`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.Progress.html#method.message | ||
|
||
[`ProgressBuilder`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.ProgressBuilder.html | ||
[`build`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.ProgressBuilder.html#method.build | ||
[`ProgressBuilder::thousands_separator`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.ProgressBuilder.html#method.thousands_separator | ||
|
||
[`State`]: https://docs.rs/ml-progress/0.1.0/ml_progress/struct.State.html | ||
|
||
[`progress!`]: https://docs.rs/ml-progress/0.1.0/ml_progress/macro.progress.html | ||
[`progress_builder!`]: https://docs.rs/ml-progress/0.1.0/ml_progress/macro.progress_builder.html |
Oops, something went wrong.