mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-15 10:21:45 -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
|
||||
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))
|
||||
end
|
||||
|
@ -47,11 +47,8 @@ local sandbox = {
|
||||
|
||||
coroutine = {
|
||||
create = coroutine.create,
|
||||
resume = coroutine.resume,
|
||||
running = coroutine.running,
|
||||
status = coroutine.status,
|
||||
wrap = coroutine.wrap,
|
||||
yield = coroutine.yield
|
||||
status = coroutine.status
|
||||
},
|
||||
|
||||
math = {
|
||||
@ -136,8 +133,9 @@ local sandbox = {
|
||||
}
|
||||
sandbox._G = sandbox
|
||||
|
||||
function sandbox.load(code, source, env)
|
||||
return load(code, source, "t", env or sandbox)
|
||||
function sandbox.load(ld, source, mode, env)
|
||||
assert((mode or "t") == "t", "unsupported mode")
|
||||
return load(ld, source, "t", env or sandbox)
|
||||
end
|
||||
|
||||
function sandbox.checkArg(n, have, ...)
|
||||
@ -151,7 +149,7 @@ function sandbox.checkArg(n, have, ...)
|
||||
end
|
||||
if not check(...) then
|
||||
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)
|
||||
end
|
||||
end
|
||||
@ -170,6 +168,100 @@ local function checkDeadline()
|
||||
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 bootstrap()
|
||||
local fs = sandbox.driver.filesystem
|
||||
@ -235,88 +327,6 @@ local function main(args)
|
||||
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
|
||||
-- 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.
|
||||
|
@ -1,10 +1,10 @@
|
||||
local args = table.pack(...)
|
||||
local args = shell.parse(...)
|
||||
|
||||
if args.n == 0 then
|
||||
for name, value in shell.aliases() do
|
||||
print(name, value)
|
||||
end
|
||||
elseif args.n == 1 then
|
||||
elseif #args == 1 then
|
||||
local value = shell.alias(args[1])
|
||||
if value then
|
||||
print(value)
|
||||
|
@ -1,10 +1,10 @@
|
||||
local args = table.pack(...)
|
||||
if args.n == 0 then
|
||||
local args = shell.parse(...)
|
||||
if #args == 0 then
|
||||
print("Usage: cat <filename1> [<filename2> [...]]")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, args.n do
|
||||
for i = 1, #args do
|
||||
local file, reason = io.open(shell.resolve(args[i]), "r")
|
||||
if not file then
|
||||
print(reason)
|
||||
|
@ -1,5 +1,5 @@
|
||||
local args = table.pack(...)
|
||||
if args.n == 0 then
|
||||
local args = shell.parse(...)
|
||||
if #args == 0 then
|
||||
print("Usage: cd <dirname>")
|
||||
else
|
||||
local result, reason = shell.cwd(shell.resolve(args[1]))
|
||||
|
@ -1,5 +1,5 @@
|
||||
local args = table.pack(...)
|
||||
if args.n < 2 then
|
||||
local args = shell.parse(...)
|
||||
if #args < 2 then
|
||||
print("Usage: cp <from> <to>")
|
||||
return
|
||||
end
|
||||
|
@ -1,33 +1,29 @@
|
||||
local args = table.pack(...)
|
||||
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
|
||||
local dirs, options = shell.parse(...)
|
||||
if #dirs == 0 then
|
||||
table.insert(dirs, ".")
|
||||
end
|
||||
|
||||
for i = 1, #dirs do
|
||||
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)
|
||||
if not list then
|
||||
print(reason)
|
||||
else
|
||||
for f in list do
|
||||
if options.l then
|
||||
print(f, fs.size(fs.concat(path, f)))
|
||||
else
|
||||
io.write(f .. "\t")
|
||||
if options.a or f:usub(1, 1) ~= "." then
|
||||
if options.l then
|
||||
print(f, fs.size(fs.concat(path, f)))
|
||||
else
|
||||
io.write(f .. "\t")
|
||||
end
|
||||
end
|
||||
end
|
||||
print()
|
||||
if not options.l then
|
||||
print()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,14 +1,17 @@
|
||||
print("Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio")
|
||||
local running = true
|
||||
local env = setmetatable({exit=function() running = false end}, {__index=_ENV})
|
||||
while running and term.isAvailable() do
|
||||
io.write("lua> ")
|
||||
local command = io.read()
|
||||
if not command then
|
||||
return -- eof
|
||||
local history = {}
|
||||
local env = setmetatable({}, {__index=_ENV})
|
||||
while term.isAvailable() do
|
||||
term.write("lua> ")
|
||||
local command = term.read(history)
|
||||
if command == nil then -- eof
|
||||
return
|
||||
end
|
||||
local statement, result = load(command, "=stdin", env)
|
||||
local expression = load("return " .. command, "=stdin", env)
|
||||
while #history > 10 do
|
||||
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
|
||||
if code then
|
||||
local result = table.pack(pcall(code))
|
||||
|
@ -1,10 +1,10 @@
|
||||
local args = table.pack(...)
|
||||
if args.n == 0 then
|
||||
local args = shell.parse(...)
|
||||
if #args == 0 then
|
||||
print("Usage: mkdir <dirname1> [<dirname2> [...]]")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, args.n do
|
||||
for i = 1, #args do
|
||||
local path = shell.resolve(args[i])
|
||||
local result, reason = fs.makeDirectory(path)
|
||||
if not result then
|
||||
|
@ -1,5 +1,5 @@
|
||||
local args = table.pack(...)
|
||||
if args.n < 2 then
|
||||
local args = shell.parse(...)
|
||||
if #args < 2 then
|
||||
print("Usage: mv <from> <to>")
|
||||
return
|
||||
end
|
||||
|
@ -1,10 +1,10 @@
|
||||
local args = table.pack(...)
|
||||
if args.n == 0 then
|
||||
local args = shell.parse(...)
|
||||
if #args == 0 then
|
||||
print("Usage: rm <filename1> [<filename2> [...]]")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, args.n do
|
||||
for i = 1, #args do
|
||||
local path = shell.resolve(args[i])
|
||||
if not fs.remove(path) then
|
||||
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 from = s:match"^%s*()"
|
||||
return from > #s and "" or s:match(".*%S", from)
|
||||
|
@ -1,5 +1,5 @@
|
||||
local args = table.pack(...)
|
||||
if args.n < 1 then
|
||||
local args = shell.parse(...)
|
||||
if #args < 1 then
|
||||
print("Usage: unalias <name>")
|
||||
return
|
||||
end
|
||||
|
@ -1,8 +1,9 @@
|
||||
local args = table.pack(...)
|
||||
if args.n == 0 then
|
||||
local args = shell.parse(...)
|
||||
if #args == 0 then
|
||||
print("Usage: which <program>")
|
||||
return
|
||||
end
|
||||
|
||||
local result, reason = shell.which(args[1])
|
||||
if result then
|
||||
print(result)
|
||||
|
@ -6,7 +6,7 @@ function dofile(filename)
|
||||
return program()
|
||||
end
|
||||
|
||||
function loadfile(filename, env)
|
||||
function loadfile(filename, mode, env)
|
||||
local file, reason = io.open(filename)
|
||||
if not file then
|
||||
return nil, reason
|
||||
@ -16,7 +16,7 @@ function loadfile(filename, env)
|
||||
if not source then
|
||||
return nil, reason
|
||||
end
|
||||
return load(source, "=" .. filename, env)
|
||||
return load(source, "=" .. filename, mode, env)
|
||||
end
|
||||
|
||||
function print(...)
|
||||
|
@ -20,6 +20,14 @@ function component.list(filter)
|
||||
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, ...)
|
||||
checkArg(1, componentType, "string")
|
||||
local args = table.pack(...)
|
||||
|
@ -95,13 +95,13 @@ function event.cancel(timerId)
|
||||
timers[timerId] = nil
|
||||
end
|
||||
|
||||
function event.interval(timeout, callback)
|
||||
function event.interval(frequency, callback)
|
||||
local interval = {}
|
||||
local function onTimer()
|
||||
interval.id = event.timer(timeout, onTimer)
|
||||
interval.id = event.timer(frequency, onTimer)
|
||||
callback()
|
||||
end
|
||||
interval.id = event.timer(timeout, onTimer)
|
||||
interval.id = event.timer(frequency, onTimer)
|
||||
return interval
|
||||
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.sleep = event.wait
|
||||
|
||||
function os.tmpname()
|
||||
if driver.filesystem.exists("tmp") then
|
||||
for i = 1, 10 do
|
||||
|
@ -146,7 +146,7 @@ function shell.execute(program, ...)
|
||||
pevent = setmetatable(pevent, {__index = event, __metatable = {}})
|
||||
local env = setmetatable({event = pevent}, {__index = _ENV, __metatable = {}})
|
||||
|
||||
program, reason = loadfile(where, env)
|
||||
program, reason = loadfile(where, "t", env)
|
||||
if not program then
|
||||
return nil, reason
|
||||
end
|
||||
@ -170,6 +170,23 @@ function shell.execute(program, ...)
|
||||
return table.unpack(result, 1, result.n)
|
||||
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)
|
||||
if path:usub(1, 1) == "/" then
|
||||
return fs.canonical(path)
|
||||
|
@ -1,14 +1,6 @@
|
||||
local cursorX, cursorY = 1, 1
|
||||
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 = {}
|
||||
@ -43,6 +35,13 @@ function term.cursor(col, row)
|
||||
end
|
||||
|
||||
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)
|
||||
if not cursorBlink then
|
||||
cursorBlink = event.interval(0.5, toggleBlink)
|
||||
@ -74,6 +73,8 @@ function term.cursorBlink(enabled)
|
||||
else
|
||||
stop()
|
||||
end
|
||||
elseif enabled and cursorBlink then
|
||||
toggleBlink()
|
||||
end
|
||||
return cursorBlink ~= nil
|
||||
end
|
||||
@ -84,11 +85,11 @@ function term.read(history)
|
||||
history = history or {}
|
||||
table.insert(history, "")
|
||||
local current = #history
|
||||
local keys = driver.keyboard.keys
|
||||
local start = term.cursor()
|
||||
local cursor, scroll = 1, 0
|
||||
local keyRepeat = nil
|
||||
local result = nil
|
||||
local forceReturn = false -- for eof where result is nil
|
||||
local function remove()
|
||||
local x = start - 1 + cursor - scroll
|
||||
local _, y = term.cursor()
|
||||
@ -160,7 +161,7 @@ function term.read(history)
|
||||
term.cursorBlink(cursor <= history[current]:ulen() and
|
||||
history[current]:usub(cursor, cursor) or " ")
|
||||
if blink then
|
||||
toggleBlink()
|
||||
term.cursorBlink(true)
|
||||
end
|
||||
end
|
||||
local function handleKeyPress(char, code)
|
||||
@ -168,7 +169,7 @@ function term.read(history)
|
||||
local w, h = gpu.resolution()
|
||||
local cancel, blink = false, false
|
||||
term.cursorBlink(false)
|
||||
if code == keys.back then
|
||||
if code == keyboard.keys.back then
|
||||
if cursor > 1 then
|
||||
copyIfNecessary()
|
||||
history[current] = history[current]:usub(1, cursor - 2) ..
|
||||
@ -180,7 +181,7 @@ function term.read(history)
|
||||
remove()
|
||||
end
|
||||
cancel = cursor == 1
|
||||
elseif code == keys.delete then
|
||||
elseif code == keyboard.keys.delete then
|
||||
if cursor <= history[current]:ulen() then
|
||||
copyIfNecessary()
|
||||
history[current] = history[current]:usub(1, cursor - 1) ..
|
||||
@ -188,7 +189,7 @@ function term.read(history)
|
||||
remove()
|
||||
end
|
||||
cancel = cursor == history[current]:ulen() + 1
|
||||
elseif code == keys.left then
|
||||
elseif code == keyboard.keys.left then
|
||||
if cursor > 1 then
|
||||
cursor = cursor - 1
|
||||
if cursor - scroll < 1 then
|
||||
@ -197,7 +198,7 @@ function term.read(history)
|
||||
end
|
||||
cancel = cursor == 1
|
||||
blink = true
|
||||
elseif code == keys.right then
|
||||
elseif code == keyboard.keys.right then
|
||||
if cursor < history[current]:ulen() + 1 then
|
||||
cursor = cursor + 1
|
||||
if cursor - scroll > w - (start - 1) then
|
||||
@ -206,34 +207,34 @@ function term.read(history)
|
||||
end
|
||||
cancel = cursor == history[current]:ulen() + 1
|
||||
blink = true
|
||||
elseif code == keys.home then
|
||||
elseif code == keyboard.keys.home then
|
||||
if cursor > 1 then
|
||||
cursor, scroll = 1, 0
|
||||
render()
|
||||
end
|
||||
cancel = true
|
||||
blink = true
|
||||
elseif code == keys["end"] then
|
||||
elseif code == keyboard.keys["end"] then
|
||||
if cursor < history[current]:ulen() + 1 then
|
||||
scrollEnd()
|
||||
end
|
||||
cancel = true
|
||||
blink = true
|
||||
elseif code == keys.up then
|
||||
elseif code == keyboard.keys.up then
|
||||
if current > 1 then
|
||||
current = current - 1
|
||||
scrollEnd()
|
||||
end
|
||||
cancel = current == 1
|
||||
blink = true
|
||||
elseif code == keys.down then
|
||||
elseif code == keyboard.keys.down then
|
||||
if current < #history then
|
||||
current = current + 1
|
||||
scrollEnd()
|
||||
end
|
||||
cancel = current == #history
|
||||
blink = true
|
||||
elseif code == keys.enter then
|
||||
elseif code == keyboard.keys.enter then
|
||||
if current ~= #history then -- bring entry to front
|
||||
history[#history] = history[current]
|
||||
table.remove(history, current)
|
||||
@ -244,7 +245,18 @@ function term.read(history)
|
||||
table.remove(history, current)
|
||||
end
|
||||
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()
|
||||
history[current] = history[current]:usub(1, cursor - 1) ..
|
||||
string.uchar(char) ..
|
||||
@ -259,9 +271,7 @@ function term.read(history)
|
||||
return cancel
|
||||
end
|
||||
local function onKeyDown(_, address, char, code)
|
||||
if not component.isAvailable("keyboard") or
|
||||
address ~= component.primary("keyboard")
|
||||
then
|
||||
if not component.isPrimary(address) then
|
||||
return
|
||||
end
|
||||
if keyRepeat then
|
||||
@ -277,19 +287,12 @@ function term.read(history)
|
||||
end
|
||||
end
|
||||
local function onKeyUp(_, address, char, code)
|
||||
if not component.isAvailable("keyboard") or
|
||||
address ~= component.primary("keyboard")
|
||||
then
|
||||
return
|
||||
end
|
||||
if keyRepeat then
|
||||
if component.isPrimary(address) and keyRepeat then
|
||||
keyRepeat = event.cancel(keyRepeat)
|
||||
end
|
||||
end
|
||||
local function onClipboard(_, address, value)
|
||||
if not component.isAvailable("keyboard") or
|
||||
address ~= component.primary("keyboard")
|
||||
then
|
||||
if not component.isPrimary(address) then
|
||||
return
|
||||
end
|
||||
copyIfNecessary()
|
||||
@ -308,7 +311,7 @@ function term.read(history)
|
||||
event.listen("key_up", onKeyUp)
|
||||
event.listen("clipboard", onClipboard)
|
||||
term.cursorBlink(true)
|
||||
while term.isAvailable() and not result do
|
||||
while term.isAvailable() and not result and not forceReturn do
|
||||
event.wait()
|
||||
end
|
||||
if history[#history] == "" then
|
||||
|
Loading…
x
Reference in New Issue
Block a user