Unexpected reset behavior
See original GitHub issueWith this code:
const kleur = require('kleur')
console.log(kleur.red(kleur.reset('a' + kleur.blue('b') + 'c')))
The result is that the last character logged is unexpectedly red, when it should be default (black):
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
Top Results From Across the Web
When Unexpected Behavior Occurs
1. Reminder - My teacher will give me a reminder of what the expected behavior is. · 2. Reset - When a reminder...
Read more >Unexpected Reset - a courageous guide to intentional living
Unexpected Reset's purpose is to revive our senses and look critically at why we do what we do and question if we have...
Read more >Behavior Reset Teaching Resources - TPT
RESET : Responding to Behaviors When unexpected behaviors happen, it can be hard to bring children back to a place where they feel...
Read more >ESXi host platform reset behavior with Intel TPM/TXT's reset ...
The error message is the expected behavior when platform is reset in an ungraceful manner and BIOS does not implement Intel's desired workflow. ......
Read more >Unusual behavior in Dreamweaver? Try restoring preferences.
... to default settings to fix issues, crashes, errors, and other unexpected behavior. ... Dreamweaver 2014.1 and later - Reset preferences.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
You’re welcome. I’ll try a different way, without HTML references because it doesn’t actually share any behaviors 😃 I chose it on a whim just to show the nesting hierarchy, but I think the inline comments might be better.
So, RESET (when caps, refers to ANSI) terminates all style codes when encountered. For this reason, it has no close-code pairing. This makes it unique from the others in that everything else is “apply until X” whereas RESET is just “apply”. In other words, RED will continue applying RED until its assigned close-code is found, BOLD still applies BOLD until closed. RESET doesn’t have an “until” clause. It applies at that point, immediately closing all previously-open windows:
However, ANSI codes of the same type share close codes. Because of this, when nesting colors, your RED has to re-initialize itself on the back of any close-code occurrences it finds within the payload. If it doesn’t, then RED terminates once the other color does too:
If we look back at the original issue (I only changed text for visibility) and the step-by-step, now with diagrams:
We see the same behavior happening. Between (2) and (3),
kleur.red
is inheriting a payload that already contains the[39m
that would close RED as well as the BLUE. Because of that, RED re-inserts itself so as to not break (like the first example). Now, this means that+R
is added immediately after the-B|-R
– but this so happens to be before theZZZ
text too.It might be helpful to see the same chain, but replacing RESET with another non-color code to be alongside RED/BLUE:
It’s the exact same thing as before – RED still injects itself once BLUE closes (because BLUE also terminates RED) – but there are no surprises here because UNDERLINE is stateful. It underlines until it no longer does.
The “surprise” is that nesting
kleur.reset
inside of payloads will not (and cannot) act like other wrappers. Everything except RESET is given an open->close window. If we had to go back to bad HTML metaphors, RESET would be like a<br/>
… but only if using<br/>
inside other<b>
,<strong>
,<em>
, …etc tags caused them to self-close and reset cleanly. HTML has a lot of self-closing rules, but that isn’t one of them 😄Changing gears a bit – If the API was a
kleur.RESET
(constant) instead, I think we’d still have surprises:While the
k.RESET
would have reset anything that came before it, the parentk.red()
still is told to wrap the payload. Given that, it sees the[39m
and reinserts itself to makeZZZ
red.Thank you, I appreciate the considerable detail in your comment. I apologise though as I’m struggling to grok all of the explanation.
The ANSI reset code doesn’t have a related end code, but do we need it to? Can’t nested color calls only restore the parent formatting if there is no reset code before it at the same level?
HTML doesn’t need end tags for some things, like
<li>
. It can automatically close the last one when it encounters the next one:https://www.w3.org/TR/2014/REC-html5-20141028/syntax.html#optional-tags
Could a similar concept be applied to an implementation here for reset nesting?
If there truly is no solution, then
kleur.reset()
should probably not be a chainable/nestable function like the other color and formatting options. It should just be removed from the API, or perhaps exist as a standalone function or constant for manual insertion. Is the rule thatkleur.reset()
can be nested inside otherkleur
functions, but not the other way around? Could misuse be detected and throw an error?