Created
October 29, 2018 05:31
-
-
Save CapsAdmin/e63da076fa851dffbe83ed3bfbabfbc3 to your computer and use it in GitHub Desktop.
lua repl using ffi, windows isn't finished/working
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local ffi = require("ffi") | |
local start | |
local stop | |
local read | |
if jit.os == "Linux" then | |
ffi.cdef([[ | |
struct termios | |
{ | |
unsigned int c_iflag; /* input mode flags */ | |
unsigned int c_oflag; /* output mode flags */ | |
unsigned int c_cflag; /* control mode flags */ | |
unsigned int c_lflag; /* local mode flags */ | |
unsigned char c_line; /* line discipline */ | |
unsigned char c_cc[32]; /* control characters */ | |
unsigned int c_ispeed; /* input speed */ | |
unsigned int c_ospeed; /* output speed */ | |
}; | |
int tcgetattr(int __fd, struct termios *__termios_p); | |
int tcsetattr(int __fd, int __optional_actions, const struct termios *__termios_p); | |
int usleep(uint32_t); | |
]]) | |
local ISIG = 0000001 | |
local ICANON = 0000002 | |
local ECHO = 0000010 | |
local VMIN = 6 | |
local VTIME = 5 | |
local TCSANOW = 0 | |
local stdin = 0 | |
local old_attributes | |
start = function() | |
if not old_attributes then | |
old_attributes = ffi.new("struct termios[1]") | |
ffi.C.tcgetattr(stdin, old_attributes) | |
end | |
local attr = ffi.new("struct termios[1]") | |
ffi.C.tcgetattr(stdin, attr) | |
attr[0].c_lflag = bit.band(attr[0].c_lflag, bit.bnot(bit.bor(ICANON, ECHO, ISIG))) | |
attr[0].c_cc[VMIN] = 0 | |
attr[0].c_cc[VTIME] = 0 | |
ffi.C.tcsetattr(stdin, TCSANOW, attr) | |
end | |
read = function() | |
return io.read() | |
end | |
stop = function() | |
ffi.C.tcsetattr(stdin, TCSANOW, old_attributes) | |
old_attributes = nil | |
end | |
end | |
if jit.os == "Windows" then | |
ffi.cdef([[ | |
struct COORD { | |
short X; | |
short Y; | |
}; | |
struct KEY_EVENT_RECORD { | |
int bKeyDown; | |
unsigned short wRepeatCount; | |
unsigned short wVirtualKeyCode; | |
unsigned short wVirtualScanCode; | |
union { | |
wchar_t UnicodeChar; | |
char AsciiChar; | |
} uChar; | |
unsigned long dwControlKeyState; | |
}; | |
struct MOUSE_EVENT_RECORD { | |
struct COORD dwMousePosition; | |
unsigned long dwButtonState; | |
unsigned long dwControlKeyState; | |
unsigned long dwEventFlags; | |
}; | |
struct WINDOW_BUFFER_SIZE_RECORD { | |
struct COORD dwSize; | |
}; | |
struct MENU_EVENT_RECORD { | |
unsigned int dwCommandId; | |
}; | |
struct FOCUS_EVENT_RECORD { | |
int bSetFocus; | |
}; | |
struct INPUT_RECORD { | |
unsigned short EventType; | |
union { | |
struct KEY_EVENT_RECORD KeyEvent; | |
struct MOUSE_EVENT_RECORD MouseEvent; | |
struct WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; | |
struct MENU_EVENT_RECORD MenuEvent; | |
struct FOCUS_EVENT_RECORD FocusEvent; | |
} Event; | |
}; | |
int PeekConsoleInputA( | |
void* hConsoleInput, | |
struct INPUT_RECORD* lpBuffer, | |
unsigned long nLength, | |
unsigned long * lpNumberOfEventsRead | |
); | |
int ReadConsoleInputA( | |
void* hConsoleInput, | |
struct INPUT_RECORD* lpBuffer, | |
unsigned long nLength, | |
unsigned long * lpNumberOfEventsRead | |
); | |
void* GetStdHandle(unsigned long nStdHandle); | |
int PeekNamedPipe( | |
void* hNamedPipe, | |
void* lpBuffer, | |
unsigned long nBufferSize, | |
unsigned long* lpBytesRead, | |
unsigned long* lpTotalBytesAvail, | |
unsigned long* lpBytesLeftThisMessage | |
); | |
]]) | |
local STD_INPUT_HANDLE = -10 | |
local stdin = ffi.C.GetStdHandle(STD_INPUT_HANDLE) | |
if true then | |
read = function() | |
local size = ffi.new("unsigned long[1]") | |
ffi.C.PeekNamedPipe(stdin, nil,nil,nil, size, nil) | |
if size[0] > 0 then | |
return io.read() | |
end | |
end | |
else | |
local rec = ffi.new("struct INPUT_RECORD[1]") | |
local events = ffi.new("unsigned long[1]") | |
read = function() | |
ffi.C.PeekConsoleInputA(stdin, rec, ffi.sizeof(rec), events) | |
if events[0] > 0 then | |
for i = 1, tonumber(events[0]) do | |
ffi.C.ReadConsoleInputA(stdin, rec, ffi.sizeof(rec), events) | |
local info = rec[0] | |
if info.EventType == 1 and info.Event.KeyEvent.bKeyDown then | |
return string.char(info.Event.KeyEvent.uChar.UnicodeChar), info.Event.KeyEvent | |
end | |
end | |
end | |
end | |
end | |
start = function() end | |
stop = function() end | |
end | |
local time = os.clock() + math.random() + 1 | |
local buffer = "" | |
local pos = 0 | |
start() | |
local function get_caret_pos() | |
io.write("\x1b[6n") | |
while true do | |
local str = read() | |
if str and str:sub(1, 2) == "\27[" then | |
y,x = str:match("\27%[(%d+);(%d+)R") | |
break | |
end | |
end | |
return tonumber(x), tonumber(y) | |
end | |
local function set_caret_pos(x, y) | |
io.write("\27[",y,";",x,"f") | |
end | |
local function move_caret(ox, oy) | |
local x,y = get_caret_pos() | |
set_caret_pos(x + ox, y + oy) | |
end | |
local function push_caret() | |
io.write("\27[s") | |
end | |
local function pop_caret() | |
io.write("\27[u") | |
end | |
local function get_size() | |
push_caret() | |
set_caret_pos(99999999,99999999) | |
local w,h = get_caret_pos() | |
pop_caret() | |
return w,h | |
end | |
local function write_string(x, y, str) | |
io.write("\27[s ", "\27[", y, ";", x, "H", "\27[K", str, "\27[u") | |
end | |
local function erase_line(y) | |
push_caret() | |
set_caret_pos(0, y) | |
io.write("\27[K") | |
pop_caret() | |
end | |
local function set_fg_color(r,g,b) | |
r = math.floor(r * 255) | |
g = math.floor(g * 255) | |
b = math.floor(b * 255) | |
io.write("\27[38;2;", r, ";", g, ";", b, "m") | |
end | |
local function set_bg_color(r,g,b) | |
r = math.floor(r * 255) | |
g = math.floor(g * 255) | |
b = math.floor(b * 255) | |
io.write("\27[48;2;", r, ";", g, ";", b, "m") | |
end | |
local function find_next_word(buffer, x, dir) | |
local left = dir == "left" and buffer:sub(0, x-1):reverse() or buffer:sub(x+1, -1) | |
if left:find("^%s", 0) then | |
return left:find("%S") | |
elseif left:find("^%p", 0) then | |
return left:find("%P", 0) | |
end | |
return left:find("%s", 0) or left:find("%p", 0) or #left + 1 | |
end | |
local x, y = get_caret_pos() | |
while true do | |
ffi.C.usleep(500) | |
-- buffer = ("="):rep((math.sin(os.clock() * 10) * 0.5 + 0.5) * 50) | |
write_string(0, y, buffer) | |
local str = read() | |
if str then | |
local w, h = get_size() | |
local x, y = get_caret_pos() | |
if str == "" then -- newline/enter? | |
erase_line(y) | |
set_caret_pos(0, y + 1) | |
io.write("> ", buffer, "\n") | |
local func, err = loadstring(buffer) | |
if func then | |
local func, res = pcall(func) | |
if not func then | |
set_fg_color(1,0,0) | |
io.write(res, "\n") | |
set_fg_color(1,1,1) | |
end | |
else | |
set_fg_color(1,0,0) | |
io.write(err, "\n") | |
set_fg_color(1,1,1) | |
end | |
buffer = "" | |
set_caret_pos(0, y + 1) | |
elseif str:byte() >= 32 and str:byte() < 127 then -- asci chars | |
buffer = buffer:sub(0, x-1) .. str .. buffer:sub(x+#str-1, -1) | |
move_caret(#str, 0) | |
elseif str:sub(1,2) == "\27[" then | |
local seq = str:sub(3, #str) | |
if seq == "3~" then -- delete | |
buffer = buffer:sub(0, x-1) .. buffer:sub(x+1, -1) | |
elseif seq == "D" then -- left | |
move_caret(-1, 0) | |
elseif seq == "C" then -- right | |
move_caret(1, 0) | |
elseif seq == "H" then -- home | |
set_caret_pos(1, y) | |
elseif seq == "F" then -- end | |
set_caret_pos(#buffer + 1, y) | |
elseif seq == "1;5C" then -- ctrl right | |
local offset = find_next_word(buffer, x, "right") | |
if offset then | |
move_caret(offset + 1, 0) | |
end | |
elseif seq == "1;5D" then -- ctrl left | |
local offset = find_next_word(buffer, x, "left") | |
if offset then | |
move_caret(-offset + 1, 0) | |
end | |
else | |
print("ansi escape sequence: " .. seq) | |
end | |
else | |
if #str == 1 then | |
local byte = str:byte() | |
if byte == 3 then -- ctrl c | |
io.write("\nquit\n") | |
break | |
elseif byte == 127 then -- backspace | |
buffer = buffer:sub(0, math.max(x - 1 - 1, 0)) .. buffer:sub(x, -1) | |
move_caret(-1, 0) | |
elseif byte == 23 then -- ctrl backspace | |
local offset = find_next_word(buffer, x, "left") | |
if offset then | |
buffer = buffer:sub(0, x - offset) .. buffer:sub(x, -1) | |
end | |
else | |
print("byte: " .. byte) | |
end | |
elseif str:byte() < 127 then | |
if str == "\27\68" then -- ctrl delete | |
local offset = find_next_word(buffer, x, "right") | |
if offset then | |
buffer = buffer:sub(0, x - 1) .. buffer:sub(x + offset, -1) | |
end | |
else | |
print("char sequence: " .. table.concat({str:byte(1, #str)}, ", ") .. " (" .. #str .. ")") | |
end | |
else -- unicode ? | |
--buffer = buffer:sub(0, x-1) .. str .. buffer:sub(x+#str-1, -1) | |
--move_caret(#str, 0) | |
end | |
end | |
local x, y = get_caret_pos() | |
x = math.min(x, #buffer + 1) | |
set_caret_pos(x, y) | |
end | |
if time < os.clock() then | |
time = os.clock() + math.random() + 1 | |
-- print("some text!") | |
end | |
end | |
stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment