在 windows 终端中启用 ANSI 序列

Enable ANSI sequences in windows terminal

我偶然发现了一个有趣的问题 在 Windows:


C:\> lua
> print("\x1b[95mMagenta\x1b[0m")
-[95mMagenta-[0m

但是如果我 运行 os.execute() 即使是一个空命令, 在它之前,它按预期工作:

C:\> lua
> os.system(""); print("\x1b[95mMagenta\x1b[0m")
Magenta

(最后一行用洋红色打印)

为什么会这样,我怎样才能使 ANSI 代码工作 不调用 os.execute()?

要使 ANSI 代码在控制台中工作,您应该通过调用 WinAPI 函数 SetConsoleMode.

来设置特定的 ENABLE_VIRTUAL_TERMINAL_PROCESSING 模式

当您在 Lua 中调用 os.execute() 时,Lua 调用 C 运行时函数 system(),它创建 cmd.exe 进程,初始化所有的铃声和口哨声。
但是 Lua 当然不知道 Windows 控制台功能;它只适用于具有默认设置的控制台。


更新:
这是一个关于如何从 LuaJIT 脚本打开 ANSI 转义序列的示例:

local ffi = require"ffi"
ffi.cdef[[
typedef int BOOL;
static const int INVALID_HANDLE_VALUE               = -1;
static const int STD_OUTPUT_HANDLE                  = -11;
static const int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;
intptr_t GetStdHandle(int nStdHandle);
BOOL GetConsoleMode(intptr_t hConsoleHandle, int* lpMode);
BOOL SetConsoleMode(intptr_t hConsoleHandle, int dwMode);
]]
local console_handle = ffi.C.GetStdHandle(ffi.C.STD_OUTPUT_HANDLE)
assert(console_handle ~= ffi.C.INVALID_HANDLE_VALUE)
local prev_console_mode = ffi.new"int[1]"
assert(ffi.C.GetConsoleMode(console_handle, prev_console_mode) ~= 0, "This script must be run from a console application")
local function turn_VT(on_off)
   assert(ffi.C.SetConsoleMode(console_handle, bit.bor(prev_console_mode[0], on_off and ffi.C.ENABLE_VIRTUAL_TERMINAL_PROCESSING or 0)) ~= 0)
end

print('\x1b[95mMagenta\x1b[m')
turn_VT(true)
print('\x1b[95mMagenta\x1b[m')
turn_VT(false)
print('\x1b[95mMagenta\x1b[m')