6

I would like to capture output from another process (for example git status), process it, and print with all styles (bold, italics, underscore) and colors. It's very important for me to further process that String, I don't want only to print it.

In the Unix world, I think this would involve escape codes, I'm not sure about Windows world but it's important for me too.

I know how to do it without colors:

fn exec_git() -> String {
    let output = Command::new("git")
        .arg("status")
        .output()
        .expect("failed to execute process");

    String::from_utf8_lossy(&output.stdout).into_owned()
}

Maybe I should use spawn instead?

Wojciech Polak
  • 101
  • 2
  • 7
  • Are you looking for a way to fool `git` into thinking it is outputting to a terminal (and thus colorize its output) or are you content with simply passing a flag/configuration to git that will force it to use colors without relying on terminal detection? – Matthieu M. Dec 30 '16 at 10:40
  • Fooling `git` seems to be nice idea. Right now `git` checks if stream is TTY right? (something like `if (uv_guess_handle(1) == UV_TTY) ` in libuv) Ok - let's assume I'll fool it (don't know how yet, but I'll solve that sooner or later). Then my output will contain escape codes and printing them will color final output? – Wojciech Polak Dec 30 '16 at 10:49
  • If you manage to fool git, yes your output should be colorized (if it's colorized on a terminal), however that's probably the most difficult option and I am not quite sure *how* you can do so. – Matthieu M. Dec 30 '16 at 11:15
  • 1
    AFAIK, this simply cannot be done on Windows in the console. – BurntSushi5 Dec 30 '16 at 14:07
  • @WojciechPolak I suggest you ask this question with different tags, maybe windows-console, console, terminal. Then when you get a generic solution you could post another question on how to translate it to Rust. The gist of the question isn't specific to Rust and I'd wager there's a lot of experts on stackoverflow that only monitor specific tags. – ArtemGr Dec 30 '16 at 15:03

2 Answers2

2

You can force git to output colors by using git -c color.status=always status

use std::process::Command;

fn main() {
    let output = Command::new("git")
        .arg("-c")
        .arg("color.status=always")
        .arg("status")
        .output()
        .expect("failed to execute process");

    let output = String::from_utf8_lossy(&output.stdout).into_owned();

    println!("{}", output);
}

This works for git status only. For a more general solution, you either have to check the programs documentation and hope there is a way to force colored output or check how the program determines if it should output colors or not (such as checking for the COLORTERM environment variable).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
belst
  • 2,285
  • 2
  • 20
  • 22
2

Your code already works:

use std::process::Command;

fn main() {
    let output = Command::new("ls")
        .args(&["-l", "--color"])
        .env("LS_COLORS", "rs=0:di=38;5;27:mh=44;38;5;15")
        .output()
        .expect("Failed to execute");

    let sout = String::from_utf8(output.stdout).expect("Not UTF-8");
    let serr = String::from_utf8(output.stderr).expect("Not UTF-8");

    println!("{}", sout);
    println!("{}", serr);
}

Prints the output:

total 68
-rw-r--r-- 4 root root 56158 Dec 23 00:00 [0m[44;38;5;15mCargo.lock[0m
-rw-rw-r-- 4 root root  2093 Dec  9 02:54 [44;38;5;15mCargo.toml[0m
drwxr-xr-x 1 root root  4096 Dec 30 15:24 [38;5;27msrc[0m
drwxr-xr-x 1 root root  4096 Dec 23 00:19 [38;5;27mtarget[0m

Note that there's a bunch of junk scattered inside the output ([44;, [0m, etc.). Those are ANSI escape codes, and the terminal emulator interprets those to change the color of the following text.

If you print the string with debugging, you will see:

\u{1b}[0m\u{1b}[44;38;5;15mCargo.lock\u{1b}[0m

Each escape code starts with an ESC (\u{1b}) followed by the actual command. You will have to parse those in order to ignore them for whatever processing you are doing.

Windows does not use escape codes (although maybe it can in Windows 10?), and instead a program directly modifies the console it is connected to. There is nothing in the output to indicate the color.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366