manual: Fix colorized CLI help

In clap 3.0, it's no longer possible to get `App::write_long_help` to
output colorized text (it doesn't invoke the Colorizer at all). So let's
move the generation outside of Rust.
This commit is contained in:
Zhaofeng Li 2022-01-03 10:37:03 -08:00
parent d2762757f0
commit f234e16e80
7 changed files with 49 additions and 96 deletions

31
Cargo.lock generated
View file

@ -11,16 +11,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "ansi-to-html"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ee82de0545b181a17cbdef44fce80ecaf394e001da7ea279008bf2e0944bee"
dependencies = [
"regex",
"thiserror",
]
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.2" version = "0.3.2"
@ -134,7 +124,6 @@ dependencies = [
name = "colmena" name = "colmena"
version = "0.3.0-pre" version = "0.3.0-pre"
dependencies = [ dependencies = [
"ansi-to-html",
"async-trait", "async-trait",
"atty", "atty",
"clap", "clap",
@ -835,26 +824,6 @@ version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.5.1" version = "1.5.1"

View file

@ -7,7 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
ansi-to-html = "0.1.0"
async-trait = "0.1.42" async-trait = "0.1.42"
atty = "0.2" atty = "0.2"
clap = "3.0.0" clap = "3.0.0"

View file

@ -17,7 +17,7 @@ in rustPlatform.buildRustPackage rec {
src = lib.cleanSource ./.; src = lib.cleanSource ./.;
}; };
cargoSha256 = "sha256-FVHNtgOZCC2aC2ilt1UreDidhiAuunPOO3E9ejJzwmw="; cargoSha256 = "sha256-rJnPo8xmasRNOYttDuG80QqfKyeEcl7gn85dvYgeOpw=";
nativeBuildInputs = [ installShellFiles ]; nativeBuildInputs = [ installShellFiles ];

30
manual/colorized-help.nix Normal file
View file

@ -0,0 +1,30 @@
{ runCommand, colmena, ansi2html }:
with builtins;
let
subcommands = [
null
"apply"
"apply-local"
"build"
"upload-keys"
"eval"
"exec"
"nix-info"
];
renderHelp = subcommand: let
fullCommand = if subcommand == null then "colmena" else "colmena ${subcommand}";
in ''
(
echo '## `${fullCommand}`'
echo -n '<pre><div class="hljs">'
TERM=xterm-256color CLICOLOR_FORCE=1 ${fullCommand} --help | ansi2html -p
echo '</div></pre>'
)>>$out
'';
in runCommand "colmena-colorized-help" {
nativeBuildInputs = [ colmena ansi2html ];
} (''
ansi2html -H > $out
'' + concatStringsSep "\n" (map renderHelp subcommands))

View file

@ -1,4 +1,4 @@
{ lib, stdenv, nix-gitignore, mdbook, python3, writeScript { lib, stdenv, nix-gitignore, mdbook, python3, callPackage, writeScript
, deploymentOptionsMd ? null , deploymentOptionsMd ? null
, metaOptionsMd ? null , metaOptionsMd ? null
, colmena ? null , colmena ? null
@ -13,6 +13,12 @@
let let
apiVersion = builtins.concatStringsSep "." (lib.take 2 (lib.splitString "." version)); apiVersion = builtins.concatStringsSep "." (lib.take 2 (lib.splitString "." version));
colorizedHelp = let
help = callPackage ./colorized-help.nix {
inherit colmena;
};
in if colmena != null then help else null;
redirectTemplate = lib.escapeShellArg '' redirectTemplate = lib.escapeShellArg ''
<!doctype html> <!doctype html>
<html> <html>
@ -28,7 +34,7 @@ let
''; '';
in stdenv.mkDerivation { in stdenv.mkDerivation {
inherit version deploymentOptionsMd metaOptionsMd; inherit version deploymentOptionsMd metaOptionsMd colorizedHelp;
pname = "colmena-manual" + (if unstable then "-unstable" else ""); pname = "colmena-manual" + (if unstable then "-unstable" else "");
@ -48,9 +54,8 @@ in stdenv.mkDerivation {
''; '';
buildPhase = '' buildPhase = ''
if [ -n "${toString colmena}" ]; then if [[ -n "$colorizedHelp" ]]; then
echo "Generating CLI help text" cat "$colorizedHelp" >> src/reference/cli.md
${toString colmena}/bin/colmena gen-help-markdown >> src/reference/cli.md
else else
echo "Error: No colmena executable passed to the builder" >> src/reference/cli.md echo "Error: No colmena executable passed to the builder" >> src/reference/cli.md
fi fi

View file

@ -1,4 +1,4 @@
# Command Line Arguments # Command Line Options
<!-- UNSTABLE_BEGIN --> <!-- UNSTABLE_BEGIN -->
You are currently reading **the unstable version** of the Colmena Manual, built against the tip of [the development branch](https://github.com/zhaofengli/colmena). You are currently reading **the unstable version** of the Colmena Manual, built against the tip of [the development branch](https://github.com/zhaofengli/colmena).

View file

@ -140,10 +140,6 @@ It's also possible to specify the preference using environment variables. See <h
.required(true) .required(true)
.takes_value(true))); .takes_value(true)));
app = app.subcommand(App::new("gen-help-markdown")
.about("Generate CLI usage guide as Markdown (Internal)")
.setting(AppSettings::Hidden));
// deprecated alias // deprecated alias
app = app.subcommand(command::eval::deprecated_alias()); app = app.subcommand(command::eval::deprecated_alias());
@ -160,7 +156,13 @@ It's also possible to specify the preference using environment variables. See <h
register_command!(exec, app); register_command!(exec, app);
register_command!(nix_info, app); register_command!(nix_info, app);
app // This does _not_ take the --color flag into account (haven't
// parsed yet), only the CLICOLOR environment variable.
if clicolors_control::colors_enabled() {
app.color(ColorChoice::Always)
} else {
app
}
} }
pub async fn run() { pub async fn run() {
@ -186,10 +188,6 @@ pub async fn run() {
return gen_completions(args); return gen_completions(args);
} }
if matches.subcommand_matches("gen-help-markdown").is_some() {
return gen_help_markdown();
};
// deprecated alias // deprecated alias
handle_command!("introspect", eval, matches); handle_command!("introspect", eval, matches);
@ -204,54 +202,6 @@ fn gen_completions(args: &ArgMatches) {
clap_complete::generate(shell, &mut app, "colmena", &mut std::io::stdout()); clap_complete::generate(shell, &mut app, "colmena", &mut std::io::stdout());
} }
fn gen_help_markdown() {
// This is tailered only for the manual, with output injected to `reference/cli.md`.
// <pre><div class="hljs">
let mut commands = vec![
build_cli(false),
command::apply::subcommand(),
command::apply_local::subcommand(),
command::build::subcommand(),
command::upload_keys::subcommand(),
command::eval::subcommand(),
command::exec::subcommand(),
command::nix_info::subcommand(),
];
for command in commands.drain(..) {
let full_command = match command.get_name() {
"Colmena" => "colmena".to_string(),
sub => format!("colmena {}", sub),
};
let mut command = {
let c = command
.color(ColorChoice::Always);
if full_command != "colmena" {
c.bin_name(&full_command)
} else {
c
}
};
println!("## `{}`", full_command);
print!("<pre><div class=\"hljs\">");
let help_message = {
let mut bytes = Vec::new();
command.write_long_help(&mut bytes).unwrap();
String::from_utf8(bytes).unwrap()
};
let help_html = ansi_to_html::convert(&help_message, true, true)
.expect("Could not convert terminal output to HTML");
print!("{}", help_html);
println!("</div></pre>");
}
}
fn set_color_pref(cli: &str) { fn set_color_pref(cli: &str) {
if cli != "auto" { if cli != "auto" {
clicolors_control::set_colors_enabled(cli == "always"); clicolors_control::set_colors_enabled(cli == "always");