-
Notifications
You must be signed in to change notification settings - Fork 52
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
Disable color output for the single instance #42
Comments
Nope, there's no API for that at the moment. |
@jorgebucaran How can I disable colors for GitHub CI? |
@snitin315 The simplest way to disable color output is by using the NO_COLOR= node my_program.js Similarly, you can force color even when it would be disabled by default (for example while your program is being piped into another program) by using the colorette/.github/workflows/test.yml Lines 18 to 23 in c5b8a00
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@jorgebucaran Actually, this kind of an API would resolve pinojs/pino-pretty#220 |
Sure, we could look into this, but I want to understand why this is needed to start with. Care to explain what's the problem with pinojs/pino-pretty#220? I still don't understand what's happening. |
Because it leaks state. Imagine I already use Colorette in my project, and then I add pino-pretty, and this transitive dependency suddenly affects my main project and turns on colourizing globally even though it was off before. |
You are describing the problem of "global state" (evil, I know), but is that what's actually happening in pinojs/pino-pretty#220? Do you have any guesses as to where the unwanted mutation is? Could it be pino-pretty changing |
@jorgebucaran Original problem is a difference in behaviour between chalk and colourette. It was possible for pino-pretty to explicitly force Chalk instance to colourize, bypassing all checks. Colourette requires global state changes to achieve the same. |
Oh, okay, so pino-pretty always colorizes regardless of terminal support (I mean that's what you want), correct? |
@jorgebucaran To be precise, it works like this:
Hence currently default colourizing behaviour is correct, but behaviour for when user has explicitly enabled colourizing is not, because it will also additionally check if there is terminal support for colourizing, and if not, ignore explicitly set colourizing flag. |
So, the user actually enabled color, but that didn't actually set Colorette's Can you tell me where in pino-pretty is defined the behavior for when the user has explicitly enabled color? Want to see how it was implemented. |
@jorgebucaran pinojs/pino-pretty@bb1afa5 this was the place. And yes. |
I see. Could you remind me how |
@jorgebucaran opts.colorize either defaults to |
Main difference is that previously Chalk part was always enabled, so it was up to pino-pretty part either being enabled or not. Currently even if pino-pretty part is enabled, if Colorette thinks terminal doesn't support it, nothing will be colourized. |
So, it serves the same purpose as Colorette's coloretteOptions.enabled = opts.colorizer |
@jorgebucaran See the very beginning of this discussion. This leaks global state and affects everything else that might be using Colorette as well, e. g. main application using pino-pretty which may want to have very different configuration. This is a no-go for pino-pretty. Chalk avoids the problem by encapsulating colourization instances, which is what this issue suggests to implement for Colorette as well. |
This is a bit vague. Could you specifically point out what would go wrong? Could you describe a scenario where someone would be affected or experience unexpected behavior if we did
I suppose this means either forcing color or disabling color. Just to be sure.
No worries, I got this part. |
E. g. I am writing a CLI tool enterpriseCLI. I directly depend on Colorette, I use it for coloring my output. Within enterpriseCLI I set global value for |
It also works in reverse - if my environment doesn't explicitly support colours and I had to force-enable it in colorette from my enterpriseCLI, I will also have to force-enable it in pino-pretty, otherwise pino-pretty will disable coloring for my enterpriseCLI as well. |
Thank you, @kibertoad! I never considered this use case. Would this API work for you? import getColors from "colorette"
// Enable color explicitly
const { red } = getColors(true)
// Forcefully disable color
const { red } = getColors(false)
// or let me auto-detect it for you
const { red } = getColors() |
@jorgebucaran perfect! |
Great! Let me think it over a bit and if we don't come with anything better, we'll go with that. |
|
`import c, { enabled } from "colorette" const { red, green, blue } = c({ enabled })` Yupp, that looks great; defaulting to |
Would you like to implement it yourself, or should I give it a shot? |
Yeah, let's keep auto-detection built-in. Let me take care of this one! 👌 |
- New default function creates a Colorette instance - Color support automatically detected - Can enable or disable color output explicitly too - Introduce new isColorSupported constant - Remove options.enabled
@kibertoad Just pushed the new API to the import colorette, { isColorSupported } from "colorette"
if (!isColorSupported) throw new Error("Color not supported!")
// ...
const { blue } = colorette({ enableColor: myOptions.forceColor })
console.log(blue("I'm blue")) // => \x1B[34mI'm blue\x1B[39m Now, before going forward with this, I have an alternative API I'd like to submit for consideration as well: import { blue, bold, underline, toColor } from "colorette"
console.log(
toColor(blue("I'm blue"), { color: true })
) You could wrap import { blue, bold, underline, createColorizer } from "colorette"
const colorize = createColorizer({ color: true })
console.log(
colorize(blue(underline(bold("I'm blue da ba dee da ba da"))))
) Thoughts? |
@jorgebucaran Do I understand correctly that the main advantage of the alternate approach is being able to chain different styles?
|
You should be able to chain or nest styles either way. The alternative is somewhat "purer". I also find it more natural to import the color functions rather than create them via a function. While I prefer the alternative, I'm fine either way. |
@jorgebucaran I'm just looking from developer's perspective, and as a developer I want as little boilerplate as possible. Using two functions where I could use just one to the same effect feels like a step backwards. Maybe default instance could be created out-of-the-box, and color functions exported for it, so that those who do not need new API could just keep using them? |
My position is far less extreme than yours. I wouldn't mind some boilerplate in exchange for simplicity and a bit more purity. Your suggestion could work, let me think about it too. |
Just pushed the new documentation. Would you mind having a look at the API section and tell me if it makes sense to you or whether you'd do it differently? 🙏 |
@jorgebucaran Looks perfect! |
Haha, thanks. 😄 |
@kibertoad I'm taking your suggestion to export individual colors (always enabled) in addition to the new API. Now, did you notice the proposed A different API like this would: import { Colorette } from "colorette"
const { blue, options } = new Colorette({ colorize: true })
console.log(c.blue("Blue")) // => \x1B[34mBlue\x1B[39m
options.enabled = false
console.log(c.blue("Blue")) // => Blue |
@jorgebucaran I don't think this would be very useful. If someone needs to dynamically change configuration, they could simply create a new Colorette instance with a different configuration. Immutable instances are cleaner. |
It's just like Chalk's Still, do you reckon this solves pinojs/pino-pretty#220? |
FYI, here is the class-based implementation: export class Colorette {
constructor({ colorize } = { colorize: isColorSupported }) {
this.options = { colorize }
Object.keys(colors).forEach((key) => {
const color = colors[key]
this[key] = (s) => (this.options.colorize ? color(s) : s)
})
}
} and here's the factory-style implementation: export const createColors = (options = { colorize: isColorSupported }) => ({
options,
...Object.entries(colors).reduce((colorMap, [key, color]) => ({
...colorMap,
[key]: (s) => (options.colorize ? color(s) : s),
})),
}) |
@jorgebucaran Yeah, either solution would resolve that issue. |
I must have gotten it all wrong. So, |
@jorgebucaran Only within that new Chalk instance. There is no global state. |
Sounds like it will let you dynamically toggle color on or off, which is what I am suggesting here. Otherwise, how is |
|
@jorgebucaran What's the plan to proceed? |
I feel I think this is not currently blocking |
It is blocking. There are still regressions being reported with people losing colouring in pino-pretty. |
- New createColors function creates a Colorette instance - Color support is automatically detected, but you can override it via the useColor boolean property. - New isColorSupported property. true if the terminal supports color or false otherwise. - Remove options.enabled
Now available in const { createColors } from "colorette"
const { blue } = createColors(/* @param { useColor: boolean } */)
console.log(blue("2.0.0")) |
Woohoo! |
Hi. Can I have color output in one part of the app and non-color in other? Something like:
The text was updated successfully, but these errors were encountered: