Как в Rust зафиксировать выходные данные процесса с помощью цветов?

Я хотел бы захватить вывод из другого процесса (например, git status), обработать его и распечатать со всеми стилями (жирный, курсив, подчеркивание) и цветами. Для меня очень важно продолжить обработку этого String, я не хочу только печатать его.

В мире Unix, я думаю, это будет связано с escape-кодами, я не уверен в мире Windows, но для меня это тоже важно.

Я знаю, как это сделать без цветов:

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()
}

Может быть, мне следует использовать spawn вместо этого?


person Wojciech Polak    schedule 30.12.2016    source источник
comment
Вы ищете способ обмануть git, заставив его думать, что он выводит на терминал (и, таким образом, раскрасить его вывод), или вы довольствуетесь простой передачей флага/конфигурации в git, который заставит его использовать цвета, не полагаясь на обнаружение терминала?   -  person Matthieu M.    schedule 30.12.2016
comment
Обмануть git кажется хорошей идеей. Прямо сейчас git проверяет, является ли поток TTY, верно? (что-то вроде if (uv_guess_handle(1) == UV_TTY) в libuv) Хорошо - допустим, я его обману (пока не знаю, как, но рано или поздно это решу). Тогда мой вывод будет содержать escape-коды, и их печать будет окрашивать окончательный вывод?   -  person Wojciech Polak    schedule 30.12.2016
comment
Если вам удастся обмануть git, да, ваш вывод должен быть раскрашен (если он раскрашен на терминале), однако это, вероятно, самый сложный вариант, и я не совсем уверен, как вы можете это сделать.   -  person Matthieu M.    schedule 30.12.2016
comment
Насколько я знаю, это просто невозможно сделать в Windows в консоли.   -  person BurntSushi5    schedule 30.12.2016
comment
@WojciechPolak Я предлагаю вам задать этот вопрос с разными тегами, может быть, windows-консоль, консоль, терминал. Затем, когда вы получите общее решение, вы можете опубликовать еще один вопрос о том, как перевести его на Rust. Суть вопроса не специфична для Rust, и я готов поспорить, что есть много экспертов по stackoverflow, которые отслеживают только определенные теги.   -  person ArtemGr    schedule 30.12.2016


Ответы (2)


Ваш код уже работает:

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);
}

Распечатывает вывод:

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

Обратите внимание, что внутри вывода разбросана куча мусора ([44;, [0m и т. д.). Это экран-коды ANSI, и эмулятор терминала интерпретирует их для изменения цвета следующего текста. .

Если вы напечатаете строку с отладкой, вы увидите:

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

Каждый escape-код начинается с ESC (\u{1b}), за которым следует фактическая команда. Вам придется проанализировать их, чтобы игнорировать их для любой обработки, которую вы делаете.

Windows не использует escape-коды (хотя может и в Windows 10?), а вместо этого программа напрямую модифицирует консоль, к которой она подключена к. В выводе нет ничего, что указывало бы на цвет.

person Shepmaster    schedule 30.12.2016

Вы можете заставить git выводить цвета, используя 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);
}

Это работает только для git status. Для более общего решения вам нужно либо проверить документацию программы и надеяться, что есть способ заставить цветной вывод, либо проверить, как программа определяет, должна ли она выводить цвета или нет (например, проверка переменной среды COLORTERM).

person belst    schedule 30.12.2016