picocli: 4.5.1
When exception is in Callable then from cli I should expect massage to be color red, but is not(powershell, gitbash)
My code:
static IExecutionExceptionHandler errorHandler = (Exception ex, CommandLine cmdL, ParseResult pr) -> {
cmdL.getErr().println(cmdL.getColorScheme().errorText(ex.getMessage()));
return cmdL.getCommandSpec().exitCodeOnExecutionException();
};
public static void main( String[] args ) {
ColorScheme colorScheme = createColorScheme();
CommandLine commands = new CommandLine(new TopLavelCommands()).setColorScheme(colorScheme).setExecutionExceptionHandler(errorHandler);
System.exit(commands ).execute(args);
}
private static ColorScheme createColorScheme() {
return new ColorScheme.Builder()
.commands(CommandLine.Help.Ansi.Style.bold, CommandLine.Help.Ansi.Style.underline) // combine multiple styles
.options(CommandLine.Help.Ansi.Style.fg_yellow) // yellow foreground color
.parameters(CommandLine.Help.Ansi.Style.fg_yellow)
.optionParams(CommandLine.Help.Ansi.Style.italic)
.errors(CommandLine.Help.Ansi.Style.fg_red, CommandLine.Help.Ansi.Style.bold)
.stackTraces(CommandLine.Help.Ansi.Style.italic)
.build();
}
@sysmat Are colors showing correctly when you execute <yourcmd> --help in those shells?
To help troubleshoot this issue, can you run again with system property -Dpicocli.trace=DEBUG on both shells, and copy-paste the output here?
The powershell problem may be related to this issue.
(I have not heard any reports of problems with ANSI colors in gitbash until now.)
[picocli DEBUG] Creating CommandSpec for si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Creating CommandSpec for class picocli.CommandLine$HelpCommand with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'help' to '<main class>'
[picocli DEBUG] Creating CommandSpec for class si.arnes.kdo.cli.SearchCmd with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'search' to '<main class>'
[picocli INFO] Picocli version: 4.5.1, JVM: 1.8.0_201 (Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.201-b09), OS: Windows 10 10.0 amd64
[picocli INFO] Parsing 1 command line args [help]
[picocli DEBUG] Parser configuration: optionsCaseInsensitive=false, subcommandsCaseInsensitive=false, abbreviatedOptionsAllowed=false, abbreviatedSubcommandsAllowed=false, aritySatisfiedByAttachedOptionParam=false, atFileCommentChar=#, caseInsensitiveEnumValuesAllowed=false, collectErrors=false, endOfOptionsDelimiter=--, expandAtFiles=true, limitSplit=false, overwrittenOptionsAllowed=false, posixClusteredShortOptionsAllowed=true, separator=null, splitQuotedStrings=false, stopAtPositional=false, stopAtUnmatched=false, toggleBooleanFlags=false, trimQuotes=false, unmatchedArgumentsAllowed=false, unmatchedOptionsAllowedAsOptionParameters=true, unmatchedOptionsArePositionalParams=false, useSimplifiedAtFiles=false
[picocli DEBUG] (ANSI is disabled by default: systemproperty[picocli.ansi]=null, isatty=true, TERM=cygwin, OSTYPE=null, isWindows=true, JansiConsoleInstalled=false, ANSICON=null, ConEmuANSI=null, NO_COLOR=null, CLICOLOR=null, CLICOLOR_FORCE=null)
[picocli DEBUG] Initializing command 'null' (user object: si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6): 0 options, 0 positional parameters, 0 required, 0 groups, 2 subcommands.
[picocli DEBUG] [0] Processing argument 'help'. Remainder=[]
[picocli DEBUG] Found subcommand 'help' (command 'help' (user object: class picocli.CommandLine$HelpCommand))
[picocli DEBUG] Checking required args for parent command 'null' (user object: si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6)...
[picocli DEBUG] Initializing command 'help' (user object: class picocli.CommandLine$HelpCommand): 1 options, 1 positional parameters, 0 required, 0 groups, 0 subcommands.
[picocli DEBUG] Getting a picocli.CommandLine$HelpCommand instance from factory picocli.CommandLine$DefaultFactory@33e5ccce
[picocli DEBUG] Factory returned a picocli.CommandLine$HelpCommand instance (5a42bbf4)
[picocli DEBUG] Set initial value for field boolean picocli.CommandLine$HelpCommand.helpRequested of type boolean to false.
[picocli DEBUG] Set initial value for field String[] picocli.CommandLine$HelpCommand.commands of type class [Ljava.lang.String; to [Ljava.lang.String;@270421f5.
[picocli DEBUG] Applying default values for command '<main class> help'
[picocli DEBUG] defaultValue not defined for field boolean picocli.CommandLine$HelpCommand.helpRequested
[picocli DEBUG] defaultValue not defined for field String[] picocli.CommandLine$HelpCommand.commands
[picocli DEBUG] Applying default values for command '<main class>'
commands for kdo cli
Usage>> command switches
help>> help
help for search command>> help search
Commands:
help Displays help information about the specified command
search search users by username or mail and retrive users data
Thank you!
I see what the cause is: the TERM environment variable has value Cygwin and this is not recognized by picocli.
I will fix this soon.
Can you provide details on the terminal software name and version?
I'm using Windows Terminal Version: 1.3.2651.0 with the different host terminal
Name : ConsoleHost
Version : 5.1.19041.1
InstanceId : 77c51b75-1189-4579-b72d-8499cbaa160a
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : sl-SI
CurrentUICulture : en-US
PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
cygcheck (msys) 2.6.0
System Checker for Msys
By the way, can you also provide -Dpicocli.trace=DEBUG output for PowerShell? The cause may be different.
❯ java '-Dpicocli.trace=DEBUG' -jar kdo.jar
[picocli DEBUG] Creating CommandSpec for si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Creating CommandSpec for class picocli.CommandLine$HelpCommand with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'help' to '<main class>'
[picocli DEBUG] Creating CommandSpec for class si.arnes.kdo.cli.SearchCmd with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'search' to '<main class>'
[picocli INFO] Picocli version: 4.5.1, JVM: 1.8.0_201 (Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.201-b09), OS: Windows 10 10.0 amd64
[picocli INFO] Parsing 0 command line args []
[picocli DEBUG] Parser configuration: optionsCaseInsensitive=false, subcommandsCaseInsensitive=false, abbreviatedOptionsAllowed=false, abbreviatedSubcommandsAllowed=false, aritySatisfiedByAttachedOptionParam=false, atFileCommentChar=#, caseInsensitiveEnumValuesAllowed=false, collectErrors=false, endOfOptionsDelimiter=--, expandAtFiles=true, limitSplit=false, overwrittenOptionsAllowed=false, posixClusteredShortOptionsAllowed=true, separator=null, splitQuotedStrings=false, stopAtPositional=false, stopAtUnmatched=false, toggleBooleanFlags=false, trimQuotes=false, unmatchedArgumentsAllowed=false, unmatchedOptionsAllowedAsOptionParameters=true, unmatchedOptionsArePositionalParams=false, useSimplifiedAtFiles=false
[picocli DEBUG] (ANSI is disabled by default: systemproperty[picocli.ansi]=null, isatty=true, TERM=null, OSTYPE=null, isWindows=true, JansiConsoleInstalled=false, ANSICON=null, ConEmuANSI=null, NO_COLOR=null, CLICOLOR=null, CLICOLOR_FORCE=null)
[picocli DEBUG] Initializing command 'null' (user object: si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6): 0 options, 0 positional parameters, 0 required, 0 groups, 2 subcommands.
[picocli DEBUG] Applying default values for command '<main class>'
Missing required subcommand
commands for kdo cli
Thank you!
Looks like on PowerShell, picocli cannot detect that ANSI escape codes are supported.
So you would need to either use Jansi:
import org.fusesource.jansi.AnsiConsole;
...
public static void main(String[] args) {
AnsiConsole.systemInstall(); // enable colors on Windows
new CommandLine(new TopLavelCommands()).execute(args);
AnsiConsole.systemUninstall(); // cleanup when done
}
...or ask your users to set one of the environment variables that picocli uses to determine if ANSI escape codes are supported.
I recommend Jansi, or picocli-jansi-graalvm.
picocli-jansi-graalvm allows you to only use Jansi on Windows-only, and fixes some Jansi bugs for GraalVM native images.
It is used like this:
import picocli.jansi.graalvm.AnsiConsole; // not org.fusesource.jansi.AnsiConsole
...
try (AnsiConsole ansi = AnsiConsole.windowsInstall()) { // enable colors on Windows
new CommandLine(new MyApp()).execute(args);
} // Closeable does cleanup when done
@sysmat I finally got around to putting in a fix for MSYS2 (auto-enable ANSI when env var TERM contains cygwin).
Can you confirm that this solves the issue in the MSYS2-based Windows Terminal shell?
To verify, check out picocli master locally, and build it with publishToMavenLocal. That should publish picocli-4.5.2-SNAPSHOT to your local .m2 Maven cache.
git clone https://github.com/remkop/picocli.git
cd picocli
gradlew publishToMavenLocal
You can then try this in a project that uses the info.picocli:picocli:4.5.2-SNAPSHOT dependency. Feedback very welcome!
@sysmat Can you think of a way to detect from the Java process whether it was launched from PowerShell or from some other shell like CMD? That would help further improve picocli's ANSI heuristics.
If we cannot improve the heuristics, then the best thing that picocli-based applications can do is to always use Jansi (at least when running on Windows).
Thoughts?
I have started the release for picocli 4.5.2, which contains the fix for MSYS2.
So, from 4.5.2, gitbash should automatically show colors.
I don't have a solution for Powershell... This may be a Powershell issue (looking at #849).
@sysmat Can you confirm that colors work correclty in MSYS2 (gitbash) with picocli 4.5.2?
←[31m←[1mUnknown options: '-u', 'gcime'←[21m←[39m←[0m
Usage:
←[1m←[4m<main class> search←[24m←[21m←[0m [←[33m-ah←[39m←[0m] [←[33m-s←[39m←[0m=←[3m<search>←[23m←[0m]
Description:
search users by username or mail and retrive users data
Options:
←[33m-a←[39m←[0m, ←[33m--all←[39m←[0m Specify to show all users if more then limit of 20
users in search result
For example, `-a`
←[33m-h←[39m←[0m, ←[33m--history←[39m←[0m Specify to show user dossier
For example, `-h`
←[33m-s←[39m←[0m, ←[33m--search←[39m←[0m=←[3m<search>←[23m←[0m Specify search by username or email
For example, `-s [email protected]`
Missing required subcommand
commands for kdo cli
Usage>> command switches
help>> help
help for search command>> help search
Commands:
help Displays help information about the specified command
search search users by username or mail and retrive users data
Oh no, that gitbash output looks bad...
Is the PS output what you expected?
Also, can you print the output of gitbash when you run with -Dpicocli.trace=DEBUG?
I cannot reproduce this. How do I set up a MSYS2-based Windows Terminal shell?
[picocli DEBUG] Creating CommandSpec for si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Creating CommandSpec for class picocli.CommandLine$HelpCommand with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'help' to '<main class>'
[picocli DEBUG] Creating CommandSpec for class si.arnes.kdo.cli.SearchCmd with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Getting a si.arnes.kdo.cli.SearchCmd instance from factory picocli.CommandLine$DefaultFactory@51016012
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[picocli DEBUG] Factory returned a si.arnes.kdo.cli.SearchCmd instance (5d3411d)
[picocli DEBUG] Creating CommandSpec for si.arnes.kdo.cli.option.KdoOptions@2471cca7 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'search' to '<main class>'
[picocli INFO] Picocli version: 4.5.2, JVM: 1.8.0_201 (Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.201-b09), OS: Windows 10 10.0 amd64
[picocli INFO] Parsing 3 command line args [search, -s, gcime]
[picocli DEBUG] Parser configuration: optionsCaseInsensitive=false, subcommandsCaseInsensitive=false, abbreviatedOptionsAllowed=false, abbreviatedSubcommandsAllowed=false, aritySatisfiedByAttachedOptionParam=false, atFileCommentChar=#, caseInsensitiveEnumValuesAllowed=false, collectErrors=false, endOfOptionsDelimiter=--, expandAtFiles=true, limitSplit=false, overwrittenOptionsAllowed=false, posixClusteredShortOptionsAllowed=true, separator=null, splitQuotedStrings=false, stopAtPositional=false, stopAtUnmatched=false, toggleBooleanFlags=false, trimQuotes=false, unmatchedArgumentsAllowed=false, unmatchedOptionsAllowedAsOptionParameters=true, unmatchedOptionsArePositionalParams=false, useSimplifiedAtFiles=false
[picocli DEBUG] (ANSI is enabled by default: systemproperty[picocli.ansi]=null, isatty=true, TERM=cygwin, OSTYPE=null, isWindows=true, JansiConsoleInstalled=false, ANSICON=null, ConEmuANSI=null, NO_COLOR=null, CLICOLOR=null, CLICOLOR_FORCE=null)
[picocli DEBUG] Initializing command 'null' (user object: si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6): 0 options, 0 positional parameters, 0 required, 0 groups, 2 subcommands.
[picocli DEBUG] [0] Processing argument 'search'. Remainder=[-s, gcime]
[picocli DEBUG] Found subcommand 'search' (command 'search' (user object: si.arnes.kdo.cli.SearchCmd@5d3411d))
[picocli DEBUG] Checking required args for parent command 'null' (user object: si.arnes.kdo.cli.TopLavelCommands@3f8f9dd6)...
[picocli DEBUG] Initializing command 'search' (user object: si.arnes.kdo.cli.SearchCmd@5d3411d): 3 options, 0 positional parameters, 0 required, 0 groups, 0 subcommands.
[picocli DEBUG] Set initial value for field String si.arnes.kdo.cli.option.KdoOptions.search of type class java.lang.String to null.
[picocli DEBUG] Set initial value for field boolean si.arnes.kdo.cli.option.KdoOptions.history of type boolean to false.
[picocli DEBUG] Set initial value for field boolean si.arnes.kdo.cli.option.KdoOptions.all of type boolean to false.
[picocli DEBUG] [1] Processing argument '-s'. Remainder=[gcime]
[picocli DEBUG] '-s' cannot be separated into <option>=<option-parameter>
[picocli DEBUG] Found option named '-s': field String si.arnes.kdo.cli.option.KdoOptions.search, arity=1
[picocli DEBUG] 'gcime' doesn't resemble an option: 0 matching prefix chars out of 6 option names
[picocli INFO] Setting field String si.arnes.kdo.cli.option.KdoOptions.search to 'gcime' (was 'null') for option -s on KdoOptions@2471cca7
[picocli DEBUG] Applying default values for command '<main class> search'
[picocli DEBUG] defaultValue not defined for field boolean si.arnes.kdo.cli.option.KdoOptions.history
[picocli DEBUG] defaultValue not defined for field boolean si.arnes.kdo.cli.option.KdoOptions.all
[picocli DEBUG] Applying default values for command '<main class>'
←[31m←[1mjava.net.ConnectException: Connection refused: connect←[21m←[39m←[0m
{
"guid": "{07b52e3e-de2c-5db4-bd2d-ba144ed6c200}",
"hidden": false,
"name": "GitBash",
"commandline": "\"%PROGRAMFILES%\\git\\bin\\bash.exe\" --login -i -l",
"icon": "%PROGRAMFILES%\\git\\mingw64\\share\\git\\git-for-windows.ico"
}
I was able to reproduce some strangeness when running picocli.AutoComplete or picocli.Demo in gitbash in Terminal. Not exactly the behaviour you are seeing, ANSI colors are partially working for me, but with some strange layout artifacts.
By the way, the value of the TERM environment variable in my gitbash in Terminal is not cygwin, but xterm-256color. This is not the default when I run gitbash: in plain gitbash, echo $TERM prints xterm. Not sure who is setting this value...
About Powershell: is your application using Jansi? Using Jansi is the most reliable way to get colors in Powershell. I gave more details in an earlier comment.
Without that, you can try setting one of the environment variables that picocli checks:
# set environment variable
$Env:CLICOLOR=1
# now run a command that shows colored output
java -cp "picocli-4.5.2.jar;picocli-4.5.2-tests.jar" picocli.Demo
$Env:CLICOLOR=1 is working, error -> color redok, I propose we put Powershell aside. I believe this (PS) is working as expected.
AnsiConsole.systemInstall();
CommandLine commands = new CommandLine(new TopLavelCommands()).setExecutionExceptionHandler(errorHandler);
System.exit(commands.execute(args));
AnsiConsole.systemUninstall(); // cleanup when done
Do you mean that with Jansi, you also see correct output in gitbash in Windows Terminal?
Yes, it solved the problem and also no strange output like ←[31m←[1m,
That is good. Still weird that plain gitbash works fine for me but gitbash in Terminal gives strange layout problems.
Does plain gitbash (without Terminal) work correctly for you without Jansi? (Trying to isolate whether the problem is with Terminal...)
Looks to be a Terminal issue...
And you have a solution: use Jansi. So I think we are ok... no?
Yes, I think so, thx again :)
Great!
Please star ⭐ picocli on GitHub if you like the project! 😉