LukasKalbertodt / bunt

Simple macros to write colored and formatted text to a terminal. Based on `termcolor`, thus also cross-platform.
Apache License 2.0
219 stars 7 forks source link

bunt::format_args & bunt::format #18

Open d4h0 opened 3 years ago

d4h0 commented 3 years ago

Hi,

Something that sometimes would be useful, is bunt::format_args (and maybe bunt::format).

This would come in handy, for example, to format logging messages with bunt. In this case, a user can't currently use bunts macros without allocating. Another use-case would be to store formatted strings (probably only via bunt::format with an allocation).

The best option I could come up with is to write! to a termcolor::Buffer, but this does allocate.

(By the way, does bunt allocate internally?)

My current use case is, that I have a log macro that accepts a bunt format string and arguments (which prints regular status messages for the user). I also have an option to activate debugging output, which activates tracing.

So basically, there are two different log output formats (my own and tracing).

It would be better if – if debug is activated – my log macro redirects messages to tracing. But, as mentioned above, this is only possible via termcolor::Buffer to which I write bunts output.

How hard would it be to add a variant of std::format_args to bunt?

d4h0 commented 3 years ago

Also, ergonomics are not really great, with the workaround mentioned above:

            let mut buf = bunt::termcolor::Buffer::ansi();
            let err = |e: &dyn Debug|
                error!("Error while converting `bunt` format string {:?}: {:?}", $fmt_str, e);
            if let Err(e) = bunt::write!(buf, $fmt_str, $($arg),*) {
                err(&e)
            } else {
                match std::str::from_utf6(buf.as_slice()) {
                    Err(e) => err(&e),
                    Ok(msg) => info!(msg),
                };
            }

😉

(Fortunately, this code only has to exist once)

LukasKalbertodt commented 3 years ago

Hi there.

Regarding format!, checkout #2. In summary: we can't really add this to bunt unless we change how the Buffer works in termcolor.

Regarding format_args: to be honest, I am still not 100% sure what this does or how it works. But as far as I understand it, it is quite complicated. It should be possible to implement bunt::format_args though. Again, as far as I currently understand. But that wouldn't be trivial. I don't think I will have time for this anytime soon, but I'll keep the issue open if I (or someone else) ever wants to give it a try.

(By the way, does bunt allocate internally?)

The proc macro code certainly does, but this happens at compile time. The emitted code does not allocate itself, only the called termcolor functions potentially do..

write! to a termcolor::Buffer, but this does allocate.

Are you sure about this? Writing into a standard stream shouldn't allocate, no?

d4h0 commented 3 years ago

Are you sure about this? Writing into a standard stream shouldn't allocate, no?

Yes, I'm pretty sure (if I'm not missing anything). Buffer has the following method:

pub fn into_inner(self) -> Vec<u8>

Consume this buffer and return the underlying raw data.

On Windows, this unrecoverably drops all color information associated with the buffer.

And the inner data for ANSI content is InnerBuffer:Ansi(Ansi<Vec<u8>>).

as far as I understand it, it is quite complicated. It should be possible to implement bunt::format_args though. Again, as far as I currently understand. But that wouldn't be trivial.

I didn't study the code of bunt, but I was thinking bunt could just pass the data to std::format_ags! and return the result.

I don't think I will have time for this anytime soon, but I'll keep the issue open if I (or someone else) ever wants to give it a try.

Alright, still thanks for the response!

Unfortunately, I'm also busy with many different projects already...

Btw., are you aware of owo_colors?

owo_colors works with no_std (so doesn't allocate), has a nice API, and probably could be easily used instead of termcolor. I haven't looked at termcolor, but I wouldn't be astonished if the usage of owo_colors would simplify the implementation of bunt significantly.

The next release will even have functionality that makes it easy to create style themes, which I believe is important (a default theme that's optimized for dark backgrounds is often not very readable on white backgrounds).

LukasKalbertodt commented 3 years ago

Ah surel, if you need to write to Buffer, that surely allocates, yes.

I was thinking bunt could just pass the data to std::format_ags! and return the result.

We could, but then all the color information is lost. The code bunt emits usually contains more than one std::write! call.

Btw., are you aware of owo_colors?

I didn't know that lib. termcolor has a more low level API which usually is better suited as a base for a library that is "just a convenience layer", like bunt.