在windows终端中启用ANSI序列
我偶然发现了一个有趣的问题 在Windows中:在windows终端中启用ANSI序列,windows,terminal,lua,ansi,Windows,Terminal,Lua,Ansi,我偶然发现了一个有趣的问题 在Windows中: C:\> lua > print("\x1b[95mMagenta\x1b[0m") -[95mMagenta-[0m 但是如果我运行os.execute(),即使使用空命令, 在此之前,它按预期工作: C:\> lua > os.system(""); print("\x1b[95mMagenta\x1b[0m") Magenta (最后一行用洋红色打印
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
来设置特定的启用虚拟终端处理模式
当您在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')
是的,这听起来很合理;你的意思是它改变了当前终端的状态,甚至在处理完成后,终端的状态也发生了改变?同时,当cmd.exe首先在此终端上启动时,不会发生这种情况?终端的模式不是终端窗口的属性。它是控制台句柄的属性。父进程(cmd.exe
)和子进程(lua.exe
)通过不同的控制台句柄访问同一终端窗口。当os.execute
创建cmd.exe
子进程时,控制台句柄由子进程继承,这是默认行为。但是当cmd.exe
创建lua.exe
子进程时,控制台句柄不会被继承,故意将子进程彼此隔离(您的程序不依赖于在同一控制台中运行的上一个程序的名称)。是的,似乎正是这样,但它如何知道在什么情况下必须创建新的控制台句柄,以及必须继承什么,目前还不清楚。或者cmd.exe总是为每个子进程创建新的控制台句柄?cmd.exe
在创建子进程时故意禁止控制台句柄继承。这是通过WinAPI函数CreateProcessW()