Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieve current foreground and background color #120

Closed
ad-si opened this issue Dec 27, 2021 · 10 comments
Closed

Retrieve current foreground and background color #120

ad-si opened this issue Dec 27, 2021 · 10 comments

Comments

@ad-si
Copy link

ad-si commented Dec 27, 2021

I want to implement a dark and light mode for a CLI tool, but therefore I need to figure out the current fore-/background color.

There seems to be a control sequence for it: https://stackoverflow.com/a/7767891/1850340
However, it's not clear if the response can be captured in a sensible way.

Are there any other ways to achieve this?

@ad-si
Copy link
Author

ad-si commented Dec 27, 2021

Here is another Answer with some more information:
https://unix.stackexchange.com/a/245568/96815

It also mentions a $COLORFGBG environment variable which might be better suited.

@UnkindPartition
Copy link
Owner

However, it's not clear if the response can be captured in a sensible way.

We already have a similar logic for querying the cursor position; perhaps it could be generalized to cover this case as well.

getReportedCursorPosition = do
-- If, unexpectedly, no data is available on the console input stream then
-- the timeout will prevent the getChar blocking. For consistency with the
-- Windows equivalent, returns "" if the expected information is unavailable.
fromMaybe "" <$> timeout 500000 get -- 500 milliseconds
where
get = do
c <- getChar
if c == '\ESC'
then get' [c]
else return [c] -- If the first character is not the expected \ESC then
-- give up. This provides a modicom of protection against
-- unexpected data in the input stream.
get' s = do
c <- getChar
if c /= 'R'
then get' (c:s) -- Continue building the list, until the expected 'R'
-- character is obtained. Build the list in reverse order,
-- in order to avoid O(n^2) complexity.
else return $ reverse (c:s) -- Reverse the order of the built list.

@mpilgrem
Copy link
Collaborator

