diff --git a/src/main/java/com/darkcollective/relix/cli/Main.java b/src/main/java/com/darkcollective/relix/cli/Main.java index e77a137..70f912b 100644 --- a/src/main/java/com/darkcollective/relix/cli/Main.java +++ b/src/main/java/com/darkcollective/relix/cli/Main.java @@ -79,6 +79,7 @@ public static int run(Host host, Interruption interruption, String... args) { .setOut(out) .setErr(err) .setPosixClusteredShortOptionsAllowed(true) + .setColorScheme(CommandLine.Help.defaultColorScheme(helpColors(host))) .setParameterExceptionHandler((e, ignored) -> { err.print("relix: " + e.getMessage() + "\n"); err.print("Try 'relix --help' for more information.\n"); @@ -106,6 +107,21 @@ public static int run(Host host, Interruption interruption, String... args) { return status; } + /** + * Whether usage help is coloured: on the terms {@code --color=auto} colours rows, when + * standard output is a terminal and {@code $NO_COLOR} is not set. picocli's own + * detection reads the real process rather than the host, and takes an MSYS or Cygwin + * {@code TERM} for a terminal, so in Git Bash on Windows it coloured help written to a + * pipe. + * + * @param host the process + * @return {@code ON} or {@code OFF}, never {@code AUTO} + */ + static CommandLine.Help.Ansi helpColors(Host host) { + return host.stdoutIsTerminal() && host.variable("NO_COLOR").isEmpty() + ? CommandLine.Help.Ansi.ON : CommandLine.Help.Ansi.OFF; + } + /** * The command line with a bare {@code --trace} given an empty value, so that the word * after it is never taken for its file: {@code relix --trace q.relix} traces diff --git a/src/test/java/com/darkcollective/relix/cli/command/ManagementCommandsTest.java b/src/test/java/com/darkcollective/relix/cli/command/ManagementCommandsTest.java index 27d996e..bf546ee 100644 --- a/src/test/java/com/darkcollective/relix/cli/command/ManagementCommandsTest.java +++ b/src/test/java/com/darkcollective/relix/cli/command/ManagementCommandsTest.java @@ -75,16 +75,24 @@ class Help { @Test @DisplayName("prints a command's usage to stdout") void command() { - var result = cli().run("help", "fmt"); + var result = cli().piped().run("help", "fmt"); assertThat(result.status()).isZero(); assertThat(result.out()).startsWith("Usage: relix fmt").contains("--keywords"); } + @Test + @DisplayName("colours usage on a terminal, and not in a pipe or with $NO_COLOR, wherever it runs") + void colours() { + assertThat(cli().run("help", "fmt").out()).startsWith("Usage: \u001B["); + assertThat(cli().piped().run("help", "fmt").out()).doesNotContain("\u001B"); + assertThat(cli().env("NO_COLOR", "1").run("help", "fmt").out()).doesNotContain("\u001B"); + } + @Test @DisplayName("prints the main usage, listing every command, with no COMMAND") void main() { - var result = cli().run("help"); + var result = cli().piped().run("help"); assertThat(result.status()).isZero(); assertThat(result.out()).startsWith("Usage: relix"); diff --git a/src/test/java/com/darkcollective/relix/cli/command/ScriptSourcesTest.java b/src/test/java/com/darkcollective/relix/cli/command/ScriptSourcesTest.java index 7662335..a46ca6e 100644 --- a/src/test/java/com/darkcollective/relix/cli/command/ScriptSourcesTest.java +++ b/src/test/java/com/darkcollective/relix/cli/command/ScriptSourcesTest.java @@ -110,7 +110,7 @@ void stdinWhenPiped() { @Test @DisplayName("with nothing named and a terminal on stdin, usage goes to stderr and the exit is 2") void nothingToRun() { - var result = Cli.in(dir).run(); + var result = Cli.in(dir).piped().run(); assertThat(result.status()).isEqualTo(2); assertThat(result.out()).isEmpty();