mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 19:25:20 -04:00
Merge remote-tracking branch 'upstream/master-MC1.9.4' into master-MC1.10
This commit is contained in:
commit
623f6d2775
@ -1,6 +1,5 @@
|
|||||||
local rc = require("rc")
|
local rc = require("rc")
|
||||||
local fs = require("filesystem")
|
local fs = require("filesystem")
|
||||||
local shell = require("shell")
|
|
||||||
|
|
||||||
local function loadConfig()
|
local function loadConfig()
|
||||||
local env = {}
|
local env = {}
|
||||||
@ -117,9 +116,7 @@ local function allRunCommand(cmd, ...)
|
|||||||
return results
|
return results
|
||||||
end
|
end
|
||||||
|
|
||||||
local args = table.pack(...)
|
if select("#", ...) == 0 then
|
||||||
|
|
||||||
if #args == 0 then
|
|
||||||
local results,reason = allRunCommand("start")
|
local results,reason = allRunCommand("start")
|
||||||
if not results then
|
if not results then
|
||||||
local msg = "rc failed to start:"..tostring(reason)
|
local msg = "rc failed to start:"..tostring(reason)
|
||||||
@ -127,16 +124,16 @@ if #args == 0 then
|
|||||||
require("event").onError(msg)
|
require("event").onError(msg)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for name, result in pairs(results) do
|
for _, result in pairs(results) do
|
||||||
local ok, reason = table.unpack(result)
|
local ok, reason = table.unpack(result)
|
||||||
if not ok then
|
if not ok then
|
||||||
io.stderr:write(reason .. "\n")
|
io.stderr:write(reason, "\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local result, reason = runCommand(table.unpack(args))
|
local result, reason = runCommand(...)
|
||||||
if not result then
|
if not result then
|
||||||
io.stderr:write(reason .. "\n")
|
io.stderr:write(reason, "\n")
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -39,23 +39,15 @@ end
|
|||||||
local total_time = 0
|
local total_time = 0
|
||||||
|
|
||||||
for _,v in ipairs(args) do
|
for _,v in ipairs(args) do
|
||||||
local interval = v:match('^%d+%.?%d*[smhd]?$')
|
local interval, time_type = v:match('^([%d%.]+)([smhd]?)$')
|
||||||
if not interval then
|
|
||||||
help(v)
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local time_type = interval:match('[smhd]') or ''
|
|
||||||
interval = interval:sub(1, -#time_type-1)
|
|
||||||
interval = tonumber(interval)
|
interval = tonumber(interval)
|
||||||
|
|
||||||
if interval < 0 then
|
if not interval or interval < 0 then
|
||||||
help(v)
|
help(v)
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
interval = time_type_multiplier(time_type) * interval
|
total_time = total_time + time_type_multiplier(time_type) * interval
|
||||||
total_time = total_time + interval
|
|
||||||
end
|
end
|
||||||
|
|
||||||
os.sleep(total_time)
|
os.sleep(total_time)
|
||||||
|
@ -32,6 +32,7 @@ end
|
|||||||
function print(...)
|
function print(...)
|
||||||
local args = table.pack(...)
|
local args = table.pack(...)
|
||||||
local stdout = io.stdout
|
local stdout = io.stdout
|
||||||
|
local old_mode, old_size = stdout:setvbuf()
|
||||||
stdout:setvbuf("line")
|
stdout:setvbuf("line")
|
||||||
local pre = ""
|
local pre = ""
|
||||||
for i = 1, args.n do
|
for i = 1, args.n do
|
||||||
@ -39,6 +40,6 @@ function print(...)
|
|||||||
pre = "\t"
|
pre = "\t"
|
||||||
end
|
end
|
||||||
stdout:write("\n")
|
stdout:write("\n")
|
||||||
stdout:setvbuf("no")
|
stdout:setvbuf(old_mode, old_size)
|
||||||
stdout:flush()
|
stdout:flush()
|
||||||
end
|
end
|
||||||
|
@ -6,7 +6,11 @@ local _coroutine = coroutine -- real coroutine backend
|
|||||||
_G.coroutine = setmetatable(
|
_G.coroutine = setmetatable(
|
||||||
{
|
{
|
||||||
resume = function(co, ...)
|
resume = function(co, ...)
|
||||||
return assert(process.info(co), "thread has no proc").data.coroutine_handler.resume(co, ...)
|
local proc = process.info(co)
|
||||||
|
-- proc is nil if the process closed, natural resume will likely complain the coroutine is dead
|
||||||
|
-- but if proc is dead and an aborted coroutine is alive, it doesn't have any proc data like stack info
|
||||||
|
-- if the user really wants to resume it, let them
|
||||||
|
return (proc and proc.data.coroutine_handler.resume or _coroutine.resume)(co, ...)
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -22,18 +26,22 @@ local kernel_load = _G.load
|
|||||||
local intercept_load
|
local intercept_load
|
||||||
intercept_load = function(source, label, mode, env)
|
intercept_load = function(source, label, mode, env)
|
||||||
if env then
|
if env then
|
||||||
local loader = setmetatable(
|
local prev_load = env.load or intercept_load
|
||||||
{
|
local env_mt = getmetatable(env) or {}
|
||||||
env = env,
|
local env_mt_index = env_mt.__index
|
||||||
load = intercept_load,
|
env_mt.__index = function(tbl, key)
|
||||||
},
|
if key == "load" then
|
||||||
{__call = function(tbl, _source, _label, _mode, _env)
|
return function(_source, _label, _mode, _env)
|
||||||
return tbl.load(_source, _label, _mode, _env or tbl.env)
|
return prev_load(_source, _label, _mode, _env or env)
|
||||||
end})
|
|
||||||
if env.load and (type(env.load) ~= "table" or env.load.load ~= intercept_load) then
|
|
||||||
loader.load = env.load
|
|
||||||
end
|
end
|
||||||
env.load = loader
|
elseif type(env_mt_index) == "table" then
|
||||||
|
return env_mt_index[key]
|
||||||
|
elseif env_mt_index then
|
||||||
|
return env_mt_index(tbl, key)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
setmetatable(env, env_mt)
|
||||||
end
|
end
|
||||||
return kernel_load(source, label, mode, env or process.info().env)
|
return kernel_load(source, label, mode, env or process.info().env)
|
||||||
end
|
end
|
||||||
@ -51,10 +59,7 @@ end
|
|||||||
_coroutine.wrap = function(f)
|
_coroutine.wrap = function(f)
|
||||||
local thread = coroutine.create(f)
|
local thread = coroutine.create(f)
|
||||||
return function(...)
|
return function(...)
|
||||||
local result_pack = table.pack(coroutine.resume(thread, ...))
|
return select(2, coroutine.resume(thread, ...))
|
||||||
local result, reason = result_pack[1], result_pack[2]
|
|
||||||
assert(result, reason)
|
|
||||||
return select(2, table.unpack(result_pack))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ function filesystem.concat(...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function filesystem.get(path)
|
function filesystem.get(path)
|
||||||
local node, rest = findNode(path)
|
local node = findNode(path)
|
||||||
if node.fs then
|
if node.fs then
|
||||||
local proxy = node.fs
|
local proxy = node.fs
|
||||||
path = ""
|
path = ""
|
||||||
@ -155,7 +155,7 @@ end
|
|||||||
|
|
||||||
function filesystem.realPath(path)
|
function filesystem.realPath(path)
|
||||||
checkArg(1, path, "string")
|
checkArg(1, path, "string")
|
||||||
local node, rest, vnode, vrest = findNode(path, false, true)
|
local node, rest = findNode(path, false, true)
|
||||||
if not node then return nil, rest end
|
if not node then return nil, rest end
|
||||||
local parts = {rest or nil}
|
local parts = {rest or nil}
|
||||||
repeat
|
repeat
|
||||||
@ -199,7 +199,7 @@ function filesystem.link(target, linkpath)
|
|||||||
return nil, "not a directory"
|
return nil, "not a directory"
|
||||||
end
|
end
|
||||||
|
|
||||||
local node, rest, vnode, vrest = findNode(linkpath_real, true)
|
local _, _, vnode, _ = findNode(linkpath_real, true)
|
||||||
vnode.links[filesystem.name(linkpath)] = target
|
vnode.links[filesystem.name(linkpath)] = target
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -235,7 +235,7 @@ function filesystem.mount(fs, path)
|
|||||||
if fstab[real] then
|
if fstab[real] then
|
||||||
return nil, "another filesystem is already mounted here"
|
return nil, "another filesystem is already mounted here"
|
||||||
end
|
end
|
||||||
for path,node in pairs(fstab) do
|
for _,node in pairs(fstab) do
|
||||||
if node.fs.address == fs.address then
|
if node.fs.address == fs.address then
|
||||||
fsnode = node
|
fsnode = node
|
||||||
break
|
break
|
||||||
|
@ -22,17 +22,18 @@ function pipe.createCoroutineStack(root, env, name)
|
|||||||
function pco.yield(...)
|
function pco.yield(...)
|
||||||
return _root_co.yield(nil, ...)
|
return _root_co.yield(nil, ...)
|
||||||
end
|
end
|
||||||
function pco.yield_all(...)
|
function pco.yield_past(co, ...)
|
||||||
return _root_co.yield(true, ...)
|
return _root_co.yield(co, ...)
|
||||||
end
|
end
|
||||||
function pco.resume(co, ...)
|
function pco.resume(co, ...)
|
||||||
checkArg(1, co, "thread")
|
checkArg(1, co, "thread")
|
||||||
local args = table.pack(...)
|
local args = table.pack(...)
|
||||||
while true do -- for consecutive sysyields
|
while true do -- for consecutive sysyields
|
||||||
local result = table.pack(_root_co.resume(co, table.unpack(args, 1, args.n)))
|
local result = table.pack(_root_co.resume(co, table.unpack(args, 1, args.n)))
|
||||||
|
local target = result[2] == true and pco.root or result[2]
|
||||||
if not result[1] or _root_co.status(co) == "dead" then
|
if not result[1] or _root_co.status(co) == "dead" then
|
||||||
return table.unpack(result, 1, result.n)
|
return table.unpack(result, 1, result.n)
|
||||||
elseif result[2] and pco.root ~= co then
|
elseif target and target ~= co then
|
||||||
args = table.pack(_root_co.yield(table.unpack(result, 2, result.n)))
|
args = table.pack(_root_co.yield(table.unpack(result, 2, result.n)))
|
||||||
else
|
else
|
||||||
return true, table.unpack(result, 3, result.n)
|
return true, table.unpack(result, 3, result.n)
|
||||||
@ -70,7 +71,8 @@ local pipe_stream =
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
-- not reading, it is requesting a yield
|
-- not reading, it is requesting a yield
|
||||||
result = table.pack(coroutine.yield_all(table.unpack(result, 2, result.n)))
|
-- yield_past(true) will exit this coroutine stack
|
||||||
|
result = table.pack(coroutine.yield_past(true, table.unpack(result, 2, result.n)))
|
||||||
result = table.pack(coroutine.resume(self.next, table.unpack(result, 1, result.n))) -- the request was for an event
|
result = table.pack(coroutine.resume(self.next, table.unpack(result, 1, result.n))) -- the request was for an event
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@ -113,7 +115,7 @@ local pipe_stream =
|
|||||||
-- natural yield (i.e. for events). To differentiate this yield from natural
|
-- natural yield (i.e. for events). To differentiate this yield from natural
|
||||||
-- yields we set read_mode here, which the pipe_stream write detects
|
-- yields we set read_mode here, which the pipe_stream write detects
|
||||||
self.read_mode = true
|
self.read_mode = true
|
||||||
coroutine.yield_all()
|
coroutine.yield_past(self.next) -- next is the first croutine in this stack
|
||||||
self.read_mode = false
|
self.read_mode = false
|
||||||
end
|
end
|
||||||
local result = string.sub(self.buffer, 1, n)
|
local result = string.sub(self.buffer, 1, n)
|
||||||
@ -158,16 +160,24 @@ end
|
|||||||
|
|
||||||
local chain_stream =
|
local chain_stream =
|
||||||
{
|
{
|
||||||
read = function(self, value)
|
read = function(self, value, ...)
|
||||||
if self.io_stream.closed then return nil end
|
if self.io_stream.closed then return nil end
|
||||||
-- handler is currently on yield all [else we wouldn't have control here]
|
-- wake up prog
|
||||||
local read_ok, ret = self.pco.resume(self.pco.root, value)
|
self.ready = false -- the pipe proc sets this true when ios completes
|
||||||
-- ret can be non string when a process ends
|
local ret = table.pack(coroutine.resume(self.pco.root, value, ...))
|
||||||
ret = type(ret) == "string" and ret or nil
|
if coroutine.status(self.pco.root) == "dead" then
|
||||||
return select(read_ok and 2 or 1, nil, ret)
|
return nil
|
||||||
|
elseif not ret[1] then
|
||||||
|
return table.unpack(ret, 1, ret.n)
|
||||||
|
end
|
||||||
|
if not self.ready then
|
||||||
|
-- prog yielded back without writing/reading
|
||||||
|
return self:read(coroutine.yield())
|
||||||
|
end
|
||||||
|
return ret[2]
|
||||||
end,
|
end,
|
||||||
write = function(self, ...)
|
write = function(self, ...)
|
||||||
return self:read(table.concat({...}))
|
return self:read(...)
|
||||||
end,
|
end,
|
||||||
close = function(self)
|
close = function(self)
|
||||||
self.io_stream:close()
|
self.io_stream:close()
|
||||||
@ -181,8 +191,8 @@ function pipe.popen(prog, mode, env)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local r = mode == "r"
|
local r = mode == "r"
|
||||||
local key = r and "read" or "write"
|
|
||||||
|
|
||||||
|
local chain = {}
|
||||||
-- to simplify the code - shell.execute is run within a function to pass (prog, env)
|
-- to simplify the code - shell.execute is run within a function to pass (prog, env)
|
||||||
-- if cmd_proc where to come second (mode=="w") then the pipe_proc would have to pass
|
-- if cmd_proc where to come second (mode=="w") then the pipe_proc would have to pass
|
||||||
-- the starting args. which is possible, just more complicated
|
-- the starting args. which is possible, just more complicated
|
||||||
@ -194,22 +204,27 @@ function pipe.popen(prog, mode, env)
|
|||||||
-- the stream needs its own process for io
|
-- the stream needs its own process for io
|
||||||
local pipe_proc = process.load(function()
|
local pipe_proc = process.load(function()
|
||||||
local n = r and 0 or ""
|
local n = r and 0 or ""
|
||||||
|
local key = r and "read" or "write"
|
||||||
local ios = stream.io_stream
|
local ios = stream.io_stream
|
||||||
while not ios.closed do
|
while not ios.closed do
|
||||||
n = coroutine.yield_all(ios[key](ios, n))
|
-- read from pipe
|
||||||
|
local ret = table.pack(ios[key](ios, n))
|
||||||
|
stream.ready = true
|
||||||
|
-- yield outside the chain now
|
||||||
|
n = coroutine.yield_past(chain[1], table.unpack(ret, 1, ret.n))
|
||||||
end
|
end
|
||||||
end, nil, nil, "pipe_handler")
|
end, nil, nil, "pipe_handler")
|
||||||
|
|
||||||
local pipe_index = r and 2 or 1
|
chain[r and 1 or 2] = cmd_proc
|
||||||
local cmd_index = r and 1 or 2
|
chain[r and 2 or 1] = pipe_proc
|
||||||
local chain = {[cmd_index]=cmd_proc, [pipe_index]=pipe_proc}
|
|
||||||
|
|
||||||
-- link the cmd and pipe proc io
|
-- link the cmd and pipe proc io
|
||||||
pipe.buildPipeChain(chain)
|
pipe.buildPipeChain(chain)
|
||||||
local cmd_stack = process.info(chain[1]).data.coroutine_handler
|
local cmd_data = process.info(chain[1]).data
|
||||||
|
local cmd_stack = cmd_data.coroutine_handler
|
||||||
|
|
||||||
-- store handle to io_stream from easy access later
|
-- store handle to io_stream from easy access later
|
||||||
stream.io_stream = process.info(chain[1]).data.io[1].stream
|
stream.io_stream = cmd_data.io[1].stream
|
||||||
stream.pco = cmd_stack
|
stream.pco = cmd_stack
|
||||||
|
|
||||||
-- popen commands start out running, like threads
|
-- popen commands start out running, like threads
|
||||||
|
@ -133,7 +133,7 @@ function sh.expand(value)
|
|||||||
end)
|
end)
|
||||||
:gsub("%${(.*)}", function(key)
|
:gsub("%${(.*)}", function(key)
|
||||||
if sh.internal.isIdentifier(key) then
|
if sh.internal.isIdentifier(key) then
|
||||||
return sh.internal.expandKey(key)
|
return os.getenv(key) or ''
|
||||||
end
|
end
|
||||||
io.stderr:write("${" .. key .. "}: bad substitution\n")
|
io.stderr:write("${" .. key .. "}: bad substitution\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
|
@ -42,10 +42,10 @@ function text.wrap(value, width, maxWidth)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function text.wrappedLines(value, width, maxWidth)
|
function text.wrappedLines(value, width, maxWidth)
|
||||||
local line, nl
|
local line
|
||||||
return function()
|
return function()
|
||||||
if value then
|
if value then
|
||||||
line, value, nl = text.wrap(value, width, maxWidth)
|
line, value = text.wrap(value, width, maxWidth)
|
||||||
return line
|
return line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -213,11 +213,11 @@ function thread.create(fp, ...)
|
|||||||
|
|
||||||
function mt.process.data.pull(_, timeout)
|
function mt.process.data.pull(_, timeout)
|
||||||
mt.register(timeout)
|
mt.register(timeout)
|
||||||
-- yield_all will yield this pco stack
|
-- yield_past(root) will yield until out of this thread
|
||||||
-- the callback will resume this stack
|
-- the callback will resume this stack
|
||||||
local event_data
|
local event_data
|
||||||
repeat
|
repeat
|
||||||
event_data = table.pack(t.pco.yield_all(timeout))
|
event_data = table.pack(t.pco.yield_past(t.pco.root, timeout))
|
||||||
-- during sleep, we may have been suspended
|
-- during sleep, we may have been suspended
|
||||||
until t:status() ~= "suspended"
|
until t:status() ~= "suspended"
|
||||||
return table.unpack(event_data, 1, event_data.n)
|
return table.unpack(event_data, 1, event_data.n)
|
||||||
|
@ -42,42 +42,7 @@ local function read_history(handler, cursor, change)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function tab_handler(handler, cursor)
|
function tty.key_down_handler(handler, cursor, char, code)
|
||||||
local hints = handler.hint
|
|
||||||
if not hints then return end
|
|
||||||
local main_kb = tty.keyboard()
|
|
||||||
-- tty may not have a keyboard
|
|
||||||
-- in which case, we shouldn't be handling tab events
|
|
||||||
if not main_kb then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not handler.cache then
|
|
||||||
handler.cache = type(hints) == "table" and hints or hints(cursor.data, cursor.index + 1) or {}
|
|
||||||
handler.cache.i = -1
|
|
||||||
end
|
|
||||||
|
|
||||||
local cache = handler.cache
|
|
||||||
|
|
||||||
if #cache == 1 and cache.i == 0 then
|
|
||||||
-- there was only one solution, and the user is asking for the next
|
|
||||||
handler.cache = hints(cache[1], cursor.index + 1)
|
|
||||||
if not handler.cache then return end
|
|
||||||
handler.cache.i = -1
|
|
||||||
cache = handler.cache
|
|
||||||
end
|
|
||||||
|
|
||||||
local change = kb.isShiftDown(main_kb) and -1 or 1
|
|
||||||
cache.i = (cache.i + change) % math.max(#cache, 1)
|
|
||||||
local next = cache[cache.i + 1]
|
|
||||||
if next then
|
|
||||||
local tail = unicode.len(cursor.data) - cursor.index
|
|
||||||
cursor:clear()
|
|
||||||
cursor:update(next)
|
|
||||||
cursor:move(-tail)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function key_down_handler(handler, cursor, char, code)
|
|
||||||
local c = false
|
local c = false
|
||||||
local backup_cache = handler.cache
|
local backup_cache = handler.cache
|
||||||
handler.cache = nil
|
handler.cache = nil
|
||||||
@ -86,7 +51,7 @@ local function key_down_handler(handler, cursor, char, code)
|
|||||||
return --close
|
return --close
|
||||||
elseif code == keys.tab then
|
elseif code == keys.tab then
|
||||||
handler.cache = backup_cache
|
handler.cache = backup_cache
|
||||||
tab_handler(handler, cursor)
|
tty.on_tab(handler, cursor)
|
||||||
elseif code == keys.enter or code == keys.numpadenter then
|
elseif code == keys.enter or code == keys.numpadenter then
|
||||||
cursor:move(math.huge)
|
cursor:move(math.huge)
|
||||||
cursor:draw("\n")
|
cursor:draw("\n")
|
||||||
@ -307,11 +272,6 @@ function tty.read(handler, cursor)
|
|||||||
checkArg(2, cursor, "table", "nil")
|
checkArg(2, cursor, "table", "nil")
|
||||||
|
|
||||||
handler.index = 0
|
handler.index = 0
|
||||||
handler.touch = handler.touch or "touch_handler"
|
|
||||||
handler.drag = handler.drag or "touch_handler"
|
|
||||||
handler.clipboard = handler.clipboard or "clipboard_handler"
|
|
||||||
handler.key_down = handler.key_down or key_down_handler
|
|
||||||
|
|
||||||
cursor = cursor or tty.internal.build_vertical_reader()
|
cursor = cursor or tty.internal.build_vertical_reader()
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
@ -329,11 +289,8 @@ function tty.read(handler, cursor)
|
|||||||
tty.drawText("^C\n")
|
tty.drawText("^C\n")
|
||||||
return false
|
return false
|
||||||
elseif address == main_kb or address == main_sc then
|
elseif address == main_kb or address == main_sc then
|
||||||
local handler_method = handler[name]
|
local handler_method = handler[name] or tty[name .. "_handler"]
|
||||||
if handler_method then
|
if handler_method then
|
||||||
if type(handler_method) == "string" then -- special hack to delay loading tty stuff
|
|
||||||
handler_method = tty[handler_method]
|
|
||||||
end
|
|
||||||
-- nil to end (close)
|
-- nil to end (close)
|
||||||
-- false to ignore
|
-- false to ignore
|
||||||
-- true-thy updates cursor
|
-- true-thy updates cursor
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
local tty = require("tty")
|
local tty = require("tty")
|
||||||
local unicode = require("unicode")
|
local unicode = require("unicode")
|
||||||
|
local kb = require("keyboard")
|
||||||
|
|
||||||
function tty.touch_handler(handler, cursor, gx, gy)
|
function tty.touch_handler(_, cursor, gx, gy)
|
||||||
if cursor.data == "" then
|
if cursor.data == "" then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -33,8 +34,9 @@ function tty.touch_handler(handler, cursor, gx, gy)
|
|||||||
end
|
end
|
||||||
return false -- no further cursor update
|
return false -- no further cursor update
|
||||||
end
|
end
|
||||||
|
tty.drag_handler = tty.touch_handler
|
||||||
|
|
||||||
function tty.clipboard_handler(handler, cursor, char, code)
|
function tty.clipboard_handler(handler, _, char, _)
|
||||||
handler.cache = nil
|
handler.cache = nil
|
||||||
local first_line, end_index = char:find("\13?\10")
|
local first_line, end_index = char:find("\13?\10")
|
||||||
if first_line then
|
if first_line then
|
||||||
@ -49,3 +51,38 @@ function tty.clipboard_handler(handler, cursor, char, code)
|
|||||||
return char
|
return char
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tty.on_tab(handler, cursor)
|
||||||
|
local hints = handler.hint
|
||||||
|
if not hints then return end
|
||||||
|
local main_kb = tty.keyboard()
|
||||||
|
-- tty may not have a keyboard
|
||||||
|
-- in which case, we shouldn't be handling tab events
|
||||||
|
if not main_kb then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not handler.cache then
|
||||||
|
handler.cache = type(hints) == "table" and hints or hints(cursor.data, cursor.index + 1) or {}
|
||||||
|
handler.cache.i = -1
|
||||||
|
end
|
||||||
|
|
||||||
|
local cache = handler.cache
|
||||||
|
|
||||||
|
if #cache == 1 and cache.i == 0 then
|
||||||
|
-- there was only one solution, and the user is asking for the next
|
||||||
|
handler.cache = hints(cache[1], cursor.index + 1)
|
||||||
|
if not handler.cache then return end
|
||||||
|
handler.cache.i = -1
|
||||||
|
cache = handler.cache
|
||||||
|
end
|
||||||
|
|
||||||
|
local change = kb.isShiftDown(main_kb) and -1 or 1
|
||||||
|
cache.i = (cache.i + change) % math.max(#cache, 1)
|
||||||
|
local next = cache[cache.i + 1]
|
||||||
|
if next then
|
||||||
|
local tail = unicode.len(cursor.data) - cursor.index
|
||||||
|
cursor:clear()
|
||||||
|
cursor:update(next)
|
||||||
|
cursor:move(-tail)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@ -13,17 +13,20 @@ DESCRIPTION
|
|||||||
|
|
||||||
Single quotes also suppress variable expansion. Per default, expressions like `$NAME` and `${NAME}` are expanded using environment variables (also accessible via the `os.getenv` method).
|
Single quotes also suppress variable expansion. Per default, expressions like `$NAME` and `${NAME}` are expanded using environment variables (also accessible via the `os.getenv` method).
|
||||||
|
|
||||||
Basic globbing is supported, i.e. '*' and '?' are expanded approriately. For example:
|
Globbing is supported, i.e. '*' and '?' are expanded approriately. For example:
|
||||||
ls b?n/
|
ls b?n/
|
||||||
will list all files in `/bin/` (and, if it exists `/ban` and so on).
|
will list all files in `/bin/` (and, if it exists `/ban` and so on).
|
||||||
cp /bin/* /usr/bin/
|
cp /bin/* /usr/bin/
|
||||||
will copy all files from `/bin` to `/usr/bin`.
|
will copy all files from `/bin` to `/usr/bin`.
|
||||||
|
|
||||||
The shell provides basic redirects and piping:
|
The shell provides redirects and piping:
|
||||||
cat f > f2
|
cat f > f2
|
||||||
copies the contents of file `f` to `f2`, for example.
|
copies the contents of file `f` to `f2`, for example.
|
||||||
echo 'this is a "test"' >> f2
|
echo 'this is a "test"' >> f2
|
||||||
will append the string 'this is a "test"' to the file `f2`.
|
will append the string 'this is a "test"' to the file `f2`.
|
||||||
|
2>/dev/null ./some_program_with_errors
|
||||||
|
will redirect all stderr to /dev/null [i.e. supress errors].
|
||||||
|
This example also demonstrates redirects can go at the front
|
||||||
|
|
||||||
Redirects can be combined:
|
Redirects can be combined:
|
||||||
cat < f >> f2
|
cat < f >> f2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user