Hi,
first, i'd want to apology, being french, my english is very bad. Sorry.
So...
I"m writing a rust program that use cmd.exe (i'm on Windows 10) as output.
This (huge) program displays a very lot of strings and their visibility is bad.
To avoid this, I'd like to change the font color, or the background color, but only for some lines, not the whole display as the "color" command can do.
I've found a batch script that seems doing so here : https://openclassrooms.com/forum/sujet/batch-plusieurs-couleurs-a-la-fois-dans-la-console-45855
but I failed to integrate it in my rust code.
Is it possible ? How ?
I show what the partial code would have been if the "color' command would do it :
if dom {
Command::new("cmd.exe").arg("/c").arg("color").arg("0A").status().unwrap();
eprintln!("\n{}", meet[j][i - 1usize]);
Command::new("cmd.exe").arg("/c").arg("color").arg("03").status().unwrap();
eprintln!("{}", meet[j][i]);
}
A very lot of thanks and bravo for those who read and understood me, and double of them if you can help me as well.
I'm gratefull with this very fast answer. However, I prefer to stay only with the Rust Standard Library, and more without any unsafe block or function, nor even nightly-only experimental API function.
Fortunately, I finally found, thanks to you because I knew about termcolor from Python, so Python is where you made me looking for, and :
Simply with hexadecimal escape sequencies. Python's ones was octals, which can not be applied to Rust because of \0 being a valid (empty) char in Rust, \033 means 33, literally, and need a conversion to \x1b .
So the 4 partials code lines i've shown become :
if dom {
eprintln!("\x1b[32m\n{}\x1b[36m", meet[j][i - 1usize]);
eprintln!("{}", meet[j][i]);
}
Well, actually not that easy...
If I open the Windows command prompt (I don't use PowerShell) and type the usual cargo run --release, the compilation is okay and the program runs just fine in there with the right colors at the right place.
But if I run the MyApp.exe that produces, it goes south. \x1b is displayed as ← (an arrow) and [32m or [36m remain as it is. And no color switch at all, obviously.
Could you tell me why that, please? And maybe a way to fix this?
I can't test this right now, but my guess would be that the command prompt is set up to interpret those character sequences, and whatever is running the .exe is not.
A quick search on the internet makes me think this is your answer:
You can use GetConsoleMode and SetConsoleMode functions to configure this behavior. A sample of the suggested way to enable virtual terminal behaviors is included at the end of this document.
Now, as to how you you do this with just the Rust Standard Library, I'm not sure.
Yep, you were right, and first, I was really embarrassed, almost ready to accept I won't do what I would want.
Fortunately, I can't stop thinking. And wondering why it was okay onto compiling cmd session, but no more at the next ones, i finally thought :
Maybe, it is because during compilation, cargo use itself some colors (green, blue...) to show the processes done, and do the job (setting the terminal) for me, but that is reset when I leave.
So I went (again) see what some Python forums say about that, and found : https://stackoverflow.com/questions/63526130/why-do-ansi-escape-codes-sometimes-work-in-cmd
The exact solution (from the very same issue and the very same thoughts about why ) to my problem is in it, with only the Rust Standard Library !
That's because what you are using are ANSI escape codes which are supported on platforms with Unix heritage but not on Windows. On Windows colors are achieved in an entirely different way.
That's why Rust standard library doesn't provide such facility (and there are no plans to provide it): it's easy to implement as third-party code, but this requires lots of platform-specific knowledge thus it's better to have it outside of std.
Rust is modern language made in modern times, you are no longer limited by what you may receive in mail after month of waiting, you can easily add third-party crate to your project — and that's what you are supposed to do.
If you don't want to do that then you have to live with the fact that you would see colors in the ANSI-enabled console (Windows Terminal should work, I think), but not in normal Windows console.
Humf... You're right about ANSI escape codes being what I use, since it is precisely the point of this page.
For the rest, I'm sorry, but you're mostly wrong.
The Windows command prompt (cmd.exe) actually supports these (since its code page is 850 since its creation), AND rust provides such facility (via the target dependency winapi-util).
About the end of your message... Yes. You're right. But I disagree anyway : The only cases I use Rust is when I need memory security as important concern and no need for a rich GUI. And only Rust Standard Library, with restrictions, can do that.
But it is NOT a recommandation I do, it is only my Rust use. And maybe not for ever, I can imagine a day when I would be reasonable, and will do what you said (all things that I do when I use any other langage, by the way, icluding interop, native access, and others).
If you're interested, the solution (4 lines -and their call into main.rs, plus 1 in cargo.toml) is in the answer I made to KSwanson.
Which, of course, pulls a third-party crate. And your were trying to assert that
It sounds a bit strange to me to reject one solution which pulls third-party library and then turn around and accept another solution which pulls third-party library. Especially if you recall that both of them are from the exact same person:
Because winapi-util is not a third-party library, you don't have to download anything, and trust how some lamba guy wrote it. Your OS in not a third-party. Pff. Sorry.
The winapi crate is third party. The underlying APIs it binds to may be part of your OS, but the glue code is not. You're also using the winapi-util crate, which is also third party.
winapi is most definitely a third-party library, it's not even Microsoft-provided library (that would be windows) crate. And winapi-utils is wrapped around that unofficial crate made by the other guy.
I only use winapi-util. And the winapi crate comes with Rust. I repeat, you don't have to download anything to have it but Rust. It is written by Rust and cargo developpers (or trusted and embed by them), not a guy who could be me (and it would be horrible).
Yes. If you write that code then cargo would automatically download and use it. Or wouldn't download it and use it (if you had it already downloaded for some other project).
And I'm not rejecting termcolor (I use it with Python, I already said that), I only prefer a solution that don't need to download a thing, if I use Rust.
Only the solution which you have found makes you download two third-party crates, anyway.
But you are still using cargo which downloads stuff by default! You need to opt-out if you don't need it. Either redirect cargo to your own server (where only you crates would reside) or use some other build-system.
Presumably you put it in your Cargo.toml (or some tool did, such as cargo add). But you haven't shared enough details to reproduce your setup/environment, so I can't really answer your question with any kind of certainty.
Unless you have a specific and compelling reason to not use third party crates or are specifically looking to understand how things work, if you're just trying to get colors working, then I'd like to suggest that you're vastly over-complicating the situation. Here is all you need to do. Create a main.rs file with this code:
$ cat main.rs
use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
fn main() -> anyhow::Result<()> {
let mut stdout = StandardStream::stdout(ColorChoice::Always);
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
writeln!(&mut stdout, "green text!")?;
Ok(())
}
Setup a Cargo project:
$ cargo init --bin
Created binary (application) package
Add termcolor (and anyhow for convenience) as dependencies:
$ cargo add anyhow termcolor
Updating crates.io index
r Adding anyhow v1.0.66 to dependencies.
Features:
+ std
- backtrace
Adding termcolor v1.1.3 to dependencies.
And now compile and run the program:
$ cargo run
Compiling anyhow v1.0.66
Compiling termcolor v1.1.3
Compiling coloring v0.1.0 (/tmp/coloring)
Finished dev [unoptimized + debuginfo] target(s) in 0.56s
Running `target/debug/coloring`
green text!
And "green text!" will be colored green, on both Unix and Windows terminals (legacy or otherwise):