Тема: CMD/WSF/JS: поддержка ANSI последовательностей в консоли
Я уже писал похожую вещь на PowerShell: CMD/PS1: поддержка ANSI последовательностей в консоли.
Недавно обнаружил, что консоль WIN10 поддерживает ANSI-коды в условно ограниченном режиме: встроенные команды type и echo поддерживают в достаточной мере (управление положением курсора, цвета), powershell поддерживает тоже.
Дальше идет вольный перевод первой публикации на зарубежном форуме https://www.dostips.com/forum/viewtopic … amp;t=9857. Кстати, там недавно сообщили, что команда set /p тоже поддерживает их.
ECHO
for /f %a in ('echo prompt $e^| cmd') do @set "ESC=%a"
echo %ESC%[107m %ESC%[0m & echo %ESC%[104m %ESC%[0m & echo %ESC%[101m %ESC%[0m
TYPE
for /f %a in ('echo prompt $e^| cmd') do @set "ESC=%a"
echo %ESC%[107m %ESC%[0m >> example.txt
echo %ESC%[104m %ESC%[0m >> example.txt
echo %ESC%[101m %ESC%[0m >> example.txt
type example.txt
POWERSHELL
$ESC = [char]27
"$ESC[107m $ESC[0m`n$ESC[104m $ESC[0m`n$ESC[101m $ESC[0m"
Другие команды и утилиты по умолчанию не поддерживают, но этим можно управлять. После включения/выключения начинает работать для последующих сеансов консоли:
ВКЛЮЧИТЬ
reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
ВЫКЛЮЧИТЬ
reg delete HKCU\Console /v VirtualTerminalLevel
После включения вывод ANSI последовательностей начинает интерпретироваться.
В юниксах управляющие последовательности могут быть дополнительно закодированы следующим образом:
"\e[" <options> <command>
"\033[" <options> <command>
"\x1b[" <options> <command>
"^[[" <options> <command> # в консоли винды надо учетверять до "^^^^[["
Чтобы поддерживать все возможные варианты ANSI-кодов и быть минимально зависимым от реестровых настроек, написал небольшой скриптик -- на самом деле там больше описания чем кода. Если VirtualTerminalLevel включен в реестре, последовательности выводятся и интерпретируются напрямую в терминал, иначе эмулируется выводом через echo
<?xml :
: version="1.0" encoding="utf-8" ?>
<!-- :
@echo off
if "%~1" == "" timeout /t 0 1>nul 2>&1 && (
cscript //nologo "%~f0?.wsf" /?
goto :EOF
)
reg query "HKCU\Console" /v VirtualTerminalLevel 2>nul | find "0x1" >nul && (
cscript //nologo "%~f0?.wsf" %*
goto :EOF
)
for /f "tokens=* delims=" %%s in ( '
cscript //nologo "%~f0?.wsf" %*
' ) do echo:%%s
goto :EOF
: -->
<package>
<job id="ansi">
<?job error="false" debug="false" ?>
<script language="javascript"><![CDATA[
var NAME = 'ANSI';
var VERSION = '0.0.1';
]]></script>
<runtime>
<description><![CDATA[
Parse the specified text from the input file or pipe and output it
accordingly the ANSI codes provided within the text.
Escaping
Interpret the following escaped characters:
\a Bell
\b Backspace
\e Escape character
\f Form feed
\n New line
\r Carriage return
\t Horizontal tabulation
\v Vertical tabulation
\\ Backslash
\0nnn The character by its ASCII code (octal)
\xHH The character by its ASCII code (hexadecimal)
ANSI sequences
<ESC> [ <list> <code>
<ESC> Escape character in the form "\e", "\033", "\x1B", "^["
<list> The list of numeric codes
<code> The sequence code
Moves the cursor n (default 1) cells in the given direction. If the cursor
is already at the edge of the screen, this has no effect.
\e[nA Cursor Up
\e[nB Cursor Down
\e[nC Cursor Forward
\e[nD Cursor Back
Moves cursor to beginning of the line n (default 1).
\e[nE Cursor Next Line
\e[nF Cursor Previous Line
Cursor position
\e[nG Moves the cursor to column n.
\e[n;mH Moves the cursor to row n, column m.
\e[n;mf The same as above.
Erasing
\e[nJ Clears part of the screen. If n is 0 (or missing), clear from
cursor to end of screen. If n is 1, clear from cursor to
beginning of the screen. If n is 2, clear entire screen.
\e[nK Erases part of the line. If n is zero (or missing), clear from
cursor to the end of the line. If n is one, clear from cursor
to beginning of the line. If n is two, clear entire line.
Cursor position does not change.
Colorizing
\e[n1[;n2;...]m, where n's are as follows:
0 All attributes off
1 Increase intensity
2 Faint (decreased intensity)
3 Italic (not widely supported)
4 Underline
5 Slow blink
6 Rapid blink
7 Reverse (invert the foreground and background colors)
8-29 Rarely supported
30-37 Set foreground color (30+x, where x from the tables below)
38 Set foreground color (Next arguments are 5;n or 2;r;g;b)
39 Default foreground text color
40-47 Set background color (40+x)
48 Set foreground color (Next arguments are 5;n or 2;r;g;b)
49 Default background color
50-74 Rarely supported
90-97 Set foreground color, high intensity (90+x)
100-107 Set background color, high intensity (100+x)
ANSI colors (default usage)
Intensity 0 1 2 3 4 5 6 7
Normal Black Red Green Yellow Blue Magenta Cyan White
Bright Black Red Green Yellow Blue Magenta Cyan White
References
http://en.wikipedia.org/wiki/ANSI_escape_code
http://misc.flogisoft.com/bash/tip_colors_and_formatting
http://stackoverflow.com/a/24273024/3627676
http://www.robvanderwoude.com/ansi.php#AnsiArt
]]></description>
<example><![CDATA[
Examples:
- Print data from pipe:
echo \e[107m \e[0m\n\e[104m \e[0m\n\e[101m \e[0m | ansi
- Prepare data in the file and print:
del example.txt
echo \e[107m \e[0m>>example.txt
echo \e[104m \e[0m>>example.txt
echo \e[101m \e[0m>>example.txt
ansi < example.txt
]]></example>
<named
name="no-eol"
helpstring="Skip explicit end of line (skip explicit CRLF)"
type="simple"
required="false"
/>
<named
name="no-space"
helpstring="Skip the last trailing space printed by echo in DOS sessions"
type="simple"
required="false"
/>
<named
name="safe"
helpstring="Reset all color attributes to defaults at the end of execution"
type="simple"
required="false"
/>
</runtime>
<!-- <script language="javascript" src="./ansi.parse.js"></script> -->
<script language="javascript"><![CDATA[
function ansi_parse(text, options) {
options = options || {};
if ( options.safe ) {
text += '\\e[0m';
}
var chars = {
'a': String.fromCharCode(7),
'b': '\b',
'e': String.fromCharCode(27),
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'v': '\v',
'\\': '\\'
};
var re_src = [
'(?:\\\\(' + '[abefnrtv\\\\]' + '))' // Escaped chars above
, '|'
, '(?:\\\\(' + '0[0-7]{1,3}' + '))' // ASCII code (oct)
, '|'
, '(?:\\\\(' + 'x[0-9a-fA-F]{1,2}' + '))' // ASCII code (hex)
, '|'
, '(' + '\\^\\[' + ')' // ^[ stands for <ESC>
].join('');
if ( options.no_eol && options.no_space ) {
re_src += '|[ ]\\r?\\n';
} else if ( options.no_eol ) {
re_src += '|\\r?\\n';
} else if ( options.no_space ) {
re_src += '|[ ](?=\\r?\\n)';
}
var re = new RegExp(re_src, 'g');
return text.replace(re, function($0, $1, $2, $3, $4) {
return $1 ? chars[$1] :
$2 ? String.fromCharCode(parseInt($2)) :
$3 ? String.fromCharCode(parseInt('0' + $3)) :
$4 ? chars.e : '';
});
}
]]></script>
<!-- <script language="javascript" src="./ansi.main.js"></script> -->
<script language="javascript"><![CDATA[
var opts = WScript.Arguments.Named;
var text = WScript.StdIn.ReadAll();
var text = ansi_parse(text, {
no_eol: opts.Exists('no-eol'),
no_space: opts.Exists('no-space'),
safe: opts.Exists('safe')
});
WScript.StdOut.Write(text);
]]></script>
</job>
</package>