jam1garner / owo-colors Goto Github PK
View Code? Open in Web Editor NEWA zero-allocation no_std-compatible zero-cost way to add color to your Rust terminal
License: MIT License
A zero-allocation no_std-compatible zero-cost way to add color to your Rust terminal
License: MIT License
The colored package contains functionality to enable or disable colors using environment variables. Usage is roughly:
use colored::control::SHOULD_COLORIZE;
....
SHOULD_COLORIZE.should_colorize()
The implementation is here: https://github.com/mackwic/colored/blob/master/src/control.rs#L100
Can we control the coloring for owo-colors using environment variables?
Hey I'm not able to compile my program anymore.
error[E0658]: const generics are unstable
--> C:\Users\YYY\.cargo\registry\src\github.com-1ecc6299db9ec823\owo-colors-1.4.2\src\lib.rs:306:25
|
306 | fn fg_rgb<'a, const R: u8, const G: u8, const B: u8>(
| ^
|
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
I was wondering if there was a way with your crate to optimize the ansi escape sequences. Here's an example of what I'm talking about. This is based off of your hello_worlds.rs example.
owo-colors: "\u{1b}[47m\u{1b}[30mHello\u{1b}[0m\u{1b}[0m \u{1b}[42m\u{1b}[35mWorld\u{1b}[0m\u{1b}[0m"
nu-ansi-term: "\u{1b}[47;30mHello\u{1b}[0m \u{1b}[42;35mWorld\u{1b}[0m"
Hello World
owo-colors: "\u{1b}[47m\u{1b}[30mo\u{1b}[0m\u{1b}[0m \u{1b}[42m\u{1b}[35mWo\u{1b}[0m\u{1b}[0m"
nu-ansi-term: "\u{1b}[47;30mo\u{1b}[0m \u{1b}[42;35mWo\u{1b}[0m"
o Wo
Note how there seems to be extra ansi codes. One way of optimizing this would be to parse the codes and combine them where possible. For instance,
E=ESC
here - note the E[47E[30m
instead of E[47;30m
.
Alternatively when you're doing "Hello".fg::<Black>().bg::<White>()
you could just write that out as E[47;30m
. I'm guessing this may be the easiest solution. Of course, you may have some reason why you're doing it the way you are that I'm unaware of.
This isn't a huge deal with 'hello world' but the extra ansi codes add up over time and will decrease throughput.
Hi.
I am having a hard time finding the Effect::from(&str)
or Style::from(&str)
. Are they don't exist?
On the contrary, I can use AnsiColors::from(style.as_str()))
to get color from a string.
Thanks! โค๏ธ
I tried to print different words with different colours depending on condition:
println!("operation is {}",
if op.success {
"successful".bright_green()
} else {
"failed".bright_red()
}
);
This doesn't work because color is encoded into type of returned wrapper.
I've managed to solve it using:
println!("operation is {}",
if op.success {
"successful".color(AnsiColors::BrightGreen)
} else {
"failed".color(AnsiColors::BrightRed)
}
);
But it would be cool to be able to perform such conversion more conveniently, so you don't have to rewrite code that much (function name may be arbitrary):
println!("operation is {}",
if op.success {
"successful".bright_green().downgrade() // converts statically-known color to common type which stores color as value
} else {
"failed".bright_red().downgrade()
}
);
Motivation
Currently, the best way to handle dynamic colors of multiple types (i.e. mixing between Ansi, Xterm, and Rgb) is using something along the lines of dyn DynColor
or creating an enum by hand that dispatches to the individual DynColors
methods. This is kinda a lot of effort.
Solution
Add an enum with 3 variants: Ansi
, Xterm
, and Rgb
, probably called DynColors
(open to suggestions) that implements DynColor
.
To allow something like this:
use owo_colors::{OwoColorize, XtermColors, DynColors};
fn main() {
let mut some_color = DynColors::Rgb(0, 0, 0);
println!("{}", "black".color(some_color));
some_color = DynColors::Xterm(XtermColors::Yellow);
println!("{}", "on yellow".on_color(some_color));
}
It's just a nice thing to have - instead of writing
strings
.iter()
.map(|string| string.style(some_style).to_string())
.collect::<Vec<_>>()
.join(", ")
It could instead be the following
strings
.iter()
.map(|string| string.style(some_style))
.collect::<Vec<_>>()
.join(", ")
Sure, it's a tiny thing, but it does make such code look less clean to me with the former option.
The crate tracing-subscriber might switch to using owo-colors. ( tokio-rs/tracing#2759 )
I tried implementing it, but stumbled upon a tricky case. Essentially tracing-subscriber is outputting values to a core::fmt::Write
, and it wants to call fmt_prefix
before that and fmt_suffix
after that.[1]
However, the fmt_prefix
and fmt_suffix
methods assume that one has a std::fmt::Formatter
. Which isn't the case here. The code is roughly
write!(writer, "{}", style.prefix())?;
// Directly prints to the writer. No instance of std::fmt::Formatter exists here.
self.timer.format_time(writer)
write!(writer, "{} ", style.suffix())?;
Would it be reasonable to change the fmt_prefix
/fmt_suffix
methods to accept anything that implements fmt::Write
? Or is there another, potentially better solution?
With input:
println!(
"{}",
"colored blue if a supported terminal"
.if_supports_color(Stdout, |text| text.bold().bright_blue())
);
I get the output:
--> src/lib.rs:46:43
|
10 | .if_supports_color(Stdout, |text| text.bold().bright_blue())
| -----------^^^^^^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
It looks like each formatter creates a temporary, causing issues if multiple formatters are applied.
I suspect this may need to be a macro rather than a function call...
The supports-color
crate is only available in std
environments, owo-colors
does not mention that this is the case.
Would it be possible to extend owo-colors
feature set to include std
, to make this dependency clear via different features?
[features]
std = []
supports-colors = ['std']
Ideally, it'd be great to decouple supports-colors
and std
further by still having the override present.
This would be beneficial for embedded systems. One could also use build-time environment variables to set the default (like defmt
does).
Happy to create a PR!
Currently the Style
API outputs multiple ANSI sequences for each form of styling done. These can all be collapsed into a single ANSI sequence. See comments of #22 for more information.
Would it be possible to support a more dense inline style of coloring similar to this python function
print_color("Command {c.b}{name}{c.d} {c.r}not found{c.d}")
where c.b
would be blue and c.d
would reset to default, ideally with customizable styles so you could have c.bb
for blue bold instead of having to do {}, name.blue().bold();
Making this into its own issue from #33.
I have no idea how I want to do this ๐
Presumably a similar API to #35, but I have no clue what the best way to do task-locals is. Presumably this will need to be supported per executor. I imagine this will require supporting tokio and async-std separately? I know smol by itself doesn't support task-locals, but are there other executors that would need this?
I feel it goes without saying that these will be behind feature-flags.
Hey!
I've written https://github.com/SirWindfield/ansi-colors-macro-rs as I couldn't find any colouring library that does not allocate a new String for each message they create, either through format!
or by simply calling push
on a String for each ANSI color code fragment.
My project does expand the static string into ANSI escape codes at compile-time. Speaking of efficiency and performance, is your crate the same/better/worse? println!
, write!
and the likes seem to not allocate new memory which should eliminate the allocation problem I always faced.
Interface-wise yours feels more natural but I explicitly tried to get coloured messages into const
declarations, and no crate could do that. Is it possible with yours? Due to the fact that you rely on Display
as well my guess would be no :(.
We still cant put conts fn
in impl Trait
, so we can't mark methods of OwoColorize
as const
. But const_fn_trait_bound
is already stable. Which means that we can allow creating FgColorDisplay
(and others) in const context.
For example, like this:
impl<'a, C: Color, T> FgColorDisplay<'a, C, T> {
pub const fn new(thing: &'a T) -> Self {
Self(thing, PhantomData)
}
}
#[test]
fn const_fg_color_display() {
const YELLOW_FISH: FgColorDisplay<'static, Yellow, &'static str> = FgColorDisplay::new(&"><>");
assert_eq!("\u{1b}[33m><>\u{1b}[39m", YELLOW_FISH.to_string())
}
I personally think having colorized constants is pretty useful (I created this issue because I wanted to do that, but found out, that I can't). So maybe we can add support for that in some form or another?
When i try to compile my code its gives me this 2 errors.
error[E0432]: unresolved import `owo_colors`
--> src/main.rs:1:5
|
1 | use owo_colors::OwoColorize;
| ^^^^^^^^^^ maybe a missing crate `owo_colors`?
error[E0599]: no method named `on_green` found for type `{integer}` in the current scope
--> src/main.rs:15:57
|
15 | ...7878.on_green());
| ^^^^^^^^ method not found in `{integer}`
Hi,
After I used owo_colors
with my changes a bit, I realized one feature was missing: It would be useful if there was a style option to apply no color style.
Let's say I want to give the user the ability to style some text, but the user doesn't want to use a color (i.e. use the default of the terminal). With the current implementation โ if the default theme defines a color โ the user has to choose "white" or "black". The problem is, one isn't readable on a black background, and the other isn't readable on a white background.
Basically, the following two methods are missing on Style
:
pub fn default_color(mut self) -> Self {
self.fg = None;
self
}
pub fn on_default_color(mut self) -> Self {
self.bg = None;
self
}
(As always, I'm very much open to suggestions for better names)
This also adds the ability to unset colors (so "remove/unset_fg/bg` also would be possible names).
If you like this idea, let me know if I should send a PR, or if you will add it.
I have an interesting use case:
This doesn't seem possible with owo-colors, but it seems like it would be possible with a little bit of infrastructure:
impl Style {
fn with_writer<F, T, E, W>(writer: W, f: F) -> Result<T, WithWriterError<E>>
where F: FnOnce(W) -> Result<T, E>, W: std::io::Write,
}
// this is optional but more generic than forcing F to return std::io::Write
enum WithWriterError<E> {
Internal(std::io::Error),
Callback(E),
}
impl WithWriterError<std::io::Error> {
// flattens the error in case f returns std::io::Error, which is the common case
pub fn flatten(self) -> std::io::Error {
...
}
}
This would make it possible to write:
style.with_writer(&mut writer, |writer| {
let mut no_color = strip_ansi_escapes::Writer(writer);
no_color.write_all(stdout);
}).map_err(|err| err.flatten())?;
The callback pattern can also makes it more robust to panics, assuming an RAII guard is used. (Or actually, it might be a better design to just make an RAII guard part of the public API!)
What do you think?
Moving this from #33 to its own issue.
One considered API design:
// color=always
scoped_override(true, || {
// do stuff here?
});
// color=never
scoped_override(false, || {
// do stuff here?
});
This would need to be behind a feature flag as it requires std for thread-local variables, but outside of that this isn't too bad. For the most part it should be able to reuse a lot of the code from #34, but replace the static with a thread local.
I'm packaging this as a dependency of miette
in Fedora, and our guidelines strongly prefer that source archives (in this case, crates) come with the license text(s) for the software: https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/#_license_text - in fact, in the case of the MIT license, the license itself requires including the text with all derivative works.
Please consider adding this to the GitHub repo and referencing it from Cargo.toml in future releases - as long as the license is in the repo, that will unblock packaging, thanks!
Ability to introspect the current override status.
(follow-up to #84)
Currently, one is already able to determine if colors are supported, but only through a "hack" what I'd like is a new function:
supports_color
considers the override value and (might ?) mirror the API of the underlying supports-color
crate. This is especially useful in cases where one would A) like to query the negative status, e.g. do something if colors are not supported and B) get more information, e.g. only execute X
if truecolor is supported, but still take into account the globally set override.
What do you think? I'd be happy to draft up a PR and implement the functionality, but before that would like to know if this is something that the library should support.
How to currently get the status (sadly involves additional atomics, is cumbersome and requires alloc):
let supports_color = AtomicBool::new(false);
owo_colors::set_override(true);
format!("{}", x.if_supports_color(Stream::Stdout, |x| {
supports_color.store(true, core::sync::atomic::Ordering::SeqCst);
x
}));
supports_color.load(core::sync::atomic::Ordering::SeqCst)
https://docs.rs/crate/owo-colors/1.1.1 has failed to build
This will allow two things:
let y = String::from("test");
let x = y.red().on_white();
println!("{}", x);
preliminary testing of autoref specialization in owo-colors has shown this issue is resolved.
This will also solve #22.
Hi!
Thanks for such a great library! It is really convenient to use in our no-alloc project.
Would it be possible to add a no-color
feature flag similarly to colored, that would make the library compile to a no-op and completely disappear in the resulting binary after llvm optimizations? In very constrained environments it would save a lot of Flash memory among others. With this option, the same codebase could be shared between different scales of available resources (like tens of KB Flash to MBs of Flash).
The other benefit is that users of the binary could use the simple interface without having to place if_support_colors
everywhere, and then compile-time determine whether the logs should be colorful (e.g. in debug builds) or plain-text (in release).
type DynEquivelant = ansi_colors::AnsiColors;
const DYN_EQUIVELANT: Self::DynEquivelant = ansi_colors::AnsiColors::$color;
This should be DynEquivalent
and so on.
I guess it'd be a breaking change to fix this though.
Hi.
Is there any way to clear
all the colored styles in the string?
I tried default_color - OwoColorize in owo_colors , but no luck.
use owo_colors::OwoColorize;
fn main() {
let colored_output: bool = true;
let is_formatted = format!("{} files formatted", 5)
.green()
.to_string();
let is_unchanged = format!("{} files unchanged", 10);
let is_failed = format!("{} files failed to format", 4)
.red()
.to_string();
let message = format!("{}. {}. {}", is_formatted, is_unchanged, is_failed);
println!("{}", message.default_color());
}
The color is still there
Do we have something like:
if_support_color
that accepts a boolean value and returns String
. if_supports_color(&'a self, colored_output: bool, apply: ApplyFn). The idea is similar to set_override in owo_colors - Rust, but I I need something like if_support_color
that return String
.Otherwise, I need to use if-else
everywhere to check if the user wants the color colored_output
.
use owo_colors::OwoColorize;
fn main() {
let colored_output: bool = true;
let is_formatted = if colored_output { // โ โ
format!("{} files formatted", 5).green().to_string()
} else {
format!("{} files formatted", 5)
};
let is_unchanged = format!("{} files unchanged", 10);
let is_failed = if colored_output { // โ โ
format!("{} files failed to format", 4).red().to_string()
} else {
format!("{} files failed to format", 4)
};
let message = format!("{}. {}. {}", is_formatted, is_unchanged, is_failed);
println!("{}", message.default_color());
}
Or, do you have any better approach?
Thanks for owo-colors. โค๏ธ
In response to #30 it seems that the Style
API isn't easy enough to find.
Style
docsexamples/
folderWhen using multiple nested colored strings, like this:
use owo_colors::{AnsiColors, OwoColorize};
fn main() {
println!(
"{}",
format!("TEST {} TEST", "TEST".color(AnsiColors::Red)).color(AnsiColors::Green)
);
}
the color ends up getting reset in the middle of the string.
This means that the this is going to print test strings of these colors: green, red, white. But in this example, I'd expect green, red, green.
I'm assuming this is happening because the coloring doesn't take into account the reset escape sequence in the inner string.
https://no-color.org/
A lot of popular CLIs (GitHub CLI) and libraries (colored) do have support for it. Might be worth adding it to owo-colors
as well :) I did take a look at the source code but there doesn't seem to be an easy way to "just ad a shim" implementation that returns the original string.
Advisory: GHSA-g98v-hv3f-hcfr
Dependency looks like it is already fixed in abb6352
But the fix was never released. I wonder if we can release 3.6.0
to fix this?
Thanks.
Hey there, thanks for writing owo-colors!
I'd love to use it except I'm running into one roadblock -- I wish owo-colors supported a global override for when e.g. a --color=always
option is passed in to override any environment variables.
Even better would be to support thread-local and task-local overrides, which would make it easy to use owo-colors in libraries too.
I don't mind doing the work, but I really need the information from https://github.com/jam1garner/owo-colors/blob/master/src/colors/xterm.rs in a module and don't want to just copy the file.
See last couple commits, needed before 5.X release
The owo-colors package is working fine from windows powershell or the visual studio code terminal, but not when using it from the windows command prompt (e.g. cmd.exe). In the output I get characters like โ[0mโ[36m:โ[0m1โ[36m:โ[0m0โ[36m:โ[0m
I use colorize
in a project and was seeing if owo-colors
might be a better fit. However owo-colors
does not provide a clear()
function, like colorize
does.
What is the recommended approach for clearing all formatting applied to a given string?
Something that at the moment is very annoying to do with owo-colors is coloring a string when given a Xterm color code in the form of a u8, as the only ways to convert between a u8 and a XtermColors struct are to use unsound code to transmute it (the enum isn't #[repr(u8)]
) or a 255 line long match expression. It would be great if conversion functionality was added.
Is there a way to get the start and end ANSI sequence from owo_colors for a given rgb value (or any other parsed color I guess)?
I need it and before implementing a method to generate a color, split if and take each bit separately I thought I ask here.
In my mind it would be something like this:
println!("unstyled {} some styled text here {} unstyled",
OwoColorize.rgb(70, 130, 180).start,
OwoColorize.rgb(70, 130, 180).end
);
Or something like that?
I just saw that you already added Xterm colors. Would be cool to also have CSS color name support. Here is a complete list of all colors: https://www.w3schools.com/cssref/css_colors.asp
If you would help me out on what I'd have to add where, I'd me happy to open a PR :)
If I try building documentation for a crate that depends on owo-colors on Rust 1.57, I get:
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /opt/cargo/registry/src/github.com-1ecc6299db9ec823/owo-colors-3.1.0/src/lib.rs:72:37
|
72 | #![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
| ^^^^^^^^^^^^^^^^
I think this might need to be gated to docs-rs somehow?
Hey!
I'm not sure if this is possible (at least it doesn't seem to be at comile-time). I have a struct that I want to contain details on how to format specific parts of a document:
pub struct DocumentStyle {
pub header: ... ,
pub body: ... ,
}
I'd imagine something like this:
let style = DocumentStyle::default().header(owo_colors::some_way::fg::<Red>().bg::<Yellow>());
println!("{}", style,header.apply(some_header_text));
I've taken a look at the source and it seems that the color information is stored using PhantomData
but it's coupled with the output string on which the style is applied to. There seems to be no way to "separate" them.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.