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

Command Shell Script to generate and display all combinations of SGR properties which can be applied as ANSI Escape Sequence control characters to text #6470

Closed
rbeesley opened this issue Jun 12, 2020 · 4 comments · Fixed by #11932
Labels
Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. Help Wanted We encourage anyone to jump in on these. Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Meta The product is the management of the products. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Milestone

Comments

@rbeesley
Copy link
Contributor

Description of the new feature/enhancement

Inspired by Daniel Crisman's BASH script from http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html. The proposed .cmd script tool echoes a bunch of color codes to the terminal to demonstrate what's available. The end of the file defines the table layout and allows the user to configure whatever matrix of ANSI Escape Sequence control characters they wish. It accomplishes this with no required external dependencies. Of the optional dependencies, the first is on PowerShell to generate the 0x1b ESC, but this can be implemented using an unprintable character, and the only recommended dependency is on %SystemRoot%\system32\chcp.com when the rendered content contains Unicode code points, used to both preserve the code page before the script was ran, switch to code page 65001, and to restore the original when complete.

Proposed technical implementation details (optional)

The .cmd script uses a "Data Segment" in the file, a section of the script blocked from execution by a guards, and it describes the configuration of the table to be displayed. You provide the text you want to display, a list of column SGR properties, and a list of row SGR properties. These properties are written to the box header and the stub header to indicate what the intersection of properties will be, for example Background for columns and Foreground for rows, it left, center, or right justifies the output for improved readability, and each cell renders a sample text string proceeded by these column and row SGR properties and terminated by a reset. These rendered rows are written to a table array variable.

Because the processing time for doing text alignment in a .cmd script is an expensive operation, there is an animated spinner, which can be disabled, which indicates to the user that the script is processing. Drawing the animation takes some time, so the user has a choice of waiting while the processing is happening in the background with no indication that the script is still running, or they can incur a slight increase in the amount of time it takes to run but have an animated indicator that the script is working. Once the table has been completely built, a routine will quickly dump the entire fully rendered view to the terminal window, allowing the user to see the application of all of the properties applied to the sample text string.

The entire script is fully customizable just by modifying the data segment which describes the table and/or by configuring a few environment variables at the top of the script. One of these variables replaces the 0x1b escape with the Unicode character. This makes it very easy to see in printable characters what is being rendered with applied SGR properties. Because this character is Unicode, this is where the optional dependency upon chcp.com comes from, but it was latter recognized that this is necessary if the sample text contains Unicode, so it is recommended that it is left on by default, but if not needed and the user doesn't want any external dependencies, it can be switched off.

Functions which tend to be expensive operations, such as figuring out the length of a string, the maximum value between two values, text alignment operations, repeating a string a number of times, and drawing the processing spinner animation, these have been written as macros to improve the script performance. The script is documented where and how it can be documented. This makes it useful for those writing color schemes for Windows Terminal to see how their colors will be shown, can assist in identifying and debugging when applied SGR properties aren't being shown correctly, and demonstrates and uses advanced techniques writing batch files so that these techniques can be used by others. All of this is self-contained in a single .cmd script. If other SGR properties become supported, adding them will be trivial.

In #6176, zadjii said in a comment that he'd welcome this PR. As someone who has contributed on several color scheme related check ins, this is the product of lot's of manhours of work over a few years, producing a tool that I think is ready for more general consumption, with a minimum requirement of running under cmd.exe, and I believe it showcases a lot of valuable techniques for writing .cmd scripts which haven't really been coalesced before. Adding it as a tool to Terminal seems like an appropriate match providing value to those who can use it. It is the Windows equivalent of Daniel Crisman's BASH script with more features and capabilities than the original.

Preliminary script in action:
ansi-color cmd

@rbeesley rbeesley added the Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. label Jun 12, 2020
@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Jun 12, 2020
@DHowett DHowett added Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. Help Wanted We encourage anyone to jump in on these. Product-Meta The product is the management of the products. and removed Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting labels Jun 12, 2020
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label Jun 12, 2020
@DHowett DHowett added this to the Terminal Backlog milestone Jun 12, 2020
@DHowett
Copy link
Member

DHowett commented Jun 12, 2020

👍

@zadjii-msft
Copy link
Member

@rbeesley did you plan on submitting a PR for this?

@rbeesley
Copy link
Contributor Author

rbeesley commented Dec 9, 2021

I can. I have it ready and can prepare it today.

@ghost ghost added the In-PR This issue has a related PR label Dec 13, 2021
@zadjii-msft zadjii-msft modified the milestones: Terminal Backlog, Backlog Jan 4, 2022
@ghost ghost closed this as completed in #11932 Jan 4, 2022
ghost pushed a commit that referenced this issue Jan 4, 2022
Adds the Ansi-Color tool, completing #6470.

