🎙 A compact library for working with user output

Overview

🎙 Storyteller

A library for working with user output

Table of contents

Introduction

This library is intended to be used by tools, such as cli's, which have multiple user interface options through which they can communicate, while also having various separate commands (or flows) which require each to carefully specify their own output formatting.

The library consists of three primary building blocks, and a default implementation on top of these building blocks. It helps you setup your program architecture

The three building blocks are:

  • EventHandler: The event handler which deals with the user output, for example:

    • A handler which formats events as json-lines, and prints them to stderr
    • A handler which updates a progress bar
    • A handler which collects events for software testing
    • A handler which sends websocket messages for each event
    • A handler which updates a user interface
  • Reporter: Called during your program logic. Used to communicate user output to a user. The reporter is invoked with an Event during the programs logic, so you don't have to deal with formatting and display details in the middle of the program flow.

  • EventListener: Receives events, send by a reporter and runs the EventHandler. Usually spins upa separate thread so it won't block.

On top of these building blocks, a channel based implementation is provided which runs the EventHandler in a separate thread. To use this implementation, consult the docs for the ChannelReporter, and the ChannelEventListener.

In addition to these provided elements, you have to:

  • Define a type which can be used as Event
  • Define one or more EventHandlers (i.e. impl EventHandler<Event = YourEventType>).

Visualized introduction

Click here for a larger version. visualized introduction sketch (light svg, dark svg, light png, dark png)

Example

use std::io::{Stderr, Write};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{io, thread};
use storyteller::{
    disconnect_channel, event_channel, ChannelEventListener, ChannelReporter, EventHandler,
    EventListener, Reporter,
};

// --- In the main function, we'll instantiate a Reporter, a Listener, and an EventHandler.
//     For the reporter and listener, we'll use implementations included with the library.
//     The EventHandler must be defined by us, and can be found below.
//     We also need to define our event type, which can also be found below.

// See the test function `bar` in src/tests.rs for an example where the handler is a progress bar.
fn main() {
    let (sender, receiver) = event_channel::<ExampleEvent>();
    let (disconnect_sender, disconnect_receiver) = disconnect_channel();

    // Handlers are implemented by you. Here you find one which writes jsonlines messages to stderr.
    // This can be anything, for example a progress bar (see src/tests.rs for an example of this),
    // a fake reporter which collects events for testing or maybe even a "MultiHandler<'h>" which
    // consists of a Vec<&'h dyn EventHandler> and executes multiple handlers under the hood.
    let handler = JsonHandler::default();

    // This one is included with the library. It just needs to be hooked up with a channel.
    let reporter = ChannelReporter::new(sender, disconnect_receiver);

    // This one is also included with the library. It also needs to be hooked up with a channel.
    // It's EventListener implementation spawns a thread in which event messages will be handled.
    // Events are send to this thread using channels, therefore the name ChannelEventListener ✨.
    let listener = ChannelEventListener::new(receiver, disconnect_sender);

    // Here we use the jsonlines handler we defined above, in combination with the default `EventListener`
    // implementation on the `ChannelEventListener` we used above.
    //
    // If we don't run the handler, we'll end up in an infinite loop, because our `reporter.disconnect()`
    // below will block until it receives a Disconnect message.
    // Besides, if we don't run the handler, we would not need this library =). 
    // 
    // Also: as described above, it spawns a thread which handles updates, so it won't block.
    listener.run_handler(handler);

    // Run your program's logic
    my_programming_logic(&reporter);

    // Finish handling reported events, then disconnect the channels.
    // If not called, events which have not been handled by the event handler yet may be discarded. 
    let _ = reporter.disconnect();
}

fn my_programming_logic(reporter: &ChannelReporter<ExampleEvent>) {
	#[allow(unused_must_use)] // sending events can fail, but we'll assume they won't for this example
    {
    	// These are the events we would call during the regular flow of our program, for example
	    // if we use the library in a package manager, before, during or after downloading dependencies.
	    // The use any-event-type-you-like nature allows you to go as crazy as you would like. 
        reporter.report_event(ExampleEvent::text("[status]\t\tOne"));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::text("[status::before]\tTwo before reset"));
        reporter.report_event(ExampleEvent::event(MyEvent::Reset));
        reporter.report_event(ExampleEvent::text("[status::after]\t\tTwo after reset"));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::text("[status]\t\tThree"));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::event(MyEvent::Increment));
        reporter.report_event(ExampleEvent::text("[status]\t\tFour"));
    }
}

