indicatif
A Rust library for indicating progress in command line applications to users.
This currently primarily provides progress bars and spinners as well as basic color support, but there are bigger plans for the future of this!
A Rust library for indicating progress in command line applications to users.
This currently primarily provides progress bars and spinners as well as basic color support, but there are bigger plans for the future of this!
Very much a janky WIP, and some of the objects I introduced could use better naming though I avoided doing so in the interest of retaining compatibility with existing code. Haven't tested this against older rustc, but as of my current rustc version (latest stable) there are no lints from either regular check or clippy. But let me know if this seems like an ok direction and I'll revise it further.
~~Somewhen I'll modify that example to show what a more bumpy file transfer looks like, and the advantage of averaging it by the method I used.~~ done
Here's a first draft of how I think Ticker
should work.
So far the only testing I've done is to confirm that the long-spinner example works OK. I have not yet tested the modified version of it (which uses the Barrier
s).
Fixes #416.
TODO:
Work-in-progress pull request for implementing println. This does not currently work as nothing is printed for some reason. I have reason to believe it is due to an interaction with e46ca83e, since if you change the line below to m.println("Starting...\n\n")
it works.
This code used to print the progress bar, and then "Something" on the next line:
use std::thread;
use std::time::Duration;
use indicatif::ProgressBar;
fn main() {
let pb = ProgressBar::new(1024);
for _ in 0..1024 {
pb.inc(1);
thread::sleep(Duration::from_millis(5));
}
pb.finish_with_message("done");
println!("Something");
}
However after #338 it prints the progress bar and the first character of what should be the next line ("S") on the same line, and then "omething" on the next line, like so:
██████████████████ 1024/1024S
omething
This PR adds support for multi-line progress messages, following #442.
The changes mostly update the drawing functions to split progress messages before counting them, so that the correct number of lines are cleared when they are redrawn. I'm not sure I 100% understood how orphan lines work, so I'd appreciate if someone could take a closer look at how I handle them.
The existing examples all run as they did previously, and I've added a new example (multi-log
) showing the style I was trying to implement when I opened the issue.
One thing I noticed is that calling clear
on a multiline progress doesn't always seem to clear all progress messages, a random amount stays on the screen even when a message is printed afterwards. I first thought that I introduced that bug, but switching back to main it still appeared in the examples I tried (yarnish
and multi
). Is this a known bug?
There have been a lot of changes since 0.16.2 was released in May 2021.
https://github.com/mitsuhiko/indicatif/compare/0.16.2...main
Thanks for this awesome library!
I think there are two parts to #397:
MutexGuard<BarState>
, we also need to drop the Arc<Mutex<BarState>>
, otherwise the reference count will never drop to 0 while the thread sleeps. The main thread will exit, but the destructor (on the Ticker
thread's stack) will not run.join
the JoinHandle
. Trouble is I am not yet sure where to put the join
. It can't go in the Drop
impl for BarState
since then the thread would probably try to join itself. Perhaps we need to move the ticker state into an Arc<Mutex<Option<TickerState>>>
in ProgressBar
or something. Then we could rewrite Ticker::run
to use, e.g. CondVar::wait_timeout
instead of thread::sleep(self.interval)
.So more experimenting is necessary.
Here is an example of the issue https://github.com/ouch-org/ouch/pull/214
I think this line https://github.com/mitsuhiko/indicatif/blob/c43d7b3d8789027835771888310f2a1416665de1/src/style.rs#L293 only expects one wide element
If this is an intended behavior, I can open a pr to document this
With 0.17.0-rc.6, set_draw_delta
is no longer.
In my application using 0.16.2, I used it effectively to limit updates to every 1% of progress with an inc(1)
inside a loop with millions of iterations by doing set_draw_delta( record_count / 100);
.
I understand that with 0.17, a lot of refactoring was done to improve performance.
Is it no longer necessary to use set_draw_delta
then and I can just do inc(1)
for a loop with millions of rows and the indicatif overhead will be minimal?
This function hides the progress bar temporarily, execute f
, then redraws the progress bar, which is useful for external code that writes to the standard output.
The idea is originally raised in #92.
It is planned to eventually create a global function like ProgressBar::instance
that allows calling suspend
from e.g. a log handler, but this currently doesn't generalize to MultiProgressBar
which could be an obstacle.
Following code gives this output (using current main branch, and also in 0.16.2
so this behaviour hasn't changed):
0/3 Step 1
1/3 Step 2
2/3 Step 3
3/3 Step 3
If I move progress.inc(1);
before set_message
then I get this output instead:
1/3
2/3 Step 1
3/3 Step 2
3/3 Step 3
But what I want is to have pos
and msg
in sync like this:
1/3 Step 1
2/3 Step 2
3/3 Step 3
Code:
fn main() {
let progress = ProgressBar::new(3);
progress.set_style(ProgressStyle::default_bar().template("{pos}/{len} {msg}"));
for n in 1..=3 {
progress.set_message(format!("Step {}", n));
progress.inc(1);
std::thread::sleep(Duration::from_secs(2));
}
progress.finish();
}
Build pass but dead lock while running. Tested with indicatif == 0.17.2
.
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
fn main() {
let mp = MultiProgress::new();
let pb = ProgressBar::new(0);
let style = ProgressStyle::with_template("{msg}").unwrap();
pb.set_style(style);
mp.add(pb.clone());
mp.add(pb.clone());
pb.set_message("Boom!");
pb.finish();
}
Output while running:
thread 'main' panicked at 'rwlock write lock would result in deadlock', /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys/unix/locks/pthread_rwlock.rs:111:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: PoisonError { .. }', /Users/kaizhao/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/indicatif-0.17.2/src/draw_target.rs:114:65
stack backtrace:
0: 0x10580b682 - std::backtrace_rs::backtrace::libunwind::trace::h74d17ea919046bae
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x10580b682 - std::backtrace_rs::backtrace::trace_unsynchronized::h2fc77fd5a14165ac
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x10580b682 - std::sys_common::backtrace::_print_fmt::h2687aa7717781133
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:65:5
3: 0x10580b682 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hdc69a6f447628e71
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:44:22
4: 0x1058245aa - core::fmt::write::hb9e764fa47ae8444
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/fmt/mod.rs:1209:17
5: 0x10580933c - std::io::Write::write_fmt::h8fc98987ed860a54
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/io/mod.rs:1682:15
6: 0x10580b44a - std::sys_common::backtrace::_print::h882e8250b822b8b0
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:47:5
7: 0x10580b44a - std::sys_common::backtrace::print::h488fe4c0b1fb9d50
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:34:9
8: 0x10580cb16 - std::panicking::default_hook::{{closure}}::h5618ea3156b8b833
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:267:22
9: 0x10580c867 - std::panicking::default_hook::h0421c26a8a92801c
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:286:9
10: 0x10580d25d - std::panicking::rust_panic_with_hook::h57383cd32463c250
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:688:13
11: 0x10580d013 - std::panicking::begin_panic_handler::{{closure}}::h1d1f7305cfe67fdd
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:579:13
12: 0x10580bb18 - std::sys_common::backtrace::__rust_end_short_backtrace::hd8e12e82ff026bae
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:137:18
13: 0x10580ccdd - rust_begin_unwind
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:575:5
14: 0x10582cd23 - core::panicking::panic_fmt::h7894cd1015cfee41
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/panicking.rs:65:14
15: 0x10582cf75 - core::result::unwrap_failed::h3077b600131e58d4
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/result.rs:1791:5
16: 0x1057c7a3c - core::result::Result<T,E>::unwrap::h3324c50c72235e7b
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/result.rs:1113:23
17: 0x1057b5245 - indicatif::draw_target::ProgressDrawTarget::width::h10f484b78fe41f38
at /Users/kaizhao/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/indicatif-0.17.2/src/draw_target.rs:114:52
18: 0x1057bffe9 - indicatif::state::BarState::draw::hef0a6bd659ade04e
at /Users/kaizhao/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/indicatif-0.17.2/src/state.rs:164:21
19: 0x1057bfaa1 - indicatif::state::BarState::finish_using_style::h9e86e00fe3c32e82
at /Users/kaizhao/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/indicatif-0.17.2/src/state.rs:64:17
20: 0x1057c0304 - <indicatif::state::BarState as core::ops::drop::Drop>::drop::h5500f1a4ff546e95
at /Users/kaizhao/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/indicatif-0.17.2/src/state.rs:195:9
21: 0x1057aba55 - core::ptr::drop_in_place<indicatif::state::BarState>::ha76e737d2a9b1c57
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ptr/mod.rs:490:1
22: 0x1057acca1 - core::ptr::drop_in_place<core::cell::UnsafeCell<indicatif::state::BarState>>::hae90256bc4473fc8
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ptr/mod.rs:490:1
23: 0x1057acda1 - core::ptr::drop_in_place<std::sync::mutex::Mutex<indicatif::state::BarState>>::he96c415f95f3be34
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ptr/mod.rs:490:1
24: 0x1057a26b4 - alloc::sync::Arc<T>::drop_slow::h58937141ea099b10
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/alloc/src/sync.rs:1114:18
25: 0x1057a2e14 - <alloc::sync::Arc<T> as core::ops::drop::Drop>::drop::h19ccb4630bd85572
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/alloc/src/sync.rs:1711:13
26: 0x1057ab461 - core::ptr::drop_in_place<alloc::sync::Arc<std::sync::mutex::Mutex<indicatif::state::BarState>>>::h3fbcd49dd933d568
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ptr/mod.rs:490:1
27: 0x1057ac465 - core::ptr::drop_in_place<indicatif::progress_bar::ProgressBar>::h70a0273cf2185db7
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ptr/mod.rs:490:1
28: 0x10579e0ae - dead_lock_multiprogress_add_same_progressbar::main::hc8c00eaea5f96442
at /Users/kaizhao/lab/rust/indicatif/dead-lock-multiprogress-add-same-progressbar/src/main.rs:20:1
29: 0x10579e21e - core::ops::function::FnOnce::call_once::h4f1d6e4dbc09e830
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ops/function.rs:251:5
30: 0x10579e7d1 - std::sys_common::backtrace::__rust_begin_short_backtrace::h9302ea09b14b2009
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/sys_common/backtrace.rs:121:18
31: 0x10579e024 - std::rt::lang_start::{{closure}}::he04aac1f5b3f6d23
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/rt.rs:166:18
32: 0x105806834 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h61195f273fbb2744
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ops/function.rs:286:13
33: 0x105806834 - std::panicking::try::do_call::h742c41daae50fa78
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:483:40
34: 0x105806834 - std::panicking::try::h289fd06090f9252d
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:447:19
35: 0x105806834 - std::panic::catch_unwind::h442e40ac2db064f5
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panic.rs:137:14
36: 0x105806834 - std::rt::lang_start_internal::{{closure}}::haebd6112c3b7ec52
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/rt.rs:148:48
37: 0x105806834 - std::panicking::try::do_call::h5621965127b9aadb
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:483:40
38: 0x105806834 - std::panicking::try::h55c66b03bc020b32
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:447:19
39: 0x105806834 - std::panic::catch_unwind::hf00d6becf2cfdae2
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panic.rs:137:14
40: 0x105806834 - std::rt::lang_start_internal::h9ca2efac34d80f78
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/rt.rs:148:20
41: 0x10579dff7 - std::rt::lang_start::hd9833a935556224b
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/rt.rs:165:17
42: 0x10579e1e8 - _main
thread panicked while panicking. aborting.
I have no idea if this is a bug. Tested with indicatif == 0.17.2
.
The good one which can be cleared when set_position
after added to MultiProgress
:
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
fn main() {
let mp = MultiProgress::new();
let pb = ProgressBar::new(0);
let style = ProgressStyle::with_template("{msg}").unwrap();
pb.set_style(style);
mp.add(pb.clone());
let pb2 = ProgressBar::new(100);
let style2 = ProgressStyle::with_template("{bar}").unwrap();
pb2.set_style(style2);
mp.add(pb2.clone());
pb2.set_position(0);
pb2.finish_and_clear();
pb.set_message("Good!");
pb.finish();
}
Output:
Good!
The bad one which can't be cleared when set_position
before added to MultiProgress
:
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
fn main() {
let mp = MultiProgress::new();
let pb = ProgressBar::new(0);
let style = ProgressStyle::with_template("{msg}").unwrap();
pb.set_style(style);
mp.add(pb.clone());
let pb2 = ProgressBar::new(100);
let style2 = ProgressStyle::with_template("{bar}").unwrap();
pb2.set_style(style2);
pb2.set_position(0);
mp.add(pb2.clone());
pb2.finish_and_clear();
pb.set_message("Bad!");
pb.finish();
}
Output:
░░░░░░░░░░░░░░░░░░░░
Bad!
I am experiencing my ProgressBar scrolling instead of truncating/redrawing when I shrink my terminal's window.
I am running on a remote Ubuntu server. Terminal is Mac's iTerm2, with and without tmux. The ProgressBar's template uses {wide_msg}
, so I expect the progress bar to truncate text as the window sizes decreases.
This only manifests when I shrink my past the ◎
character. If this character is not present in the message, the progress bar works as expected regardless of how small I shrink my terminal's window.
Also, version v0.16.2 does not exhibit this behavior; it works as expected.
I've tried v0.17.1 and v0.17.2. With v0.17.2 I also tried using the "improved_unicode" feature. None of these resulted in correct behavior.
Here's more information in an issue I have against my repo where I debugged this: https://github.com/solana-labs/solana/issues/29158
If it's helpful, I can get a screen capture and/or a set of steps to reproduce the issue (may be slightly involved though). Thanks in advance!
Similar to #144 , if progress bars exceeds terminal's height i.e if there are more progress bars than it is able fit in visible at once, newlines are created. Fix provided in #144 doesn't help either.
indicatif = "0.17.2"
use std::thread;
use std::time::Duration;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
fn main() {
let m = MultiProgress::new();
let sty = ProgressStyle::with_template(
"[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}",
)
.unwrap()
.progress_chars("##-");
m.println("starting!").unwrap();
let mut h = vec![];
for _ in 0..50 {
let pb = m.add(ProgressBar::new(128));
pb.set_style(sty.clone());
let m_clone = m.clone();
let h1 = thread::spawn(move || {
for i in 0..128 {
pb.set_message(format!("item #{}", i + 1));
pb.inc(1);
thread::sleep(Duration::from_millis(50));
}
m_clone.println("pb1 is done!").unwrap();
pb.finish_with_message("done");
});
h.push(h1);
}
for k in h {
k.join().unwrap();
}
// m.clear().unwrap();
}
It seems that this originated in 71e7eaab9070f2cc34e9002074fe28c9f3fb371f.
The previous behavior was that the per_sec and eta values would be relatively steady throughout the life of the progress bar, as they simply calculated pos / (now - start_time)
.
The new behavior instead calculates (pos - prev_pos) / (now - prev_time)
. Since this no longer has the effect of averaging out fast and slow spikes since the start of the progress bar, it causes the values in per_sec and eta to fluctuate wildly between each tick. In my opinion, this is undesirable.
A small maintenance release which makes indicatif more portable and fixes some minor regressions.
On behalf of @djc and @chris-laplante, thanks to all contributors!
Source code(tar.gz)2.5 months after the large 0.17 release, we (finally) have a release that addresses most of the regressions found in 0.17. There is ongoing work on changes in the estimation algorithm, tracked in #394, which has regressed for some users.
Note that we made some technically semver-breaking change of adding a missing Sync
bound to the ProgressTracker
bounds (#471). We're assuming that most users don't (yet) have custom ProgressTracker
impls, and that users who do have probably built one that is Sync
anyway.
unicode-width
feature spelling (#456)MultiProgress
zombie line handling (#460)ProgressBar::style()
(#476, thanks to @andrewchambers)HumanFloatCount
formatting option (#453, thanks to @jqnatividad)Sync
bound to ProgressTracker
(#471)write_all()
impl from ProgressBarIter
's Write
impl (#478, thanks to @hexagonal-sun)Thanks from @djc and @chris-laplante to all contributors!
Source code(tar.gz)indicatif is one of the most popular terminal progress bar libraries in the Rust ecosystem. More than a year after the 0.16.0 release, we're happy to finally release 0.17. In the past year, the indicatif team has grown to two maintainers, since @chris-laplante joined @djc as a maintainer. We also now have a Discord channel.
Apart from many small API additions and fixes, particular effort has gone into reducing the overhead for reporting progress. To this end, we've removed some of the explicit rate limiting APIs in favor of a single refresh rate in the ProgressDrawTarget
. We now set a rate limit by default (50ms) that should drastically reduce overhead for most applications while being more than enough for most terminal applications. Additionally, position updates are now synchronized by using atomic integer APIs instead of a mutex. In a basic test the simplest possible progress bar is about 95x faster on 0.17.0 compared to 0.16.2.
We've made many changes to the way MultiProgress
collections work. You no longer need to explicitly join()
the MultiProgress
, there are more ways to insert new progress bars into the collection, and many correctness improvements have been made, in part to more effort having gone into testing the crate.
Additionally, we've reduced our dependency footprint, removing lazy_static and regex from our required dependencies.
HumanCount
and template keys to print more humane position/length (#340, thanks to @dabreegster)ProgressBar::suspend()
(#333, thanks to @ishitatsuyuki)ProgressIterator::progress_with_style()
(#306, thanks to @LeCyberDucky)stream_position()
in ProgressBarIter
(#309, thanks to @rlee287)AsyncRead
/AsyncWrite
support for ProgressBar
(#308, thanks to @x0f5c3)AsyncBufRead
implementation for ProgressBarIterator
(#315, thanks to @x0f5c3)ProgressBarIter
(#337, thanks to @chubei-oppen)ProgressBar
elapsed time (#325, thanks to @zhaofengli)ProgressBar::style()
to enable access to the current style (#396, thanks to @andrewchambers)ProgressDrawTarget
to reduce in-memory size (#277, thanks to @mibac138)MultiProgress
changesMultiProgress
drawing on the main thread (#231 and #284, thanks to @marienz and @aj-bagwell)MultiProgress
(#326, thanks to @omjadas)insert_after()
/insert_before()
methods on MultiProgress
(#331, with follow up in #424)MultiProgress
: add println()
and suspend()
methods (#351)MultiProgress
: prune zombie progress bars (#438, with follow up in #446)is_hidden()
work for MultiProgress
(#430)MultiProgress
bars (#295, thanks to @nlinker)ProgressFolder
shouldn't finish progress bars on completion (#290, thanks to @mibac138)per_sec
values to make them more readable (#312)HumanDuration
values (#296, thanks to @Armavica)WeakProgressBar::new()
should not take self
(#359, thanks to @ishitatsuyuki)wide_bar
and wide_msg
(#329, thanks to @sigmaSd)doc(cfg)
to improve docs.rs documentation (#399)Option
(#415)narrate This library provides CLI application error and status reporting utilities. The coloured output formatting aims to be similar to Cargo. Error
Ara Reporting A Reporting library for Ara Programming Language ?? Internally, Ara reporting uses the codespan-reporting library to build a report of t
tqdm Rust implementation of Python command line progress bar tool tqdm. From original documentation: tqdm derives from the Arabic word taqaddum (تقدّم
swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .
line2httppost Simple tool to read lines from stdin and post each line as separate POST request to a specified URL (TCP connection is reused though). G
Pink is a command-line tool inspired by the Unix man command. It displays custom-formatted text pages in the terminal using a subset of HTML-like tags.
Terminal progress bar for Rust Console progress bar for Rust Inspired from pb, support and tested on MacOS, Linux and Windows Documentation Examples s
status-line This crate allows you to display status & progress information in a terminal This crate handles the problem of displaying a small amount o
unosolo Work-in-progress Rust application that converts C++ header-only libraries to single self-contained headers. Disclaimer This is my first Rust p
PoC: Integrating Rust in Python A toy example showing how to run Rust code in Python for speed and progress. Requirements Python 3.6+ Rust 1.44+ Cargo
Experimental Tailscale PAM Module This is a very very experimental Tailscale PAM module that allows you to SSH using your Tailscale credentials. This
zman zman is a CLI year (time) progress that small, fast, and just one single binary. Features Show year progress Show month, and week progress Show r
azeron-cli A small, unfinished CLI application intended to manage the Azeron Cyborg. The code is still in a very messy state and doesn't look very rus
Lomanai Usage lomanai --species 'Mus musculus' --species 'Homo sapiens' #> Mammalia #> ++Rodentia #> | \-Mus musculus #> \+Primates #> \-Homo sapien
Statan Statan is an early-stage static analyser for PHP and PXP projects. It is being developed in public and the journey is documented on my blog. Th
jalm Generate Progress Bars from Cron Expressions Installation and Usage Grab the latest binary from the Github Actions tab. Alternatively, to build f
tracing-indicatif A tracing layer that automatically creates and manages indicatif progress bars for active spans. Progress bars are a great way to ma
monologue A Content Discovery Tool written in Rust, insipired from Feroxbuster. Installation Dependencies OpenSSL (If You are on linux). Rust programm
A high level DSL for Simplicity. This is a work in progress and is not yet ready for production use. The language is designed to be simple and easy to use. It is inspired by rust syntax and is statically typed. The syntax will be extended in the future to support more features.