PowerShell / PSReadLine

A bash inspired readline implementation for PowerShell
BSD 2-Clause "Simplified" License
3.72k stars 295 forks source link

PowerShell on osx - how to force to be completely monochrome #3918

Open rhubarb-geek-nz opened 9 months ago

rhubarb-geek-nz commented 9 months ago

Prerequisites

Exception report

See PowerShell on osx how to force to be completely monochrome

Should be able to easily use PowerShell on a monochrome terminal, ideally respecting the TERM environment variable.

Screenshot

Image 14-01-24 at 08 39

Environment data

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Darwin 23.2.0 Darwin Kernel Version 23.2.0: Wed Nov 15 21:53:34 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T8103
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Steps to reproduce

Open a terminal on macOS of type "Man Page", use pwsh

Typed text will be yellow on a yellow background

Expected behavior

Typed text should be visible no matter the type of terminal or colours used by the terminal

Actual behavior

Typed text is always yellow, hard to read on white or yellow backgrounds.

mklement0 commented 9 months ago

+1, but please reformat your post to provide a proper link to https://github.com/PowerShell/PowerShell/issues/21066, and provide an actual screenshot.

rhubarb-geek-nz commented 9 months ago

PSReadLine abide by terminfo

One proposal is to have the PowerShell core's $PSStyle.OutputRendering controlled by NO_COLOR, and then PSReadLine governed by terminfo.

Given .bashrc on Debian systems uses 'xterm-256color' as the determination on whether to use colours, then PSReadLine could do similar and if terminfo says the current terminal has more than 16 colours it could use colours, if 16 or less then it should be monochrome.

We note that macOS does not support "xterm-mono" in its terminfo database. Setting TERM is global for a session so affects other programs including 'pico' and 'nano'.

% TERM=xterm-mono nano
zsh: can't find terminal definition for xterm-mono
'xterm-mono': unknown terminal type.
% TERM=xterm infocmp | grep colors 
    colors#8, cols#80, it#8, lines#24, pairs#64,
mklement0 commented 9 months ago

@rhubarb-geek-nz, I just noticed that you can use xtermm on macOS, which is the xterm-mono equivalent and is also honored by PowerShell (but not PSReadLine yet).

Note that making PSReadline respect TERM also makes sense for supporting a value of dumb, which currently breaks the interactive experience.

Apart from that, it would be great if PSReadLine - in the absence of explicit color configuration for it (i.e. Set-PSReadLineOption -Colors ... having been called) - could automatically and dynamically - pick colors that work well with the terminal foreground and background color (at least as in effect at session startup). I imagine that won't be trivial, though.

This would more directly give you what you want - readability - while not having to forgo color support.

rhubarb-geek-nz commented 9 months ago

I would certainly like a monochrome option somehow. I often remove the default alias to "ls" in bash because I find it hard to read blue text on a black background, let alone yellow on white.

The great thing about monochrome is that it is (a) high contrast (b) the user's preference of colours.

mklement0 commented 9 months ago

Understood. I think that both things are worth implementing:

237dmitry commented 9 months ago

I think that PSReadline should understand $PSStyle.OutputRendering = "PlainText", since unlike NO_COLOR it is cross-platform.

mklement0 commented 9 months ago

Good point, @237dmitry.

What NO_COLOR and $PSStyle.OutputRendering = "PlainText" share (the former translates into the latter), if set directly, is that - unlike TERM, which implies specific terminal capabilities on Unix - they are pure expressions of user preference: the desire not to use color.

My only question is: Would users ever want to control this preference separately for output (already implemented in PowerShell) vs. interactive input?

rhubarb-geek-nz commented 9 months ago

My only question is: Would users ever want to control this preference separately for output (already implemented in PowerShell) vs. interactive input?

Perhaps, they may want NO_COLOR for all rendering of output because they are copying and pasting output tables and results into a document or a report, but want the colour during editing of commands to assist with syntax highlighting and auto-completion.

237dmitry commented 9 months ago

NO_COLOR is the first for syntax like ENV=value command And it does not work with aliases like alias ls="ls --color"

rhubarb-geek-nz commented 9 months ago

NO_COLOR is the first for syntax like ENV=value command And it does not work with aliases like alias ls="ls --color"

I am not sure what you mean.