// --- Here we define out Event Type.

// if we would have imported third-party libraries, we could have done: #[derive(serde::Serialize)]
enum ExampleEvent {
    Event(MyEvent),
    Text(String),
}

impl ExampleEvent {
    pub fn event(event: MyEvent) -> Self {
        Self::Event(event)
    }

    pub fn text<T: AsRef<str>>(text: T) -> Self {
        Self::Text(text.as_ref().to_string())
    }
}

impl ExampleEvent {
    // Here we create some json by hand, so you can copy the example without importing other libraries, but you can also
    // replace all of this by, say `serde_json`, and derive a complete json output of your `Event` definition all at once (by design™ =)).
    pub fn to_json(&self) -> String {
        match self {
            Self::Event(event) => event.to_json(),
            Self::Text(msg) => format!("{{ \"event\" : \"message\", \"value\" : \"{}\" }}", msg),
        }
    }
}

enum MyEvent {
    Increment,
    Reset,
}

impl MyEvent {
    pub fn to_json(&self) -> String {
        match self {
            Self::Increment => format!("{{ \"event\" : \"increment\" }}"),
            Self::Reset => format!("{{ \"event\" : \"reset\" }}"),
        }
    }
}

// --- Here we define an Event Handler which deals with the user output.

struct JsonHandler {
    stream: Arc<Mutex<Stderr>>,
}

impl Default for JsonHandler {
    fn default() -> Self {
        Self {
            stream: Arc::new(Mutex::new(io::stderr())),
        }
    }
}

impl EventHandler for JsonHandler {
    type Event = ExampleEvent;

    fn handle(&self, event: Self::Event) {
        /* simulate some busy work, so we can more easily follow the user output */
        thread::sleep(Duration::from_secs(1));
        /* simulate some busy work */
        let message = event.to_json();

        let mut out = self.stream.lock().unwrap();
        let _ = writeln!(out, "{}", message);
        let _ = out.flush();
    }

    fn finish(&self) {
        let mut out = self.stream.lock().unwrap();

        let message = format!("{{ \"event\" : \"program-finished\", \"success\" : true }}");

        let _ = writeln!(out, "{}", message);
        let _ = out.flush();
    }
}

Origins

This library is a refined implementation based on an earlier experiment. It is intended to be used by, and was developed because of, cargo-msrv which has outgrown its current user output implementation.

Contributions

