From a8288b26230129a71843335733aff07f0bdfdba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 23 Oct 2013 17:10:56 +0200 Subject: [PATCH] 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 --- assets/opencomputers/lua/drivers/keyboard.lua | 2 +- assets/opencomputers/lua/kernel.lua | 188 +++++++++--------- assets/opencomputers/lua/rom/bin/alias.lua | 4 +- assets/opencomputers/lua/rom/bin/cat.lua | 6 +- assets/opencomputers/lua/rom/bin/cd.lua | 4 +- assets/opencomputers/lua/rom/bin/cp.lua | 4 +- assets/opencomputers/lua/rom/bin/ls.lua | 34 ++-- assets/opencomputers/lua/rom/bin/lua.lua | 21 +- assets/opencomputers/lua/rom/bin/mkdir.lua | 6 +- assets/opencomputers/lua/rom/bin/mv.lua | 4 +- assets/opencomputers/lua/rom/bin/rm.lua | 6 +- assets/opencomputers/lua/rom/bin/sh.lua | 6 + assets/opencomputers/lua/rom/bin/unalias.lua | 4 +- assets/opencomputers/lua/rom/bin/which.lua | 5 +- assets/opencomputers/lua/rom/lib/base.lua | 4 +- .../opencomputers/lua/rom/lib/component.lua | 8 + assets/opencomputers/lua/rom/lib/event.lua | 6 +- assets/opencomputers/lua/rom/lib/keyboard.lua | 52 +++++ assets/opencomputers/lua/rom/lib/os.lua | 2 + assets/opencomputers/lua/rom/lib/shell.lua | 19 +- assets/opencomputers/lua/rom/lib/term.lua | 69 ++++--- 21 files changed, 276 insertions(+), 178 deletions(-) create mode 100644 assets/opencomputers/lua/rom/lib/keyboard.lua diff --git a/assets/opencomputers/lua/drivers/keyboard.lua b/assets/opencomputers/lua/drivers/keyboard.lua index f8c0928db..21ef38936 100644 --- a/assets/opencomputers/lua/drivers/keyboard.lua +++ b/assets/opencomputers/lua/drivers/keyboard.lua @@ -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 diff --git a/assets/opencomputers/lua/kernel.lua b/assets/opencomputers/lua/kernel.lua index db8d2551f..c975e2af7 100644 --- a/assets/opencomputers/lua/kernel.lua +++ b/assets/opencomputers/lua/kernel.lua @@ -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. diff --git a/assets/opencomputers/lua/rom/bin/alias.lua b/assets/opencomputers/lua/rom/bin/alias.lua index 68b7974ed..819c67dcb 100644 --- a/assets/opencomputers/lua/rom/bin/alias.lua +++ b/assets/opencomputers/lua/rom/bin/alias.lua @@ -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) diff --git a/assets/opencomputers/lua/rom/bin/cat.lua b/assets/opencomputers/lua/rom/bin/cat.lua index 7886874a7..1b97f7313 100644 --- a/assets/opencomputers/lua/rom/bin/cat.lua +++ b/assets/opencomputers/lua/rom/bin/cat.lua @@ -1,10 +1,10 @@ -local args = table.pack(...) -if args.n == 0 then +local args = shell.parse(...) +if #args == 0 then print("Usage: cat [ [...]]") 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) diff --git a/assets/opencomputers/lua/rom/bin/cd.lua b/assets/opencomputers/lua/rom/bin/cd.lua index 4f35966a3..ad9a98326 100644 --- a/assets/opencomputers/lua/rom/bin/cd.lua +++ b/assets/opencomputers/lua/rom/bin/cd.lua @@ -1,5 +1,5 @@ -local args = table.pack(...) -if args.n == 0 then +local args = shell.parse(...) +if #args == 0 then print("Usage: cd ") else local result, reason = shell.cwd(shell.resolve(args[1])) diff --git a/assets/opencomputers/lua/rom/bin/cp.lua b/assets/opencomputers/lua/rom/bin/cp.lua index 239ffc60a..ebf3571f9 100644 --- a/assets/opencomputers/lua/rom/bin/cp.lua +++ b/assets/opencomputers/lua/rom/bin/cp.lua @@ -1,5 +1,5 @@ -local args = table.pack(...) -if args.n < 2 then +local args = shell.parse(...) +if #args < 2 then print("Usage: cp ") return end diff --git a/assets/opencomputers/lua/rom/bin/ls.lua b/assets/opencomputers/lua/rom/bin/ls.lua index 054e4e74d..d9f432c36 100644 --- a/assets/opencomputers/lua/rom/bin/ls.lua +++ b/assets/opencomputers/lua/rom/bin/ls.lua @@ -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 \ No newline at end of file +end diff --git a/assets/opencomputers/lua/rom/bin/lua.lua b/assets/opencomputers/lua/rom/bin/lua.lua index 47e7dd87b..c343062a9 100644 --- a/assets/opencomputers/lua/rom/bin/lua.lua +++ b/assets/opencomputers/lua/rom/bin/lua.lua @@ -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)) diff --git a/assets/opencomputers/lua/rom/bin/mkdir.lua b/assets/opencomputers/lua/rom/bin/mkdir.lua index 5c446e302..8a75c4194 100644 --- a/assets/opencomputers/lua/rom/bin/mkdir.lua +++ b/assets/opencomputers/lua/rom/bin/mkdir.lua @@ -1,10 +1,10 @@ -local args = table.pack(...) -if args.n == 0 then +local args = shell.parse(...) +if #args == 0 then print("Usage: mkdir [ [...]]") 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 diff --git a/assets/opencomputers/lua/rom/bin/mv.lua b/assets/opencomputers/lua/rom/bin/mv.lua index 39c499710..e2521b5e8 100644 --- a/assets/opencomputers/lua/rom/bin/mv.lua +++ b/assets/opencomputers/lua/rom/bin/mv.lua @@ -1,5 +1,5 @@ -local args = table.pack(...) -if args.n < 2 then +local args = shell.parse(...) +if #args < 2 then print("Usage: mv ") return end diff --git a/assets/opencomputers/lua/rom/bin/rm.lua b/assets/opencomputers/lua/rom/bin/rm.lua index 7b0a5c925..e0620517f 100644 --- a/assets/opencomputers/lua/rom/bin/rm.lua +++ b/assets/opencomputers/lua/rom/bin/rm.lua @@ -1,10 +1,10 @@ -local args = table.pack(...) -if args.n == 0 then +local args = shell.parse(...) +if #args == 0 then print("Usage: rm [ [...]]") 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") diff --git a/assets/opencomputers/lua/rom/bin/sh.lua b/assets/opencomputers/lua/rom/bin/sh.lua index 1decd30b2..34230f589 100644 --- a/assets/opencomputers/lua/rom/bin/sh.lua +++ b/assets/opencomputers/lua/rom/bin/sh.lua @@ -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) diff --git a/assets/opencomputers/lua/rom/bin/unalias.lua b/assets/opencomputers/lua/rom/bin/unalias.lua index 18e943b0f..596c31831 100644 --- a/assets/opencomputers/lua/rom/bin/unalias.lua +++ b/assets/opencomputers/lua/rom/bin/unalias.lua @@ -1,5 +1,5 @@ -local args = table.pack(...) -if args.n < 1 then +local args = shell.parse(...) +if #args < 1 then print("Usage: unalias ") return end diff --git a/assets/opencomputers/lua/rom/bin/which.lua b/assets/opencomputers/lua/rom/bin/which.lua index 6069b38ea..2e30ee194 100644 --- a/assets/opencomputers/lua/rom/bin/which.lua +++ b/assets/opencomputers/lua/rom/bin/which.lua @@ -1,8 +1,9 @@ -local args = table.pack(...) -if args.n == 0 then +local args = shell.parse(...) +if #args == 0 then print("Usage: which ") return end + local result, reason = shell.which(args[1]) if result then print(result) diff --git a/assets/opencomputers/lua/rom/lib/base.lua b/assets/opencomputers/lua/rom/lib/base.lua index 3b3ae8f2a..6e0b16973 100644 --- a/assets/opencomputers/lua/rom/lib/base.lua +++ b/assets/opencomputers/lua/rom/lib/base.lua @@ -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(...) diff --git a/assets/opencomputers/lua/rom/lib/component.lua b/assets/opencomputers/lua/rom/lib/component.lua index c3584045e..8abf6c9f8 100644 --- a/assets/opencomputers/lua/rom/lib/component.lua +++ b/assets/opencomputers/lua/rom/lib/component.lua @@ -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(...) diff --git a/assets/opencomputers/lua/rom/lib/event.lua b/assets/opencomputers/lua/rom/lib/event.lua index 8c40f3a42..a6f837975 100644 --- a/assets/opencomputers/lua/rom/lib/event.lua +++ b/assets/opencomputers/lua/rom/lib/event.lua @@ -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 diff --git a/assets/opencomputers/lua/rom/lib/keyboard.lua b/assets/opencomputers/lua/rom/lib/keyboard.lua new file mode 100644 index 000000000..ee3906a37 --- /dev/null +++ b/assets/opencomputers/lua/rom/lib/keyboard.lua @@ -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 diff --git a/assets/opencomputers/lua/rom/lib/os.lua b/assets/opencomputers/lua/rom/lib/os.lua index 4821acff5..c672ff3de 100644 --- a/assets/opencomputers/lua/rom/lib/os.lua +++ b/assets/opencomputers/lua/rom/lib/os.lua @@ -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 diff --git a/assets/opencomputers/lua/rom/lib/shell.lua b/assets/opencomputers/lua/rom/lib/shell.lua index e66f400a7..82625454e 100644 --- a/assets/opencomputers/lua/rom/lib/shell.lua +++ b/assets/opencomputers/lua/rom/lib/shell.lua @@ -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) diff --git a/assets/opencomputers/lua/rom/lib/term.lua b/assets/opencomputers/lua/rom/lib/term.lua index 4b29f3e46..996b4169b 100644 --- a/assets/opencomputers/lua/rom/lib/term.lua +++ b/assets/opencomputers/lua/rom/lib/term.lua @@ -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