mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-15 18:30:27 -04:00
ctrl+d for soft and ctrl+c for hard abort in term.read, resulting in 'nil' being read, signalling an eof and thus allowing the lua program to be quit that way; removed the exit() function from the lua function; added shell.parse
for rudimentary argument parsing (anything starting with -
is treated as an option or a list of option (each option name must be exactly one char); added key state tracking and keyboard library
This commit is contained in:
parent
e9f2fac861
commit
a8288b2623
@ -135,6 +135,6 @@ for k, v in pairs(driver.keyboard.keys) do
|
|||||||
driver.keyboard.keys[v] = k
|
driver.keyboard.keys[v] = k
|
||||||
end
|
end
|
||||||
|
|
||||||
function driver.keyboard.keys.isControl(char)
|
function driver.keyboard.isControl(char)
|
||||||
return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
|
return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
|
||||||
end
|
end
|
||||||
|
@ -47,11 +47,8 @@ local sandbox = {
|
|||||||
|
|
||||||
coroutine = {
|
coroutine = {
|
||||||
create = coroutine.create,
|
create = coroutine.create,
|
||||||
resume = coroutine.resume,
|
|
||||||
running = coroutine.running,
|
running = coroutine.running,
|
||||||
status = coroutine.status,
|
status = coroutine.status
|
||||||
wrap = coroutine.wrap,
|
|
||||||
yield = coroutine.yield
|
|
||||||
},
|
},
|
||||||
|
|
||||||
math = {
|
math = {
|
||||||
@ -136,8 +133,9 @@ local sandbox = {
|
|||||||
}
|
}
|
||||||
sandbox._G = sandbox
|
sandbox._G = sandbox
|
||||||
|
|
||||||
function sandbox.load(code, source, env)
|
function sandbox.load(ld, source, mode, env)
|
||||||
return load(code, source, "t", env or sandbox)
|
assert((mode or "t") == "t", "unsupported mode")
|
||||||
|
return load(ld, source, "t", env or sandbox)
|
||||||
end
|
end
|
||||||
|
|
||||||
function sandbox.checkArg(n, have, ...)
|
function sandbox.checkArg(n, have, ...)
|
||||||
@ -151,7 +149,7 @@ function sandbox.checkArg(n, have, ...)
|
|||||||
end
|
end
|
||||||
if not check(...) then
|
if not check(...) then
|
||||||
local msg = string.format("bad argument #%d (%s expected, got %s)", n, table.concat({...}, " or "), have)
|
local msg = string.format("bad argument #%d (%s expected, got %s)", n, table.concat({...}, " or "), have)
|
||||||
--error(debug.traceback(msg, 2), 2)
|
--error(debug.traceback(msg, 2), 0)
|
||||||
error(msg, 2)
|
error(msg, 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -170,6 +168,100 @@ local function checkDeadline()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sandbox.coroutine.resume(co, ...)
|
||||||
|
local args = table.pack(...)
|
||||||
|
while true do
|
||||||
|
if not debug.gethook(co) then -- don't reset counter
|
||||||
|
debug.sethook(co, checkDeadline, "", 10000)
|
||||||
|
end
|
||||||
|
local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n)))
|
||||||
|
checkDeadline()
|
||||||
|
if result[1] then
|
||||||
|
local isSystemYield = coroutine.status(co) ~= "dead" and result[2] ~= nil
|
||||||
|
if isSystemYield then
|
||||||
|
args = table.pack(coroutine.yield(result[2]))
|
||||||
|
else
|
||||||
|
return true, table.unpack(result, 3, result.n)
|
||||||
|
end
|
||||||
|
else -- error: result = (bool, string)
|
||||||
|
return table.unpack(result, 1, result.n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.coroutine.yield(...)
|
||||||
|
return coroutine.yield(nil, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.coroutine.wrap(f) -- for sandbox's coroutine.resume
|
||||||
|
local co = sandbox.coroutine.create(f)
|
||||||
|
return function(...)
|
||||||
|
local result = table.pack(sandbox.coroutine.resume(co, ...))
|
||||||
|
if result[1] then
|
||||||
|
return table.unpack(result, 2, result.n)
|
||||||
|
else
|
||||||
|
error(result[2], 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.pcall(...)
|
||||||
|
local result = table.pack(pcall(...))
|
||||||
|
checkDeadline()
|
||||||
|
return table.unpack(result, 1, result.n)
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.xpcall(...)
|
||||||
|
local result = table.pack(xpcall(...))
|
||||||
|
checkDeadline()
|
||||||
|
return table.unpack(result, 1, result.n)
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function sandbox.os.shutdown(reboot)
|
||||||
|
coroutine.yield(reboot ~= nil and reboot ~= false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function sandbox.os.signal(name, timeout)
|
||||||
|
local waitUntil = os.uptime() + (type(timeout) == "number" and timeout or math.huge)
|
||||||
|
repeat
|
||||||
|
local signal = table.pack(coroutine.yield(waitUntil - os.uptime()))
|
||||||
|
if signal.n > 0 and (name == signal[1] or name == nil) then
|
||||||
|
return table.unpack(signal, 1, signal.n)
|
||||||
|
end
|
||||||
|
until os.uptime() >= waitUntil
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sandbox.driver = {}
|
||||||
|
|
||||||
|
function sandbox.driver.componentType(address)
|
||||||
|
return nodeName(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local env = setmetatable({ send = sendToAddress },
|
||||||
|
{ __index = sandbox, __newindex = sandbox })
|
||||||
|
for name, code in pairs(drivers()) do
|
||||||
|
local driver, reason = load(code, "=" .. name, "t", env)
|
||||||
|
if not driver then
|
||||||
|
print("Failed loading driver '" .. name .. "': " .. reason)
|
||||||
|
else
|
||||||
|
local result, reason = xpcall(driver, function(msg)
|
||||||
|
return debug.traceback(msg, 2)
|
||||||
|
end)
|
||||||
|
if not result then
|
||||||
|
print("Failed initializing driver '" .. name .. "': " ..
|
||||||
|
(reason or "unknown error"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
local function main(args)
|
local function main(args)
|
||||||
local function bootstrap()
|
local function bootstrap()
|
||||||
local fs = sandbox.driver.filesystem
|
local fs = sandbox.driver.filesystem
|
||||||
@ -235,88 +327,6 @@ local function main(args)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function sandbox.coroutine.resume(co, ...)
|
|
||||||
local args = table.pack(...)
|
|
||||||
while true do
|
|
||||||
if not debug.gethook(co) then -- don't reset counter
|
|
||||||
debug.sethook(co, checkDeadline, "", 10000)
|
|
||||||
end
|
|
||||||
local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n)))
|
|
||||||
checkDeadline()
|
|
||||||
if result[1] then
|
|
||||||
local isSystemYield = coroutine.status(co) ~= "dead" and result[2] ~= nil
|
|
||||||
if isSystemYield then
|
|
||||||
args = table.pack(coroutine.yield(result[2]))
|
|
||||||
else
|
|
||||||
return true, table.unpack(result, 3, result.n)
|
|
||||||
end
|
|
||||||
else -- error: result = (bool, string)
|
|
||||||
return table.unpack(result, 1, result.n)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function sandbox.coroutine.yield(...)
|
|
||||||
return coroutine.yield(nil, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function sandbox.pcall(...)
|
|
||||||
local result = table.pack(pcall(...))
|
|
||||||
checkDeadline()
|
|
||||||
return table.unpack(result, 1, result.n)
|
|
||||||
end
|
|
||||||
|
|
||||||
function sandbox.xpcall(...)
|
|
||||||
local result = table.pack(xpcall(...))
|
|
||||||
checkDeadline()
|
|
||||||
return table.unpack(result, 1, result.n)
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function sandbox.os.shutdown(reboot)
|
|
||||||
coroutine.yield(reboot ~= nil and reboot ~= false)
|
|
||||||
end
|
|
||||||
|
|
||||||
function sandbox.os.signal(name, timeout)
|
|
||||||
local waitUntil = os.uptime() + (type(timeout) == "number" and timeout or math.huge)
|
|
||||||
repeat
|
|
||||||
local signal = table.pack(coroutine.yield(waitUntil - os.uptime()))
|
|
||||||
if signal.n > 0 and (name == signal[1] or name == nil) then
|
|
||||||
return table.unpack(signal, 1, signal.n)
|
|
||||||
end
|
|
||||||
until os.uptime() >= waitUntil
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
sandbox.driver = {}
|
|
||||||
|
|
||||||
function sandbox.driver.componentType(address)
|
|
||||||
return nodeName(address)
|
|
||||||
end
|
|
||||||
|
|
||||||
do
|
|
||||||
local env = setmetatable({ send = sendToAddress },
|
|
||||||
{ __index = sandbox, __newindex = sandbox })
|
|
||||||
for name, code in pairs(drivers()) do
|
|
||||||
local driver, reason = load(code, "=" .. name, "t", env)
|
|
||||||
if not driver then
|
|
||||||
print("Failed loading driver '" .. name .. "': " .. reason)
|
|
||||||
else
|
|
||||||
local result, reason = xpcall(driver, function(msg)
|
|
||||||
return debug.traceback(msg, 2)
|
|
||||||
end)
|
|
||||||
if not result then
|
|
||||||
print("Failed initializing driver '" .. name .. "': " ..
|
|
||||||
(reason or "unknown error"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- JNLua converts the coroutine to a string immediately, so we can't get the
|
-- JNLua converts the coroutine to a string immediately, so we can't get the
|
||||||
-- traceback later. Because of that we have to do the error handling here.
|
-- traceback later. Because of that we have to do the error handling here.
|
||||||
-- Also, yield once to allow initializing up to here to get a memory baseline.
|
-- Also, yield once to allow initializing up to here to get a memory baseline.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
|
|
||||||
if args.n == 0 then
|
if args.n == 0 then
|
||||||
for name, value in shell.aliases() do
|
for name, value in shell.aliases() do
|
||||||
print(name, value)
|
print(name, value)
|
||||||
end
|
end
|
||||||
elseif args.n == 1 then
|
elseif #args == 1 then
|
||||||
local value = shell.alias(args[1])
|
local value = shell.alias(args[1])
|
||||||
if value then
|
if value then
|
||||||
print(value)
|
print(value)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n == 0 then
|
if #args == 0 then
|
||||||
print("Usage: cat <filename1> [<filename2> [...]]")
|
print("Usage: cat <filename1> [<filename2> [...]]")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1, args.n do
|
for i = 1, #args do
|
||||||
local file, reason = io.open(shell.resolve(args[i]), "r")
|
local file, reason = io.open(shell.resolve(args[i]), "r")
|
||||||
if not file then
|
if not file then
|
||||||
print(reason)
|
print(reason)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n == 0 then
|
if #args == 0 then
|
||||||
print("Usage: cd <dirname>")
|
print("Usage: cd <dirname>")
|
||||||
else
|
else
|
||||||
local result, reason = shell.cwd(shell.resolve(args[1]))
|
local result, reason = shell.cwd(shell.resolve(args[1]))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n < 2 then
|
if #args < 2 then
|
||||||
print("Usage: cp <from> <to>")
|
print("Usage: cp <from> <to>")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1,33 +1,29 @@
|
|||||||
local args = table.pack(...)
|
local dirs, options = shell.parse(...)
|
||||||
local options = {}
|
|
||||||
local dirs = {}
|
|
||||||
for i = 1, args.n do
|
|
||||||
if args[i]:usub(1, 1) == "-" then
|
|
||||||
if args[i]:ulen() > 1 then
|
|
||||||
options[args[i]:usub(2)] = true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.insert(dirs, args[i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #dirs == 0 then
|
if #dirs == 0 then
|
||||||
table.insert(dirs, ".")
|
table.insert(dirs, ".")
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1, #dirs do
|
for i = 1, #dirs do
|
||||||
local path = shell.resolve(dirs[i])
|
local path = shell.resolve(dirs[i])
|
||||||
|
if #dirs > 1 then
|
||||||
|
if i > 1 then print() end
|
||||||
|
print("/" .. path .. ":")
|
||||||
|
end
|
||||||
local list, reason = fs.dir(path)
|
local list, reason = fs.dir(path)
|
||||||
if not list then
|
if not list then
|
||||||
print(reason)
|
print(reason)
|
||||||
else
|
else
|
||||||
for f in list do
|
for f in list do
|
||||||
if options.l then
|
if options.a or f:usub(1, 1) ~= "." then
|
||||||
print(f, fs.size(fs.concat(path, f)))
|
if options.l then
|
||||||
else
|
print(f, fs.size(fs.concat(path, f)))
|
||||||
io.write(f .. "\t")
|
else
|
||||||
|
io.write(f .. "\t")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
print()
|
if not options.l then
|
||||||
|
print()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,14 +1,17 @@
|
|||||||
print("Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio")
|
print("Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio")
|
||||||
local running = true
|
local history = {}
|
||||||
local env = setmetatable({exit=function() running = false end}, {__index=_ENV})
|
local env = setmetatable({}, {__index=_ENV})
|
||||||
while running and term.isAvailable() do
|
while term.isAvailable() do
|
||||||
io.write("lua> ")
|
term.write("lua> ")
|
||||||
local command = io.read()
|
local command = term.read(history)
|
||||||
if not command then
|
if command == nil then -- eof
|
||||||
return -- eof
|
return
|
||||||
end
|
end
|
||||||
local statement, result = load(command, "=stdin", env)
|
while #history > 10 do
|
||||||
local expression = load("return " .. command, "=stdin", env)
|
table.remove(history, 1)
|
||||||
|
end
|
||||||
|
local statement, result = load(command, "=stdin", "t", env)
|
||||||
|
local expression = load("return " .. command, "=stdin", "t", env)
|
||||||
local code = expression or statement
|
local code = expression or statement
|
||||||
if code then
|
if code then
|
||||||
local result = table.pack(pcall(code))
|
local result = table.pack(pcall(code))
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n == 0 then
|
if #args == 0 then
|
||||||
print("Usage: mkdir <dirname1> [<dirname2> [...]]")
|
print("Usage: mkdir <dirname1> [<dirname2> [...]]")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1, args.n do
|
for i = 1, #args do
|
||||||
local path = shell.resolve(args[i])
|
local path = shell.resolve(args[i])
|
||||||
local result, reason = fs.makeDirectory(path)
|
local result, reason = fs.makeDirectory(path)
|
||||||
if not result then
|
if not result then
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n < 2 then
|
if #args < 2 then
|
||||||
print("Usage: mv <from> <to>")
|
print("Usage: mv <from> <to>")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n == 0 then
|
if #args == 0 then
|
||||||
print("Usage: rm <filename1> [<filename2> [...]]")
|
print("Usage: rm <filename1> [<filename2> [...]]")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1, args.n do
|
for i = 1, #args do
|
||||||
local path = shell.resolve(args[i])
|
local path = shell.resolve(args[i])
|
||||||
if not fs.remove(path) then
|
if not fs.remove(path) then
|
||||||
print(path .. ": no such file, or permission denied")
|
print(path .. ": no such file, or permission denied")
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
local args = table.pack(...)
|
||||||
|
if args.n > 0 then
|
||||||
|
os.execute(table.concat(args, " ", 1, args.n))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local function trim(s) -- from http://lua-users.org/wiki/StringTrim
|
local function trim(s) -- from http://lua-users.org/wiki/StringTrim
|
||||||
local from = s:match"^%s*()"
|
local from = s:match"^%s*()"
|
||||||
return from > #s and "" or s:match(".*%S", from)
|
return from > #s and "" or s:match(".*%S", from)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n < 1 then
|
if #args < 1 then
|
||||||
print("Usage: unalias <name>")
|
print("Usage: unalias <name>")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
local args = table.pack(...)
|
local args = shell.parse(...)
|
||||||
if args.n == 0 then
|
if #args == 0 then
|
||||||
print("Usage: which <program>")
|
print("Usage: which <program>")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local result, reason = shell.which(args[1])
|
local result, reason = shell.which(args[1])
|
||||||
if result then
|
if result then
|
||||||
print(result)
|
print(result)
|
||||||
|
@ -6,7 +6,7 @@ function dofile(filename)
|
|||||||
return program()
|
return program()
|
||||||
end
|
end
|
||||||
|
|
||||||
function loadfile(filename, env)
|
function loadfile(filename, mode, env)
|
||||||
local file, reason = io.open(filename)
|
local file, reason = io.open(filename)
|
||||||
if not file then
|
if not file then
|
||||||
return nil, reason
|
return nil, reason
|
||||||
@ -16,7 +16,7 @@ function loadfile(filename, env)
|
|||||||
if not source then
|
if not source then
|
||||||
return nil, reason
|
return nil, reason
|
||||||
end
|
end
|
||||||
return load(source, "=" .. filename, env)
|
return load(source, "=" .. filename, mode, env)
|
||||||
end
|
end
|
||||||
|
|
||||||
function print(...)
|
function print(...)
|
||||||
|
@ -20,6 +20,14 @@ function component.list(filter)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function component.isPrimary(address)
|
||||||
|
local componentType = component.type(address)
|
||||||
|
if componentType then
|
||||||
|
return primaries[componentType] == address
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
function component.primary(componentType, ...)
|
function component.primary(componentType, ...)
|
||||||
checkArg(1, componentType, "string")
|
checkArg(1, componentType, "string")
|
||||||
local args = table.pack(...)
|
local args = table.pack(...)
|
||||||
|
@ -95,13 +95,13 @@ function event.cancel(timerId)
|
|||||||
timers[timerId] = nil
|
timers[timerId] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function event.interval(timeout, callback)
|
function event.interval(frequency, callback)
|
||||||
local interval = {}
|
local interval = {}
|
||||||
local function onTimer()
|
local function onTimer()
|
||||||
interval.id = event.timer(timeout, onTimer)
|
interval.id = event.timer(frequency, onTimer)
|
||||||
callback()
|
callback()
|
||||||
end
|
end
|
||||||
interval.id = event.timer(timeout, onTimer)
|
interval.id = event.timer(frequency, onTimer)
|
||||||
return interval
|
return interval
|
||||||
end
|
end
|
||||||
|
|
||||||
|
52
assets/opencomputers/lua/rom/lib/keyboard.lua
Normal file
52
assets/opencomputers/lua/rom/lib/keyboard.lua
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
keyboard = setmetatable({}, {__index = driver.keyboard})
|
||||||
|
|
||||||
|
local pressedChars = {}
|
||||||
|
local pressedCodes = {}
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function keyboard.isKeyDown(charOrCode)
|
||||||
|
checkArg(1, charOrCode, "string", "number")
|
||||||
|
if type(charOrCode) == "string" then
|
||||||
|
return pressedChars[charOrCode]
|
||||||
|
elseif type(charOrCode) == "number" then
|
||||||
|
return pressedCodes[charOrCode]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function keyboard.isControlDown()
|
||||||
|
return (pressedCodes[keyboard.keys.lcontrol] or pressedCodes[keyboard.keys.rcontrol]) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function keyboard.isShiftDown()
|
||||||
|
return (pressedCodes[keyboard.keys.lshift] or pressedCodes[keyboard.keys.rshift]) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local function onKeyDown(_, address, char, code)
|
||||||
|
if component.isPrimary(address) then
|
||||||
|
pressedChars[char] = true
|
||||||
|
pressedCodes[code] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onKeyUp(_, address, char, code)
|
||||||
|
if component.isPrimary(address) then
|
||||||
|
pressedChars[char] = nil
|
||||||
|
pressedCodes[code] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onComponentUnavailable(_, componentType)
|
||||||
|
if componentType == "keyboard" then
|
||||||
|
pressedChars = {}
|
||||||
|
pressedCodes = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function()
|
||||||
|
event.listen("key_down", onKeyDown)
|
||||||
|
event.listen("key_up", onKeyUp)
|
||||||
|
event.listen("component_unavailable", onComponentUnavailable)
|
||||||
|
end
|
@ -25,6 +25,8 @@ os.remove = driver.filesystem.remove
|
|||||||
|
|
||||||
os.rename = driver.filesystem.rename
|
os.rename = driver.filesystem.rename
|
||||||
|
|
||||||
|
os.sleep = event.wait
|
||||||
|
|
||||||
function os.tmpname()
|
function os.tmpname()
|
||||||
if driver.filesystem.exists("tmp") then
|
if driver.filesystem.exists("tmp") then
|
||||||
for i = 1, 10 do
|
for i = 1, 10 do
|
||||||
|
@ -146,7 +146,7 @@ function shell.execute(program, ...)
|
|||||||
pevent = setmetatable(pevent, {__index = event, __metatable = {}})
|
pevent = setmetatable(pevent, {__index = event, __metatable = {}})
|
||||||
local env = setmetatable({event = pevent}, {__index = _ENV, __metatable = {}})
|
local env = setmetatable({event = pevent}, {__index = _ENV, __metatable = {}})
|
||||||
|
|
||||||
program, reason = loadfile(where, env)
|
program, reason = loadfile(where, "t", env)
|
||||||
if not program then
|
if not program then
|
||||||
return nil, reason
|
return nil, reason
|
||||||
end
|
end
|
||||||
@ -170,6 +170,23 @@ function shell.execute(program, ...)
|
|||||||
return table.unpack(result, 1, result.n)
|
return table.unpack(result, 1, result.n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function shell.parse(...)
|
||||||
|
local params = table.pack(...)
|
||||||
|
local args = {}
|
||||||
|
local options = {}
|
||||||
|
for i = 1, params.n do
|
||||||
|
local param = params[i]
|
||||||
|
if param:usub(1, 1) == "-" then
|
||||||
|
for j = 2, param:ulen() do
|
||||||
|
options[param:usub(j, j)] = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(args, param)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return args, options
|
||||||
|
end
|
||||||
|
|
||||||
function shell.resolve(path)
|
function shell.resolve(path)
|
||||||
if path:usub(1, 1) == "/" then
|
if path:usub(1, 1) == "/" then
|
||||||
return fs.canonical(path)
|
return fs.canonical(path)
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
local cursorX, cursorY = 1, 1
|
local cursorX, cursorY = 1, 1
|
||||||
local cursorBlink = nil
|
local cursorBlink = nil
|
||||||
|
|
||||||
local function toggleBlink()
|
|
||||||
cursorBlink.state = not cursorBlink.state
|
|
||||||
if term.isAvailable() then
|
|
||||||
local char = cursorBlink.state and cursorBlink.solid or cursorBlink.alt
|
|
||||||
gpu.set(cursorX, cursorY, char)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
term = {}
|
term = {}
|
||||||
@ -43,6 +35,13 @@ function term.cursor(col, row)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function term.cursorBlink(enabled)
|
function term.cursorBlink(enabled)
|
||||||
|
local function toggleBlink()
|
||||||
|
cursorBlink.state = not cursorBlink.state
|
||||||
|
if term.isAvailable() then
|
||||||
|
local char = cursorBlink.state and cursorBlink.solid or cursorBlink.alt
|
||||||
|
gpu.set(cursorX, cursorY, char)
|
||||||
|
end
|
||||||
|
end
|
||||||
local function start(alt)
|
local function start(alt)
|
||||||
if not cursorBlink then
|
if not cursorBlink then
|
||||||
cursorBlink = event.interval(0.5, toggleBlink)
|
cursorBlink = event.interval(0.5, toggleBlink)
|
||||||
@ -74,6 +73,8 @@ function term.cursorBlink(enabled)
|
|||||||
else
|
else
|
||||||
stop()
|
stop()
|
||||||
end
|
end
|
||||||
|
elseif enabled and cursorBlink then
|
||||||
|
toggleBlink()
|
||||||
end
|
end
|
||||||
return cursorBlink ~= nil
|
return cursorBlink ~= nil
|
||||||
end
|
end
|
||||||
@ -84,11 +85,11 @@ function term.read(history)
|
|||||||
history = history or {}
|
history = history or {}
|
||||||
table.insert(history, "")
|
table.insert(history, "")
|
||||||
local current = #history
|
local current = #history
|
||||||
local keys = driver.keyboard.keys
|
|
||||||
local start = term.cursor()
|
local start = term.cursor()
|
||||||
local cursor, scroll = 1, 0
|
local cursor, scroll = 1, 0
|
||||||
local keyRepeat = nil
|
local keyRepeat = nil
|
||||||
local result = nil
|
local result = nil
|
||||||
|
local forceReturn = false -- for eof where result is nil
|
||||||
local function remove()
|
local function remove()
|
||||||
local x = start - 1 + cursor - scroll
|
local x = start - 1 + cursor - scroll
|
||||||
local _, y = term.cursor()
|
local _, y = term.cursor()
|
||||||
@ -160,7 +161,7 @@ function term.read(history)
|
|||||||
term.cursorBlink(cursor <= history[current]:ulen() and
|
term.cursorBlink(cursor <= history[current]:ulen() and
|
||||||
history[current]:usub(cursor, cursor) or " ")
|
history[current]:usub(cursor, cursor) or " ")
|
||||||
if blink then
|
if blink then
|
||||||
toggleBlink()
|
term.cursorBlink(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function handleKeyPress(char, code)
|
local function handleKeyPress(char, code)
|
||||||
@ -168,7 +169,7 @@ function term.read(history)
|
|||||||
local w, h = gpu.resolution()
|
local w, h = gpu.resolution()
|
||||||
local cancel, blink = false, false
|
local cancel, blink = false, false
|
||||||
term.cursorBlink(false)
|
term.cursorBlink(false)
|
||||||
if code == keys.back then
|
if code == keyboard.keys.back then
|
||||||
if cursor > 1 then
|
if cursor > 1 then
|
||||||
copyIfNecessary()
|
copyIfNecessary()
|
||||||
history[current] = history[current]:usub(1, cursor - 2) ..
|
history[current] = history[current]:usub(1, cursor - 2) ..
|
||||||
@ -180,7 +181,7 @@ function term.read(history)
|
|||||||
remove()
|
remove()
|
||||||
end
|
end
|
||||||
cancel = cursor == 1
|
cancel = cursor == 1
|
||||||
elseif code == keys.delete then
|
elseif code == keyboard.keys.delete then
|
||||||
if cursor <= history[current]:ulen() then
|
if cursor <= history[current]:ulen() then
|
||||||
copyIfNecessary()
|
copyIfNecessary()
|
||||||
history[current] = history[current]:usub(1, cursor - 1) ..
|
history[current] = history[current]:usub(1, cursor - 1) ..
|
||||||
@ -188,7 +189,7 @@ function term.read(history)
|
|||||||
remove()
|
remove()
|
||||||
end
|
end
|
||||||
cancel = cursor == history[current]:ulen() + 1
|
cancel = cursor == history[current]:ulen() + 1
|
||||||
elseif code == keys.left then
|
elseif code == keyboard.keys.left then
|
||||||
if cursor > 1 then
|
if cursor > 1 then
|
||||||
cursor = cursor - 1
|
cursor = cursor - 1
|
||||||
if cursor - scroll < 1 then
|
if cursor - scroll < 1 then
|
||||||
@ -197,7 +198,7 @@ function term.read(history)
|
|||||||
end
|
end
|
||||||
cancel = cursor == 1
|
cancel = cursor == 1
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys.right then
|
elseif code == keyboard.keys.right then
|
||||||
if cursor < history[current]:ulen() + 1 then
|
if cursor < history[current]:ulen() + 1 then
|
||||||
cursor = cursor + 1
|
cursor = cursor + 1
|
||||||
if cursor - scroll > w - (start - 1) then
|
if cursor - scroll > w - (start - 1) then
|
||||||
@ -206,34 +207,34 @@ function term.read(history)
|
|||||||
end
|
end
|
||||||
cancel = cursor == history[current]:ulen() + 1
|
cancel = cursor == history[current]:ulen() + 1
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys.home then
|
elseif code == keyboard.keys.home then
|
||||||
if cursor > 1 then
|
if cursor > 1 then
|
||||||
cursor, scroll = 1, 0
|
cursor, scroll = 1, 0
|
||||||
render()
|
render()
|
||||||
end
|
end
|
||||||
cancel = true
|
cancel = true
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys["end"] then
|
elseif code == keyboard.keys["end"] then
|
||||||
if cursor < history[current]:ulen() + 1 then
|
if cursor < history[current]:ulen() + 1 then
|
||||||
scrollEnd()
|
scrollEnd()
|
||||||
end
|
end
|
||||||
cancel = true
|
cancel = true
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys.up then
|
elseif code == keyboard.keys.up then
|
||||||
if current > 1 then
|
if current > 1 then
|
||||||
current = current - 1
|
current = current - 1
|
||||||
scrollEnd()
|
scrollEnd()
|
||||||
end
|
end
|
||||||
cancel = current == 1
|
cancel = current == 1
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys.down then
|
elseif code == keyboard.keys.down then
|
||||||
if current < #history then
|
if current < #history then
|
||||||
current = current + 1
|
current = current + 1
|
||||||
scrollEnd()
|
scrollEnd()
|
||||||
end
|
end
|
||||||
cancel = current == #history
|
cancel = current == #history
|
||||||
blink = true
|
blink = true
|
||||||
elseif code == keys.enter then
|
elseif code == keyboard.keys.enter then
|
||||||
if current ~= #history then -- bring entry to front
|
if current ~= #history then -- bring entry to front
|
||||||
history[#history] = history[current]
|
history[#history] = history[current]
|
||||||
table.remove(history, current)
|
table.remove(history, current)
|
||||||
@ -244,7 +245,18 @@ function term.read(history)
|
|||||||
table.remove(history, current)
|
table.remove(history, current)
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
elseif not keys.isControl(char) then
|
elseif keyboard.isControlDown() then
|
||||||
|
if code == keyboard.keys.d then
|
||||||
|
if history[current] == "" then
|
||||||
|
forceReturn = true
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
elseif code == keyboard.keys.c then
|
||||||
|
history[current] = ""
|
||||||
|
forceReturn = true
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
elseif not keyboard.isControl(char) then
|
||||||
copyIfNecessary()
|
copyIfNecessary()
|
||||||
history[current] = history[current]:usub(1, cursor - 1) ..
|
history[current] = history[current]:usub(1, cursor - 1) ..
|
||||||
string.uchar(char) ..
|
string.uchar(char) ..
|
||||||
@ -259,9 +271,7 @@ function term.read(history)
|
|||||||
return cancel
|
return cancel
|
||||||
end
|
end
|
||||||
local function onKeyDown(_, address, char, code)
|
local function onKeyDown(_, address, char, code)
|
||||||
if not component.isAvailable("keyboard") or
|
if not component.isPrimary(address) then
|
||||||
address ~= component.primary("keyboard")
|
|
||||||
then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if keyRepeat then
|
if keyRepeat then
|
||||||
@ -277,19 +287,12 @@ function term.read(history)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function onKeyUp(_, address, char, code)
|
local function onKeyUp(_, address, char, code)
|
||||||
if not component.isAvailable("keyboard") or
|
if component.isPrimary(address) and keyRepeat then
|
||||||
address ~= component.primary("keyboard")
|
|
||||||
then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if keyRepeat then
|
|
||||||
keyRepeat = event.cancel(keyRepeat)
|
keyRepeat = event.cancel(keyRepeat)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function onClipboard(_, address, value)
|
local function onClipboard(_, address, value)
|
||||||
if not component.isAvailable("keyboard") or
|
if not component.isPrimary(address) then
|
||||||
address ~= component.primary("keyboard")
|
|
||||||
then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
copyIfNecessary()
|
copyIfNecessary()
|
||||||
@ -308,7 +311,7 @@ function term.read(history)
|
|||||||
event.listen("key_up", onKeyUp)
|
event.listen("key_up", onKeyUp)
|
||||||
event.listen("clipboard", onClipboard)
|
event.listen("clipboard", onClipboard)
|
||||||
term.cursorBlink(true)
|
term.cursorBlink(true)
|
||||||
while term.isAvailable() and not result do
|
while term.isAvailable() and not result and not forceReturn do
|
||||||
event.wait()
|
event.wait()
|
||||||
end
|
end
|
||||||
if history[#history] == "" then
|
if history[#history] == "" then
|
||||||
|
Loading…
x
Reference in New Issue
Block a user