Contributions, feedback or other correspondence are more than welcome! Feel free to send a message or create an issue 😄 .

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Rename Reporter to EventReporter

    Rename Reporter to EventReporter

    This brings the Reporter in line with the other Event* names, such as the EventListener. It's also more specific by being explicit it's meant to report events.

    opened by foresterre 4
  • Update once_cell requirement from ~1.14.0 to ~1.15.0

    Update once_cell requirement from ~1.14.0 to ~1.15.0

    Updates the requirements on once_cell to permit the latest version.

    Changelog

    Sourced from once_cell's changelog.

    1.15.0

    • Increase minimal supported Rust version to 1.56.0.
    • Implement UnwindSafe even if the std feature is disabled.

    1.14.0

    • Add extension to unsync and sync Lazy mut API:
      • force_mut
      • get_mut

    1.13.1

    • Make implementation compliant with strict provenance.
    • Upgrade atomic-polyfill to 1.0

    1.13.0

    • Add Lazy::get, similar to OnceCell::get.

    1.12.1

    • Remove incorrect debug_assert.

    1.12.0

    • Add OnceCell::wait, a blocking variant of get.

    1.11.0

    • Add OnceCell::with_value to create initialized OnceCell in const context.
    • Improve Clone implementation for OnceCell.
    • Rewrite parking_lot version on top of parking_lot_core, for even smaller cells!

    1.10.0

    • upgrade parking_lot to 0.12.0 (note that this bumps MSRV with parking_lot feature enabled to 1.49.0).

    1.9.0

    • Added an atomic-polyfill optional dependency to compile race on platforms without atomics

    1.8.0

    • Add try_insert API -- a version of set that returns a reference.

    1.7.2

    • Improve code size when using parking_lot feature.

    ... (truncated)

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 3
  • Bump actions/checkout from 3.1.0 to 3.2.0

    Bump actions/checkout from 3.1.0 to 3.2.0

    Bumps actions/checkout from 3.1.0 to 3.2.0.

    Release notes

    Sourced from actions/checkout's releases.

    v3.2.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/checkout/compare/v3...v3.2.0

    Changelog

    Sourced from actions/checkout's changelog.

    Changelog

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 2
  • Update indicatif requirement from 0.16.2 to 0.17.1

    Update indicatif requirement from 0.16.2 to 0.17.1

    Updates the requirements on indicatif to permit the latest version.

    Release notes

    Sourced from indicatif's releases.

    0.17.1

    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.

    Fixed regressions

    • Fixed unicode-width feature spelling (#456)
    • Only tick if the ticker is disabled (#458)
    • Rework MultiProgress zombie line handling (#460)
    • Fix incorrect link in documentation (#469, thanks to @​Jedsek)
    • Take a reference for ProgressBar::style() (#476, thanks to @​andrewchambers)

    Other changes

    Thanks from @​djc and @​chris-laplante to all contributors!

    Commits
    • 791068c Bump version to 0.17.1
    • b65eb85 add new render tests that exercise zombie handling
    • d88fa2d modify render tests to account for fixed MultiProgress::println/clear behavior
    • d32eed5 rewrite zombie handling
    • bdf1890 clarify comment for MultiState::orphan_lines member
    • efc8558 No-op MultiState::draw if we are panicking
    • b9dcd47 Document last char/string in tick style being the "final" state
    • a466096 Remove write_all from wrap_write
    • 81cca1e ProgressBar style() now takes a reference
    • b5de18c Correct mis-naming of variables in wrap_async_read
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 2
  • Link to cargo-msrv example in readme

    Link to cargo-msrv example in readme

    The usage in cargo-msrv shows a real-world example, which is still readable. It also uses serde_json instead of hand formatting json (the readme example can be compiled without installing third party dependencies).

    opened by foresterre 2
  • Update indicatif requirement from 0.16.2 to 0.17.0

    Update indicatif requirement from 0.16.2 to 0.17.0

    Updates the requirements on indicatif to permit the latest version.

    Release notes

    Sourced from indicatif's releases.

    0.17.0

    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.

    Additions

    Performance

    • Use atomics to track the current position (#390 with follow up in #404, #406, #414)
    • Faster template expansion (without the regex dependency; #319)
    • Draw progress bars into draw states (#361, with follow up in #371)
    • Remove draw limiting from the progress bar state (#380)
    • Simplify ProgressDrawTarget to reduce in-memory size (#277, thanks to @​mibac138)

    MultiProgress changes

    • Run MultiProgress drawing on the main thread (#231 and #284, thanks to @​marienz and @​aj-bagwell)
    • Enable inserting progress bars at the end in MultiProgress (#326, thanks to @​omjadas)
    • Add 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)
    • Make is_hidden() work for MultiProgress (#430)
    • Allow vertical alignment in MultiProgress bars (#295, thanks to @​nlinker)

    Fixes

    • Expand tabs to spaces to fix formatting (#150)
    • Enable 256 color support in template strings (#283, thanks to @​MoSal)
    • Fix potential panic for hidden draw targets (#286, thanks to @​matthiasbeyer)
    • ProgressFolder shouldn't finish progress bars on completion (#290, thanks to @​mibac138)

    ... (truncated)

    Commits
    • 39ebd5f Add a Discord badge to the README
    • 7c96dcd Bump version to 0.17.0
    • 1d47e1d stateful progress tracking
    • 4cbdcbf Expand tabs => configurable number of spaces to fix #150 (#423)
    • 88d87d4 modify zombie handling code so it doesn't need to alloc
    • af5d925 add render tests for #426
    • 0f33289 MultiProgress: prune 'zombie' progress bars; fixes #426
    • f41eaa9 add InMemoryTerm::reset()
    • de9862b fix: first style of wide elements was ignored
    • 9cb25a7 add sanity check to ensure tests using Ticker acquire the global test lock
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 2
  • Bump actions/checkout from 2 to 3.1.0

    Bump actions/checkout from 2 to 3.1.0

    Bumps actions/checkout from 2 to 3.1.0.

    Release notes

    Sourced from actions/checkout's releases.

    v3.1.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/checkout/compare/v3.0.2...v3.1.0

    v3.0.2

    What's Changed

    Full Changelog: https://github.com/actions/checkout/compare/v3...v3.0.2

    v3.0.1

    v3.0.0

    • Updated to the node16 runtime by default
      • This requires a minimum Actions Runner version of v2.285.0 to run, which is by default available in GHES 3.4 or later.

    v2.4.2

    What's Changed

    Full Changelog: https://github.com/actions/checkout/compare/v2...v2.4.2

    v2.4.1

    • Fixed an issue where checkout failed to run in container jobs due to the new git setting safe.directory

    v2.4.0

    • Convert SSH URLs like org-<ORG_ID>@github.com: to https://github.com/ - pr

    v2.3.5

    Update dependencies

    v2.3.4

    v2.3.3

    ... (truncated)

    Changelog

    Sourced from actions/checkout's changelog.

    v3.1.0

    v3.0.2

    v3.0.1

    v3.0.0

    v2.3.1

    v2.3.0

    v2.2.0

    v2.1.1

    • Changes to support GHES (here and here)

    v2.1.0

    v2.0.0

    v2 (beta)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
  • Unpin once_cell dependency and set MSRV to 1.56

    Unpin once_cell dependency and set MSRV to 1.56

    Pinning once_cell results in problems for dependencies which use once_cell 1.15+.

    Users which are served by the MSRV of 1.38, can use storyteller 0.7.0 with once_cell 1.14.

    Users which are okay with an MSRV of 1.56 can use storyteller 0.8.0. No functional changes are made in this release.

    opened by foresterre 0
  • EventListener::run_handler now takes an Arc to the handler instead of moving it

    EventListener::run_handler now takes an Arc to the handler instead of moving it

    This is convenient when the handler stores, or refers to outside state. By taking an atomic reference, we can simply clone the reference counting ptr and keep it around to inspect the state of the handler (assuming the handler allows inspection of its contents).

    The cost compared to just moving the handler is negligible compared to the expected cost of the running lifetime of the handler.

    Unfortunately, since thread::spawn takes an F: 'static, we can't just take the handler by reference. We may be able to use scoped threads and put the scope in the EventListener::FinishProcessingHandle, but doing so would require doing acrobatics with lifetimes beyond the added value, over the little added cost of introducing the Arc.

    A bigger disadvantage of taking an Arc is that the Arc will be present in the EventListener::run_handler API.

    Why Arc over Rc? It is expected that since the handler must run in some place where it doesn't block the main loop, some form of concurrency will be exhibited. As such, we would require the atomicity of the Arc.

    opened by foresterre 0
  • Breaking: Remove Disconnect Channel in ChannelReporter implementation

    Breaking: Remove Disconnect Channel in ChannelReporter implementation

    This also makes the crossbeam-channel optional (required just for the channel reporter implementation). Without the channel_reporter features, this crate consists of just the primary traits and it's skeleton, without any ready to use implementation. The channel_reporter feature is enabled by default for ease of getting started.

    opened by foresterre 0
  • Put the channel reporter in its own feature

    Put the channel reporter in its own feature

    This also makes the crossbeam-channel optional (required just for the channel reporter implementation). Without the channel_reporter features, this crate consists of just the primary traits and it's skeleton, without any ready to use implementation. The channel_reporter feature is enabled by default for ease of getting started.

    opened by foresterre 0
  • Update indicatif requirement from 0.16.2 to 0.17.2

    Update indicatif requirement from 0.16.2 to 0.17.2

    Updates the requirements on indicatif to permit the latest version.

    Release notes

    Sourced from indicatif's releases.

    0.17.2

    A small maintenance release which makes indicatif more portable and fixes some minor regressions.

    • Use portable-atomic to fix build on some 32-bit platforms (#484, thanks to @​messense)
    • Implement multi-line progress message support (#443, thanks to @​happenslol)
    • Reset estimator of progress rate on backwards movement (#483, thanks to @​rlee287)
    • Fix percent initial value when there is no length (#491, thanks to @​devmatteini)
    • Bumped the MSRV to 1.56 (#482)

    On behalf of @​djc and @​chris-laplante, thanks to all contributors!

    Commits
    • 25afbed Bump version number to 0.17.2
    • 8e220fd Fix clippy lints
    • 5b8b905 Fix percent initial value when there is no length
    • 2c85ff8 Add an armv5te test job to CI
    • 44ec391 Use portable-atomic to fix build on some 32-bit platforms
    • 14b5ef2 Update test to ensure reset occurs after rewind
    • 997567d Reset estimator of progress rate on backwards movement
    • 517398b Bump MSRV to 1.56
    • 222df5b Add additional tests for multi-progress multiline rendering
    • be579da Improve multiline support in format_style
    • Additional commits viewable in compare view

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
Releases(v0.8.0)
  • v0.8.0(Sep 28, 2022)

  • v0.7.0(Sep 28, 2022)

    What's Changed

    • ⚠️ (Breaking change) Rename Reporter to EventReporter by @foresterre in https://github.com/foresterre/storyteller/pull/20

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.6.1...v0.7.0

    Source code(tar.gz)
    Source code(zip)
  • v0.6.1(Jun 19, 2022)

    What's Changed

    • Fix large packaged crate size by @foresterre in https://github.com/foresterre/storyteller/pull/13
    • Implement Display for ReporterEvent where T: Display by @foresterre in https://github.com/foresterre/storyteller/pull/12

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.6.0...v0.6.1

    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Jun 18, 2022)

    What's Changed

    • Add changelog by @foresterre in https://github.com/foresterre/storyteller/pull/8
    • ⚠(Breaking change) EventListener::run_handler now takes an Arc to the handler instead of moving it by @foresterre in https://github.com/foresterre/storyteller/pull/9

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.5.0...v0.6.0

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Jun 16, 2022)

    What's Changed

    • Put the channel reporter in its own feature by @foresterre in https://github.com/foresterre/storyteller/pull/6
    • ⚠ Breaking: Remove Disconnect Channel in ChannelReporter by @foresterre implementation https://github.com/foresterre/storyteller/pull/7
      • Removed all disconnect related types, such as: Disconnect, DisconnectSender, DisconnectReceiver, disconnect_channel()
      • Split process of disconnecting channel and waiting for unfinished events to be processed. The former can be done via Reporter::disconnect(), the latter via the new FinishProcessing::finish_processing(). As a result, if FinishProcessing::finish_processing() is not called after Reporter::disconnect(), events may go unprocessed.
        • Caution: if FinishProcessing::finish_processing() is called before ChannelReporter::disconnect() (in case the included ChannelReporter/ChannelListener implementation is used), the program will hang since the event handling thread will never finish.
      • A FinishProcessing implementation is now returned by EventListener::run_handler

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.4.2...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jun 9, 2022)

    What's Changed

    • Refactor: let the reporter take anything which can be converted into an Event instead of a raw event by @foresterre in https://github.com/foresterre/storyteller/pull/4

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.3.2...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Jun 9, 2022)

    What's Changed

    • Move the ChannelReporter, Reporter implementation to a submodule of reporter by @foresterre in https://github.com/foresterre/storyteller/pull/1
    • Implement Debug for ReporterError by @foresterre in https://github.com/foresterre/storyteller/pull/2

    Full Changelog: https://github.com/foresterre/storyteller/compare/v0.3.1...v0.3.2

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(May 6, 2022)

    Changelog:

    • Excluded png images in repo from crates.io published version

    NB: v0.3.0 has not been published to crates.io, because of the above change.

    Source code(tar.gz)
    Source code(zip)
A compact implementation of connect four written in rust.

connect-four A compact implementation of connect four written in rust. Run the game At the moment there no pre-built binaries - but you can build it l

Maximilian Schulke 12 Jul 31, 2022
🐎 A fast implementation of the Aho-Corasick algorithm using the compact double-array data structure. (Python wrapper for daachorse)

python-daachorse daachorse is a fast implementation of the Aho-Corasick algorithm using the compact double-array data structure. This is a Python wrap

Koichi Akabe 11 Nov 30, 2022
A more compact and intuitive ASCII table in your terminal: an alternative to "man 7 ascii" and "ascii"

asciit A more compact and intuitive ASCII table in your terminal: an alternative to man 7 ascii and ascii. Colored numbers and letters are much more e

Qichen Liu 刘启辰 5 Nov 16, 2023
A command line tool and Rust library for working with recombination maps.

RecMap library (and command line tool) for reading and working with recombination maps in Rust A RecMap object can be created from reading in a HapMap

Vince Buffalo 5 Feb 11, 2024
Cross-platform Rust library for coloring and formatting terminal output

Coloring terminal output Documentation term-painter is a cross-platform (i.e. also non-ANSI terminals) Rust library for coloring and formatting termin

Lukas Kalbertodt 75 Jul 28, 2022
A Rust program/library to write a Hello World message to the standard output.

hello-world Description hello-world is a Rust program and library that prints the line Hello, world! to the console. Why was this created? This progra

null 0 May 11, 2022
Utilites for working with `bevy_ecs` when not all types are known at compile time

bevy_ecs_dynamic Utilities for working with bevy_ecs in situations where the types you're dealing with might not be known at compile time (e.g. script

Jakob Hellermann 17 Dec 9, 2022
A calculator working with text.

Calculator A calculator working purely with text inputs. Downloading Desktop Version (Windows + Mac) available in the Releases Tab Web Version availab

null 9 Dec 16, 2022
A workflow tool for quickly running / testing something you are working on

runfast What is it? This is a program intended to be run in a project directory to set up a project run command, and remember it so we dont have to ty

anna 4 Dec 16, 2022
Code for working with edge-matching puzzles in the Eternity 2 family.

e2rs Code for working with edge-matching puzzles in the Eternity 2 family. This is a WIP sketch of some APIs and algs for representing and manipulatin

Matthew Pocock 3 Jan 18, 2023
A rust crate for working with colors and color spaces.

Color Art A rust crate for working with colors and color spaces. Documentation See Color Art. Usage Add Dependency [dependencies] color-art = "0.2" Co

cx33 5 Dec 30, 2022
Solving context limits when working with AI LLM models by implementing a "chunkable" attribute on your prompt structs.

Promptize Promptize attempts to solve the issues with context limits when working with AI systems. It allows a user to add an attribute to their struc

Dan Nelson 5 Jul 18, 2023
A working, tested example for how to use Rust with warp and JWT

rust-jwt-example Example of JWT authentication and authorization in Rust using Warp Login curl http://localhost:8000/login -d '{"email": "user@userlan

Akhil Sharma 3 Sep 18, 2023
Dead simple, memoized cargo subcommand to hoist cargo-built binaries into the current working directory, written in Rust.

cargo-hoist Dead simple cargo subcommand to hoist cargo-built binaries into scope. stable Install | User Docs | Crate Docs | Reference | Contributing

refcell.eth 6 Nov 9, 2023
A cargo plugin to shrink cargo's output

cargo single-line A simple cargo plugin that shrinks the visible cargo output to a single line (okay, in the best case scenario). In principle, the pl

Denis 5 Oct 30, 2022
Grep with human-friendly search output

hgrep: Human-friendly GREP hgrep is a grep tool to search files with given pattern and print the matched code snippets with human-friendly syntax high

Linda_pp 345 Jan 4, 2023
A syntax-highlighting pager for git, diff, and grep output

Get Started Install delta and add this to your ~/.gitconfig: [core] pager = delta [interactive] diffFilter = delta --color-only [delta]

Dan Davison 16k Dec 31, 2022
A silly program written in Rust to output nonsensical sentences in the command line interface.

A silly program written in Rust to output nonsensical sentences in the command line interface.

Rachael Ava 1 Dec 13, 2021
Watch output and trigger on diff!

watchdiff Watch output and trigger on diff! Ever want to have watch output only tell you what changed? And not only what, but when? Now you can! Enter

geno 2 Apr 6, 2022