Environment variables like LANG and TZ have traditionally affected the output of commands. Likewise TERM affects how editors drive the terminal console.

Aliases are purely internal to shells themselves and do not affect actual programs. It is the shell interpreting an alias that appends the argument --color to an invocation of ls, not the executing of /bin/ls or /usr/bin/ls.

Debian's .bashrc has similar to

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

So it determines the prompt based on the TERM environment variable. Likewise it conditionally sets up the alias of ls based on the executability of /usr/bin/dircolors

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
237dmitry commented 9 months ago

I am not sure what you mean.

I meant that this variable is not for global use so that the terminal becomes completely monochrome, but for launching individual utilities.

If I add export NO_COLOR="true" in ~/.bashrc then launched bash is still colored.

And not of all utilities understand $NO_COLOR in single-line syntax. For example, NO_COLOR="true" micro will start colored micro, and micro is not the only application.

As for pwsh, not everything is so smooth with it, because many users, unlike you, use profiles for shell configuration. And this is normal use, that's what $profile is for.

rhubarb-geek-nz commented 9 months ago

I certainly agree that NO_COLOR is not supported by every application, no-color-.org shows a list of a hundred or so programs that do (PowerShell is listed!). Likewise many applications ignore TERM. NO_COLOR is new and TERM is relayed by ssh.

One of the principles of UNIX software is mechanism, not policy.

Do we provide a mechanism to support monochrome, and if so is it a standard?

The policy is something different which we cannot enforce, who sets the variable (if that is the mechanism) in the first place and who else also abides by it.

Having the mechanism of supporting NO_COLOR does mean that I could change my .bashrc to set it depending on the TERM variable value, along with not setting the aliases for ls. That would be me implementing my policy.

In reality I don't customise machines .bashrc or profiles because life is really too short and I deal with hundreds of real and virtual machines and don't have time for customising each. However setting my TERM to be a simple "xterm" or similar does allow me to get by.

237dmitry commented 9 months ago

That's why we need to target pwsh so that the core and modules understand each other. To prevent PSReadline from being colorful when $PSStyle.OutputRendering is set to "PlainText". This is a single directive and works fine, even though it is primarily intended to output the results of a command to a file so that there are no esc-sequences in it.

For me, until this is implemented, I would just write a function that defines the colors in Set-PSReadlineOption

rhubarb-geek-nz commented 9 months ago

I can't set the colours in Set-PSReadlineOption because they are not static, the macOS terminal changes automatically between dark mode and light mode depending on the time of day, and I might have one window open as "Man Page" and the other as "Homebrew".

237dmitry commented 9 months ago

I can't set the colours in Set-PSReadlineOption because they are not static,

Base 16 console colors are not absolute, and they depend on terminal settings.

Just enter in different (dark and light) modes:

"`e[37m Some text `e[0m"

Screenshot 2024-01-15 235750

rhubarb-geek-nz commented 9 months ago

On MacOS Terminal in the different themes `e[37m just gave white text as per the ANSI escape sequence specification. So when on a yellow background, it gave white text. When Terminal is in light mode it is a very pale grey, eg the background is true bright white and the text is off-white.

237dmitry commented 9 months ago

So when on a yellow background, it gave white text

You have to configure terminal

Screenshot 2024-01-16 005550

function set-mono {

    $PSStyle.OutputRendering = "PlainText"

    Set-PSReadlineOption -Color @{

        Command = "`e[37m"
        Comment = "`e[37m"
        ContinuationPrompt = "`e[37m"
        Default = "`e[37m"
        Emphasis = "`e[37m"
        Error = "`e[37m"
        InlinePrediction = "`e[37m"
        Keyword = "`e[37m"
        ListPrediction = "`e[37m"
        ListPredictionSelected = "`e[7m"
        ListPredictionTooltip = "`e[37m"
        Member = "`e[37m"
        Number = "`e[37m"
        Operator = "`e[37m"
        Parameter = "`e[37m"
        Selection = "`e[7m"
        String = "`e[37m"
        Type = "`e[37m"
        Variable = "`e[37m"
    }
}
rhubarb-geek-nz commented 9 months ago

You have to configure terminal

Or just use a shell that works monochrome out of the box, eg bash or zsh, and only use PowerShell to execute scripts. The default terminal on MacOS gives you ( during the day ) black text on a white background. You should not have to reconfigure that to run PowerShell.