What started out as an experiment to see the support of ANSI support to
conhost, I wanted to write a Windows equivalent of Daniel Crisman's
[BASH script on tldp.org]. I didn't like how the BASH script hard coded
in whitespace and I thought Windows could do better. I applied
techniques to speed up the execution and tried to use the Command Script
batch language in ways that pushed the limits for what I thought it
could do. Running this from withing PowerShell, `&cmd /c ansi-color.cmd`,
I found out that the active code page is already 65001, but when ran
from a Command Prompt, the active code page depends on the regional
settings and I would have a dependency on CHCP to detect the active code
page, change to 65001 if necessary, and restore the previous code page
after running. I found it useful for designing color schemes and writing
shaders, and I started using an earlier version for logging bugs.

Initially it was a single script which I would dump every SGR
combination I could think of, and many which weren't implemented yet,
but as I was looking at other tools which had been written I wanted to
mimic the same output so I could do side-by-side comparisons. First I
wrote `crisman.def` and then `colortool.def`. So I had to align text.
Then output was slow for big tables so I wrote to an outbuffer and made
use of macros. I wanted to handle flags instead of needing to change
settings every time, so I added argument parsing and loading external
files.

It's a batch file that has some really useful purposes and does nothing
I've seen before. 

I've ran every definition in a Command Prompt, with CP 437 and CP 65001
to make sure it works. Posted as a Gist on my account for about year, a
Portuguese (Brazilian as I recall), speaking user tried the Gist and it
was failing because CHCP is localized. I've taken an approach to try and
make it work for different localizations, but this is a potential
problem. I also ran every definition in PowerShell 7, shelling down to
`cmd` to actually run it. Lastly, I went through using the flags and
made sure that help would be shown. Error messages generate error levels
when the script exits, so those could be used to use this in an
automated test and catch if there was a problem with the script
executing. It won't be able to validate if the generated output shows
correctly, but it would fail if a definition file is missing or if it
needed to switch to Unicode and wasn't flagged or configured to do so.
For trying to build the table stub and headers, there is some debug code
which will output what was parsed. This is the last debug code in the
script itself, but I found it to be useful at times, so there is a
configuration setting which can turn that debug output back on.
Technically there is also a debug statement to break after adding the
macros and parsing the arguments, but before it does any configuration
changes, changes the code page, or anything. This was useful for making
changes to macros and being able to test them as well as making sure
that flags and arguments are parsed correctly. It was a rather cryptic
discovery to call `cmd /c exit -1073741510` to break out, so in part
that was my reason to leave this in. The definition files themselves
could be cleaned up further, but in both of them there are a lot of
Unicode codepoints that could be useful when defining division lines for
the headers so I opted to just comment them out. I initially had the
default definition to require Unicode, but now it just changes to a
non-Unicode output if it can't. And this brings up the last concern. The
way certain settings are set, is that they are defined in the
`__TABLE__` section of the definition file.  With `PARSE_TABLE_DATA`,
the script looks line by line for `SET *` or `IF *` and if found it will
effectively eval that line. The definition files are written so that for
instance `SET "CELL= gYw "` could be used to set the code which is used.
`If` was allow so that there could be a test if Unicode were available
and set something different for ASCII and Unicode. But it also opens the
possibility that a rogue actor could create a `ansi-color.cmd`
definition file something like `SET "foo=bar" & DoSomethingBad.exe`.
First of all I'd be flattered that anyone would use this very niche
tool, but it is something I think which needs to be called out.
Essentially the definition files are just batch files, but they are
extremely limited to executing only one line at a time and only
supporting IF and SET commands. I think this is a minimal risk because
at that point batch files would already be more effective, but there
should also be an expectation that a batch file will run something and
the same may not be true for the heavily degraded definition files. I
think the risk is minimal but it is a risk I wanted to make clear. This
really showcases some interesting techniques and ideas, and I hope that
it is useful. All told, there are a couple years of incremental changes
in this PR.

Closes #6470

[BASH script on tldp.org]: https://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Jan 4, 2022
@ghost
Copy link

ghost commented Feb 3, 2022

🎉This issue was addressed in #11932, which has now been successfully released as Windows Terminal Preview v1.13.10336.0.:tada:

Handy links:

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-CodeHealth Issues related to code cleanliness, linting, rules, warnings, errors, static analysis, etc. Help Wanted We encourage anyone to jump in on these. Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Meta The product is the management of the products. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants