[FEATURE REQUEST] Fallbacks when true color or ANSI 256 is not supported
Closed this issue · 13 comments
Current behaviour
When using hex()
method in a terminal having only 256 colors, the following things happen:
- There is no fallback to the closest color from 256-color palette,
- The following output has distorted colors that can not even be forced to normal.
Expected behaviour
- There should be fallback to the lower palette level, similar to Chalk behaviour, it should find a color closest to the requested one;
- If a certain color is not supported, that should not alter the next output.
Reproduction Example
import { ansi256, hex, white } from "ansis";
const pink = hex("#F5A9B8");
const blue = hex("#5BCEFA");
// running in 256 colors mode
console.log(ansi256(199)("Color 199")); // works
console.log(pink("This should be pink")); // no fallback to 256
console.log(blue("This should be blue")); // no fallback to 256, wrong color
console.log("This should be default"); // does not return to default color
console.log(white("Forced white")); // can not even force white
Environment
- OS: macOS
- version of Node.js: v20.11.1
- version of Webpack: not applicable
- version of the Plugin: ansis@2.3.0
Additional context
Using built-in Terminal on MacOS having 256 colors.
For comparison, this is how it looks when running in iTerm having true color support
Here is a similar code, but using chalk
v4.1.2
import chalk from "chalk";
const pink = chalk.hex("#F5A9B8");
const blue = chalk.hex("#5BCEFA");
console.log(chalk.ansi256(199)("Color 199"));
console.log(pink("This should be pink"));
console.log(blue("This should be blue"));
console.log("This should be default");
console.log(chalk.whiteBright("Forced white"));
Running it in built-in Terminal on MacOS having 256 colors gives the desirable output:
Hallo @RobinTail,
Thanks for the feature request!
- I will check the issue with default color in the next output.
- Yes, it is very important to have a fallback for a terminal supported 256 colors only.
I will implement it in the next version.
Grüß aus Köln
Yes, it is very important to have a fallback for a terminal supported 256 colors only.
I will implement it in the next version.
Thank you, @webdiscus
Ideally it should have fallbacks down to the minimal supported palette.
True color —> 256 colors —> 16 colors —> no colors.
For example, doing hex("#5BCEFA")
in environment having 16 colors only, it should fall back approximately to cyan
.
@RobinTail
I have implemented the detection of color spaces: truecolor, 256 colors, 16 colors, mono.
The fallback truecolor —> 256 colors —> 16 colors —> no colors
works too.
I'm by testing and refactoring.
I'm glad to read it, @webdiscus , great news!
Let me know if you need any help.
Awesome! I'm going to try it today, @webdiscus
Dear @webdiscus ,
It works perfectly! Thank you so much for all the effort you applied to this feature and your attention to details.
I highly appreciate that you measured the performance and updated documentation.
Fallbacks, named imports, CommonJS compatibility — everything works well.
I tested it in iTerm, Terminal of MacOS and GitHub CI.
By the way, @webdiscus
I noticed you also switched to vitest, and I'd like to inform you that vitest now also has benchmarking tools:
https://vitest.dev/api/#bench
So that you can have a single dependency both for testing and benchmarking.
I use it myself and I like how it works.
Thank You for the very useful feature request!
This makes the library even better.
I have invested a time to optimize performance and size for the new features.
New features adds in bundle only ~600 bytes and the code bundle is still < 4 KB.
vitest now also has benchmarking tools: https://vitest.dev/api/#bench
Thanks @RobinTail for the info.
Yes, I know, and I will switch the benchmark to vitest/bench, but in next step. First I wanted to release the feature and then optimize the benchmark.
Vitest is a very cool tools. This allow to test ESM modules "out of the box". Jest doesn't work with ESM in JetBrains IDEA, so I switched to vitest.
New features adds in bundle only ~600 bytes and the code bundle is still < 4 KB.
That's a great result, @webdiscus !
I highly appreciate your passion.
I think the issue is resolved, so I'm going to close it.
Thank you so much for all the support :)
I have create some simple tests suits using vitest bench.
I am saddened :-(
- it's still very raw and is not yet released:
Benchmarking is an experimental feature. Breaking changes might not follow SemVer, please pin Vitest's version when using it.
- it's very very buggy and does not work stably. Using only 4 suits occurs
fatal error
:Allocation failed - JavaScript heap out of memory
- test results are false and
cannot be trusted
, e.g., the simple bench forchalk.red('foo')
andansis.red('foo')
have results:To compare with the result of thechalk 7.000.000 ansis 23.000.000 (x3 faster than chalk - this is unreal/FALSE result)
benchmark
:chalk 73.000.000 ansis 69.000.000 (this is TRUE result)
So, we cannot trust the results of the vitest bench
.
We need to wait until the first release appears.
Alright, you seem to made a deep research on that topic.
Perhaps it's not yet ready for the project of your scale.
Regarding the accuracy of the measurements.
I think it's different because vitest
runs the tests against the transformed code (using esbuild and rollup under the hood). Perhaps it does that transformation differently for ansis
and chalk
.
I hope it will get better. Thanks for letting me know, @webdiscus