So there is this taskbar known as Lemonbar for Linux and it takes information (such as texts) and gets piped into the taskbar.
For example like this. echo "Hello Bar" | lemonbar -p
If I wrote this in Rust I can do it like this.
fn main()
{
println!("Hello, bar!");
}
and then compiled it and run it like this ./bar | lemonbar -p -F#ffffff -B#041024 it works just fine.
But if I want to do something more complicated like this: echo "%{l}Hello%{c}yellow%{r}Bar" | lemonbar -p -F#000000 -B#FFFF00 How would I output %{l}Hello%{c}yellow%{r}Bar from rust code? Because putting characters like {} Rust does not like that. Is there a way to perhaps escape those characters or something so I can use it?
To print a literal %{l} in Rust using println!(), you need to escape the { and } by doubling them. println!("{{l}}") will print a literal "{l}". For more details, see the std::fmt documentation.
Alternatively, if you have no interpolation, you can print an entire string as a single argument to println!(), and then none of the {} need escaping. That would look like println!("{}", "%{l}Hello%{c}yellow%{r}Bar");.
I guess that wasn't exactly the right term. I meant if you don't use {} or similar things inside the format string to insert variables. For instance, if you did this:
println!("%{{l}}Hello%{{c}}{}", "world");
Then using the second technique in my post above wouldn't work, as this is using the format machinery, and the string needs to be the first argument to println!() to actually act as a format string (rather than a string which is just being printed).
One other question, echo "some characters" | lemonbar -p -F#ffffff -B#041024 With this particular command, is there a way to get Rust to fully run this entire command without pushing it through an external shell script or something?
I'm not sure how lemonbar wants the "some characters" input, if using an arg doesn't work, you can try calling spawn on the Command to make a Child, get its stdin and then write "some characters" into it.
Potentially slightly, but I doubt there will be many practical differences. I think the main benefit would come from being able to run a single rust binary, rather than having to run a shell script containing the command to run your rust binary + lemonbar.
It's worth noting that when writing to stdin, the write!() macro will provide equivalent functionality to println!() - you'd use it like write!(stdin_handle, "format string", args).unwrap();, just like println!("format string", args);.
So if I used the write!() macro, then what is the stdin_handle, would I write echo Hello Bar! inside the stdin_handle or is this a keyword where I have to litereally write stdin_handle?
I don't think you would need echo at all. echo is a command line application who's entire purpose is to write to stdout, and then the | bash primitive forwards everything from echo's stdout into lemonbar's stdin. If you're writing directly to stdin, you don't need any of that.
With that in mind, there are some special things | will do that rust's Command does not do by default. Mainly, it flushes stdin and closes lemonbar's stdin when echo exits. I've included some code here to do that in Rust.
This rust program:
use std::process::{Command, Stdio};
use std::io::prelude::*;
fn main() -> Result<(), std::io::Error> {
let mut child = Command::new("./lemonbar").stdin(Stdio::piped()).spawn()?;
let mut lemonbar_stdin = child.stdin.take().unwrap();
// write! does not include a newline, writeln! does.
writeln!(lemonbar_stdin, "Hello world")?;
// ensure everything's been written to the child.
lemonbar_stdin.flush()?;
// close stdin to tell lemonbar that no more input is coming.
drop(lemonbar_stdin);
child.wait()?;
Ok(())
}