On Windows 10/11 and with Windows Terminal (planned to be the default terminal on Windows 11 during 2022: https://devblogs.microsoft.com/commandline/windows-terminal-as-your-default-command-line-experience/), the implementation of the OSC 11 code appears to be a work in progress: microsoft/terminal#3718. For now, if this were to be implemented in ansi-terminal it would likely be only for Unix-like OSs.

mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 1, 2022
Not supported by native terminals on Windows.

Also adds, and applies, utility `osc :: [(String, String)] -> String`, as several functions now use the XTerm OSC control sequences.

This means that `setTitleCode` now ends with the recommended STRING TERMINATOR (ST), rather than legacy `\007`. The filter in `setTitleCode` is changed to exclude all non-printable characters.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 2, 2022
Not supported by native terminals on Windows.

Also adds, and applies, utility `osc :: [(String, String)] -> String`, as several functions now use the XTerm OSC control sequences.

This means that `setTitleCode` now ends with the recommended STRING TERMINATOR (ST), rather than legacy `\007`. The filter in `setTitleCode` is changed to exclude all non-printable characters.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 2, 2022
Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 2, 2022
Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 2, 2022
…r` etc

Also adds `reportLayerColorCode`, `layerColor` and `getLayerColor`.

Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
@mpilgrem
Copy link
Collaborator

mpilgrem commented May 3, 2022

I have been looking into this further, on macOS 10.15.5. I am running into inconsistencies with the STRING TERMINATOR (ST) in the output. I was hoping the output would use the same ST as the command.

macOS Terminal v2.10 (433) appears to recognise legacy "\BEL" and modern "\ESC\" but returns only "\BEL".
iTerm2 build 3.4.15 appears to be the same as macOS Terminal.
Hyper 3.2.3 (stable) appears to recognise "\BEL" and "\ESC\" but return only "\ESC\".

On Windows:
mintty 3.6.0 appears to recognise "\BEL" and "\ESC\" and return the same ST as the command.

mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 4, 2022
Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 4, 2022
Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 4, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

Not supported by terminals on Windows. Native terminals do not allow the color to be reported. Other terminals do not allow the reported color to be read from the console input stream.
@mpilgrem
Copy link
Collaborator

mpilgrem commented May 4, 2022

@ad-si, I think my proposed pull request #137 will add this to ansi-terminal for Unix-like operating systems only. I have tested it on macOS 10.15.5 (Catalina) (with macOS Terminal, iTerm2 and Hyper) but my access to machines with other Unix-like operating systems is limited. If you were able to test that PR, I would be grateful.

My proposed API mimics the existing API for getCursorPosition :: IO (Maybe (Int, Int)) etc, with getLayerColor :: ConsoleLayer -> IO (Maybe (RGB Word16)) etc. As explained in the Haddock documentation, I chose RGB Word16 because 16 bit colour channels is the most common format used by terminal software to report colours.

mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
Emulation works for the Windows Console Host (ConHost) user-interface and not for Windows Terminal.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
Emulation works for the Windows Console Host (ConHost) user-interface and not for Windows Terminal.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
Emulation works for the Windows Console Host (ConHost) user-interface and not for Windows Terminal.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 6, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

Also updates and reorganises some Haddock documentation for developments in Windows.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 7, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

Also updates and reorganises some Haddock documentation for developments in Windows.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 7, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.

Also updates and reorganises some Haddock documentation for developments in Windows and to take a consistent approach to the documentation of the 'h...' and '...Code' variants.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 7, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.

Also updates and reorganises some Haddock documentation for developments in Windows and to take a consistent approach to the documentation of the 'h...' and '...Code' variants.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 7, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
@mpilgrem
Copy link
Collaborator

mpilgrem commented May 7, 2022

I have updated my pull request to cover Windows, and I think it could be merged and a new version of ansi-terminal released, but I going to wait a little while to see if the position as regards GHC's WinIO can be bottomed out (see below).

On Windows, things are a little complicated. As mentioned above, the native terminals still do not support the OSC code. So, I have emulated that. However, the emulation only works for ConHost and not for Windows Terminal (which no longer uses ConHost for the user-interface). Further, getting the data emitted into the input stream has to use the Windows Console API (GHC's WinIO does not yet provide a solution - see https://gitlab.haskell.org/ghc/ghc/-/issues/21488) and so will not work on mintty (for example).

mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue May 9, 2022
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue Nov 21, 2022
…getLayerColor

Also adds `hReportLayerColor`, `hGetLayerColor` and `layerColor`.

On Windows, emulated using the Windows Console API but the emulation of `reportLayerColor` works only on the native ConHost terminal and not on Windows Terminal. Non-native terminals cannot make use of `getReportedLayerColor`.
mpilgrem added a commit to mpilgrem/ansi-terminal that referenced this issue Nov 21, 2022
@ad-si
Copy link
Author

ad-si commented Jan 4, 2023

Awesome, thanks a lot for implementing this @mpilgrem!

The docs say:

Uses stdout. If stdout will be redirected, see hGetLayerColor for a more general function.

But how would it work to use some other Handler? When I use it with stdout, it behaves very weirdly on redirection:

$ stack run open | head -c 40
Id     []11;rgb:1999/1999/1999^[\⏎
$ ]11;rgb:1999/1999/1999\

How can I fix / circumvent this?

@mpilgrem
Copy link
Collaborator

mpilgrem commented Jan 4, 2023

@ad-si, the way that this works is that the relevant 'ANSI' codes are detected in the (ANSI-capable) terminal's output stream and the information is injected into the terminal's input stream. If the stdout output stream is redirected away from the terminal, then you need to use stderr (assuming it is not also redirected). For example:

module Main (main) where

import System.Console.ANSI ( ConsoleLayer (..), hGetLayerColor )
import System.IO ( stderr )

main :: IO ()
main = do
    mBC <- hGetLayerColor stderr Background 
    mFC <- hGetLayerColor stderr Foreground 
    print (mBC, mFC)

@ad-si
Copy link
Author

ad-si commented Jan 4, 2023

Yeah, stderr is already a little better, but is there no way to create something like a "dummy output stream", which will never interfere with the normal usage of the CLI tool?

@mpilgrem
Copy link
Collaborator

mpilgrem commented Jan 4, 2023

@ad-si, not as far as I am aware. An application's code would usually detect if its output was to a terminal or not (eg redirected) (https://hackage.haskell.org/package/ansi-terminal-0.11.4/docs/System-Console-ANSI.html#g:32), and then behave accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants