mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 11:48:02 -04:00
fixed output rendering in term.write a bit; cleaned up shell execution logic a little (shell.execute now loads the $SHELL directly and runs it with the command that should be performed); added option for a read timeout to buffer:read; primitive variable expansion for default shell (no support for escaped quotes/brackets)
This commit is contained in:
parent
c71646569b
commit
05f6fcfebf
@ -134,7 +134,7 @@ class InternetCard extends ManagedComponent {
|
||||
def isTcpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled)
|
||||
|
||||
@Callback(doc = """function(address:string[, port:number]):number -- Opens a new TCP connection. Returns the handle of the connection.""")
|
||||
def connect(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
def connect(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val address = args.checkString(0)
|
||||
val port = if (args.count > 1) args.checkInteger(1) else -1
|
||||
if (!Settings.get.tcpEnabled) {
|
||||
@ -153,8 +153,8 @@ class InternetCard extends ManagedComponent {
|
||||
result(handle)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(handle:number) -- Closes an open socket stream.""")
|
||||
def close(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
@Callback(direct = true, doc = """function(handle:number) -- Closes an open socket stream.""")
|
||||
def close(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val handle = args.checkInteger(0)
|
||||
connections.remove(handle) match {
|
||||
case Some(socket) => socket.close()
|
||||
@ -164,7 +164,7 @@ class InternetCard extends ManagedComponent {
|
||||
}
|
||||
|
||||
@Callback(doc = """function(handle:number, data:string):number -- Tries to write data to the socket stream. Returns the number of bytes written.""")
|
||||
def write(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
def write(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val handle = args.checkInteger(0)
|
||||
val value = args.checkByteArray(1)
|
||||
connections.get(handle) match {
|
||||
@ -176,7 +176,7 @@ class InternetCard extends ManagedComponent {
|
||||
}
|
||||
|
||||
@Callback(doc = """function(handle:number, n:number):string -- Tries to read data from the socket stream. Returns the read byte array.""")
|
||||
def read(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
def read(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
|
||||
val handle = args.checkInteger(0)
|
||||
val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1)))
|
||||
connections.get(handle) match {
|
||||
@ -222,7 +222,7 @@ class InternetCard extends ManagedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
override def onDisconnect(node: Node) {
|
||||
override def onDisconnect(node: Node) = this.synchronized {
|
||||
super.onDisconnect(node)
|
||||
if (owner.isDefined && (node == this.node || node.host.isInstanceOf[Context] && (node.host.asInstanceOf[Context] == owner.get))) {
|
||||
owner = None
|
||||
@ -236,7 +236,7 @@ class InternetCard extends ManagedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
override def onMessage(message: Message) {
|
||||
override def onMessage(message: Message) = this.synchronized {
|
||||
super.onMessage(message)
|
||||
message.data match {
|
||||
case Array() if (message.name == "computer.stopped" || message.name == "computer.started") && owner.isDefined && message.source.address == owner.get.node.address =>
|
||||
|
@ -16,7 +16,7 @@ local args, options = shell.parse(...)
|
||||
local function get(pasteId, filename)
|
||||
local f, reason = io.open(filename, "w")
|
||||
if not f then
|
||||
io.stderr:write("Failed opening file for writing: ", reason)
|
||||
io.stderr:write("Failed opening file for writing: " .. reason)
|
||||
return
|
||||
end
|
||||
|
||||
@ -33,12 +33,12 @@ local function get(pasteId, filename)
|
||||
end
|
||||
|
||||
f:close()
|
||||
io.write("Saved data to ", filename, "\n")
|
||||
io.write("Saved data to " .. filename .. "\n")
|
||||
else
|
||||
io.write("failed.\n")
|
||||
f:close()
|
||||
fs.remove(filename)
|
||||
io.stderr:write("HTTP request failed: ", response, "\n")
|
||||
io.stderr:write("HTTP request failed: " .. response .. "\n")
|
||||
end
|
||||
end
|
||||
|
||||
@ -48,7 +48,7 @@ function encode(code)
|
||||
code = string.gsub(code, "([^%w ])", function (c)
|
||||
return string.format("%%%02X", string.byte(c))
|
||||
end)
|
||||
code = string.gsub (code, " ", "+")
|
||||
code = string.gsub(code, " ", "+")
|
||||
end
|
||||
return code
|
||||
end
|
||||
@ -74,14 +74,14 @@ function put(path)
|
||||
if configFile then
|
||||
local result, reason = pcall(configFile)
|
||||
if not result then
|
||||
io.stderr:write("Failed loading config: ", reason)
|
||||
io.stderr:write("Failed loading config: " .. reason)
|
||||
end
|
||||
end
|
||||
config.key = config.key or "fd92bd40a84c127eeb6804b146793c97"
|
||||
local file, reason = io.open(path, "r")
|
||||
|
||||
if not file then
|
||||
io.stderr:write("Failed opening file for reading: ", reason)
|
||||
io.stderr:write("Failed opening file for reading: " .. reason)
|
||||
return
|
||||
end
|
||||
|
||||
@ -109,8 +109,8 @@ function put(path)
|
||||
else
|
||||
io.write("success.\n")
|
||||
local pasteId = string.match(info, "[^/]+$")
|
||||
io.write("Uploaded as ", info, "\n")
|
||||
io.write('Run "pastebin get ', pasteId, '" to download anywhere.')
|
||||
io.write("Uploaded as " .. info .. "\n")
|
||||
io.write('Run "pastebin get ' .. pasteId .. '" to download anywhere.')
|
||||
end
|
||||
else
|
||||
io.write("failed.\n")
|
||||
|
@ -47,7 +47,7 @@ end
|
||||
|
||||
local f, reason = io.open(filename, "wb")
|
||||
if not f then
|
||||
io.stderr:write("failed opening file for writing: ", reason)
|
||||
io.stderr:write("failed opening file for writing: " .. reason)
|
||||
return
|
||||
end
|
||||
|
||||
@ -65,7 +65,7 @@ if result then
|
||||
|
||||
f:close()
|
||||
if not options.q then
|
||||
io.write("Saved data to ", filename, "\n")
|
||||
io.write("Saved data to " .. filename .. "\n")
|
||||
end
|
||||
else
|
||||
if not options.q then
|
||||
@ -73,5 +73,5 @@ else
|
||||
end
|
||||
f:close()
|
||||
fs.remove(filename)
|
||||
io.stderr:write("HTTP request failed: ", response, "\n")
|
||||
io.stderr:write("HTTP request failed: " .. response .. "\n")
|
||||
end
|
@ -109,13 +109,7 @@ function internet.socket(address, port)
|
||||
-- the __gc metamethod. So we start a timer to do the yield/cleanup.
|
||||
local function cleanup(self)
|
||||
if not self.handle then return end
|
||||
-- save non-gc'ed values as upvalues
|
||||
local inet = self.inet
|
||||
local handle = self.handle
|
||||
local function close()
|
||||
inet.close(handle)
|
||||
end
|
||||
event.timer(0, close)
|
||||
pcall(self.inet.close, self.handle)
|
||||
end
|
||||
local metatable = {__index = socketStream,
|
||||
__gc = cleanup,
|
||||
|
@ -4,7 +4,7 @@ local args = shell.parse(...)
|
||||
|
||||
if #args == 0 then
|
||||
for name, value in shell.aliases() do
|
||||
io.write(name, " ", value, "\n")
|
||||
io.write(name .. " " .. value .. "\n")
|
||||
end
|
||||
elseif #args == 1 then
|
||||
local value = shell.getAlias(args[1])
|
||||
@ -15,5 +15,5 @@ elseif #args == 1 then
|
||||
end
|
||||
else
|
||||
shell.setAlias(args[1], args[2])
|
||||
io.write("alias created: ", args[1], " -> ", args[2])
|
||||
io.write("alias created: " .. args[1] .. " -> " .. args[2])
|
||||
end
|
@ -253,7 +253,7 @@ local function execute(command, env, ...)
|
||||
for i = 1, #commands do
|
||||
local program, args, input, output, mode = table.unpack(commands[i])
|
||||
local reason
|
||||
threads[i], reason = shell.load(program, env, function()
|
||||
threads[i], reason = process.load(shell.resolve(program, "lua"), env, function()
|
||||
if input then
|
||||
local file, reason = io.open(shell.resolve(input))
|
||||
if not file then
|
||||
|
@ -1,5 +1,5 @@
|
||||
local component = require("component")
|
||||
|
||||
for address, name in component.list() do
|
||||
io.write(name, "\t", address, "\n")
|
||||
io.write(name .. "\t" .. address .. "\n")
|
||||
end
|
@ -18,7 +18,7 @@ for i = 1, #dirs do
|
||||
end
|
||||
local list, reason = fs.list(path)
|
||||
if not list then
|
||||
io.write(reason, "\n")
|
||||
io.write(reason .. "\n")
|
||||
else
|
||||
local function setColor(c)
|
||||
if component.gpu.getForeground() ~= c then
|
||||
@ -40,7 +40,7 @@ for i = 1, #dirs do
|
||||
setColor(0x99CCFF)
|
||||
for _, d in ipairs(lsd) do
|
||||
if options.a or d:sub(1, 1) ~= "." then
|
||||
io.write(d, "\t")
|
||||
io.write(d .. "\t")
|
||||
if options.l or io.output() ~= io.stdout then
|
||||
io.write("\n")
|
||||
end
|
||||
@ -55,7 +55,7 @@ for i = 1, #dirs do
|
||||
setColor(0xFFFFFF)
|
||||
end
|
||||
if options.a or f:sub(1, 1) ~= "." then
|
||||
io.write(f, "\t")
|
||||
io.write(f .. "\t")
|
||||
if options.l then
|
||||
setColor(0xFFFFFF)
|
||||
io.write(fs.size(fs.concat(path, f)), "\n")
|
||||
|
@ -16,11 +16,11 @@ local env = setmetatable({}, {__index = function(t, k)
|
||||
end})
|
||||
|
||||
component.gpu.setForeground(0xFFFFFF)
|
||||
io.write("Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio\n")
|
||||
term.write("Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio\n")
|
||||
component.gpu.setForeground(0xFFFF00)
|
||||
io.write("Enter a statement and hit enter to evaluate it.\n")
|
||||
io.write("Prefix an expression with '=' to show its value.\n")
|
||||
io.write("Press Ctrl+C to exit the interpreter.\n")
|
||||
term.write("Enter a statement and hit enter to evaluate it.\n")
|
||||
term.write("Prefix an expression with '=' to show its value.\n")
|
||||
term.write("Press Ctrl+C to exit the interpreter.\n")
|
||||
component.gpu.setForeground(0xFFFFFF)
|
||||
|
||||
while term.isAvailable() do
|
||||
@ -46,16 +46,16 @@ while term.isAvailable() do
|
||||
if type(result[2]) == "table" and result[2].reason == "terminated" then
|
||||
os.exit(result[2].code)
|
||||
end
|
||||
io.stderr:write(tostring(result[2]), "\n")
|
||||
io.stderr:write(tostring(result[2]) .. "\n")
|
||||
else
|
||||
for i = 2, result.n do
|
||||
io.write(text.serialize(result[i], true), "\t")
|
||||
term.write(text.serialize(result[i], true) .. "\t")
|
||||
end
|
||||
if result.n > 1 then
|
||||
io.write("\n")
|
||||
if term.getCursor() > 1 then
|
||||
term.write("\n")
|
||||
end
|
||||
end
|
||||
else
|
||||
io.stderr:write(reason, "\n")
|
||||
io.stderr:write(tostring(reason) .. "\n")
|
||||
end
|
||||
end
|
||||
|
@ -18,6 +18,6 @@ for i = 1, #args do
|
||||
reason = "unknown reason"
|
||||
end
|
||||
end
|
||||
io.stderr:write(path, ": ", reason, "\n")
|
||||
io.stderr:write(path .. ": " .. reason .. "\n")
|
||||
end
|
||||
end
|
||||
|
@ -50,8 +50,8 @@ if options.b then
|
||||
end
|
||||
rs.setBundledOutput(side, color, value)
|
||||
end
|
||||
io.write("in: ", rs.getBundledInput(side, color), "\n")
|
||||
io.write("out: ", rs.getBundledOutput(side, color))
|
||||
io.write("in: " .. rs.getBundledInput(side, color) .. "\n")
|
||||
io.write("out: " .. rs.getBundledOutput(side, color))
|
||||
else
|
||||
if #args > 1 then
|
||||
local value = args[2]
|
||||
@ -62,6 +62,6 @@ else
|
||||
end
|
||||
rs.setOutput(side, value)
|
||||
end
|
||||
io.write("in: ", rs.getInput(side), "\n")
|
||||
io.write("out: ", rs.getOutput(side))
|
||||
io.write("in: " .. rs.getInput(side) .. "\n")
|
||||
io.write("out: " .. rs.getOutput(side))
|
||||
end
|
||||
|
@ -9,6 +9,6 @@ end
|
||||
for i = 1, #args do
|
||||
local path = shell.resolve(args[i])
|
||||
if not os.remove(path) then
|
||||
io.stderr:write(path, ": no such file, or permission denied\n")
|
||||
io.stderr:write(path .. ": no such file, or permission denied\n")
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ local args = {...}
|
||||
|
||||
if #args < 1 then
|
||||
for k,v in pairs(os.getenv()) do
|
||||
io.write(k, "='", string.gsub(v, "'", [['"'"']]), "'\n")
|
||||
io.write(k .. "='" .. string.gsub(v, "'", [['"'"']]) .. "'\n")
|
||||
end
|
||||
else
|
||||
local count = 0
|
||||
|
@ -6,45 +6,133 @@ local shell = require("shell")
|
||||
local term = require("term")
|
||||
local text = require("text")
|
||||
|
||||
local args, options = shell.parse(...)
|
||||
local history = {}
|
||||
|
||||
if options.v or not process.running(2) then
|
||||
io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n")
|
||||
local function expand(value)
|
||||
return value:gsub("%$(%w+)", os.getenv):gsub("%$%b{}",
|
||||
function(match) return os.getenv(expand(match:sub(3, -2))) or match end)
|
||||
end
|
||||
|
||||
while true do
|
||||
if not term.isAvailable() then -- don't clear unless we lost the term
|
||||
while not term.isAvailable() do
|
||||
event.pull("term_available")
|
||||
end
|
||||
term.clear()
|
||||
if options.v then
|
||||
io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n")
|
||||
local function evaluate(value)
|
||||
local init, result = 1, ""
|
||||
repeat
|
||||
local match = value:match("^%b''", init)
|
||||
if match then -- single quoted string. no variable expansion.
|
||||
match = match:sub(2, -2)
|
||||
init = init + 2
|
||||
result = result .. match
|
||||
else
|
||||
match = value:match('^%b""', init)
|
||||
if match then -- double quoted string.
|
||||
match = match:sub(2, -2)
|
||||
init = init + 2
|
||||
else
|
||||
-- plaintext?
|
||||
match = value:match("^([^']+)%b''", init)
|
||||
if not match then -- unmatched single quote.
|
||||
match = value:match('^([^"]+)%b""', init)
|
||||
if not match then -- unmatched double quote.
|
||||
match = value:sub(init)
|
||||
end
|
||||
end
|
||||
end
|
||||
result = result .. expand(match)
|
||||
end
|
||||
init = init + #match
|
||||
until init > #value
|
||||
return result
|
||||
end
|
||||
|
||||
local function execute(command, ...)
|
||||
local parts, reason = text.tokenize(command)
|
||||
if not parts then
|
||||
return false, reason
|
||||
elseif #parts == 0 then
|
||||
return true
|
||||
end
|
||||
while term.isAvailable() do
|
||||
local foreground = component.gpu.setForeground(0xFF0000)
|
||||
term.write(os.getenv("PS1") or "# ")
|
||||
component.gpu.setForeground(foreground)
|
||||
local command = term.read(history)
|
||||
if not command then
|
||||
io.write("exit\n")
|
||||
return -- eof
|
||||
end
|
||||
while #history > 10 do
|
||||
table.remove(history, 1)
|
||||
end
|
||||
command = text.trim(command)
|
||||
if command == "exit" then
|
||||
return
|
||||
elseif command ~= "" then
|
||||
local result, reason = os.execute(command)
|
||||
if not result then
|
||||
io.stderr:write(reason .. "\n")
|
||||
elseif term.getCursor() > 1 then
|
||||
io.write("\n")
|
||||
local program, args = shell.resolveAlias(parts[1], table.pack(select(2, table.unpack(parts))))
|
||||
program = evaluate(program)
|
||||
local program, reason = shell.resolve(program, "lua")
|
||||
if not program then
|
||||
return false, reason
|
||||
end
|
||||
for i = 1, args.n do
|
||||
args[i] = evaluate(args[i])
|
||||
end
|
||||
for _, arg in ipairs(table.pack(...)) do
|
||||
table.insert(args, arg)
|
||||
end
|
||||
table.insert(args, 1, true)
|
||||
args.n = #args
|
||||
local thread, reason = process.load(shell.resolve(program, "lua"), env, nil, command)
|
||||
if not thread then
|
||||
return false, reason
|
||||
end
|
||||
local result = nil
|
||||
-- Emulate CC behavior by making yields a filtered event.pull()
|
||||
while args[1] and coroutine.status(thread) ~= "dead" do
|
||||
result = table.pack(coroutine.resume(thread, table.unpack(args, 2, args.n)))
|
||||
if coroutine.status(thread) ~= "dead" then
|
||||
if type(result[2]) == "string" then
|
||||
args = table.pack(pcall(event.pull, table.unpack(result, 2, result.n)))
|
||||
else
|
||||
args = {true, n=1}
|
||||
end
|
||||
end
|
||||
end
|
||||
if not args[1] then
|
||||
return false, args[2]
|
||||
end
|
||||
if not result[1] and type(result[2]) == "table" and result[2].reason == "terminated" then
|
||||
if result[2].code then
|
||||
return true
|
||||
else
|
||||
return false, "terminated"
|
||||
end
|
||||
end
|
||||
return table.unpack(result, 1, result.n)
|
||||
end
|
||||
|
||||
local args, options = shell.parse(...)
|
||||
local history = {}
|
||||
|
||||
if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then
|
||||
-- interactive shell.
|
||||
while true do
|
||||
if not term.isAvailable() then -- don't clear unless we lost the term
|
||||
while not term.isAvailable() do
|
||||
event.pull("term_available")
|
||||
end
|
||||
term.clear()
|
||||
end
|
||||
while term.isAvailable() do
|
||||
local foreground = component.gpu.setForeground(0xFF0000)
|
||||
term.write(expand(os.getenv("PS1") or "$ "))
|
||||
component.gpu.setForeground(foreground)
|
||||
local command = term.read(history)
|
||||
if not command then
|
||||
term.write("exit\n")
|
||||
return -- eof
|
||||
end
|
||||
while #history > 10 do
|
||||
table.remove(history, 1)
|
||||
end
|
||||
command = text.trim(command)
|
||||
if command == "exit" then
|
||||
return
|
||||
elseif command ~= "" then
|
||||
local result, reason = execute(command)
|
||||
if not result then
|
||||
io.stderr:write(reason .. "\n")
|
||||
elseif term.getCursor() > 1 then
|
||||
term.write("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- execute command.
|
||||
local result = table.pack(execute(table.unpack(args)))
|
||||
if not result[1] then
|
||||
error(result[2])
|
||||
end
|
||||
return table.unpack(result, 2)
|
||||
end
|
@ -11,5 +11,5 @@ if not result then
|
||||
io.stderr:write("no such alias")
|
||||
else
|
||||
shell.setAlias(args[1], nil)
|
||||
io.write("alias removed: ", args[1], " -> ", result)
|
||||
io.write("alias removed: " .. args[1] .. " -> " .. result)
|
||||
end
|
@ -14,8 +14,8 @@ for i = 1, #args do
|
||||
result, reason = shell.resolve(args[i], "lua")
|
||||
end
|
||||
if result then
|
||||
io.write(result, "\n")
|
||||
io.write(result .. "\n")
|
||||
else
|
||||
io.stderr:write(args[i], ": ", reason, "\n")
|
||||
io.stderr:write(args[i] .. ": " .. reason .. "\n")
|
||||
end
|
||||
end
|
@ -1,17 +1,20 @@
|
||||
local component = require("component")
|
||||
local computer = require("computer")
|
||||
local event = require("event")
|
||||
|
||||
for c, t in component.list() do
|
||||
computer.pushSignal("component_added", c, t)
|
||||
end
|
||||
os.sleep(0.5) -- Allow signal processing by libraries.
|
||||
|
||||
require("term").clear()
|
||||
|
||||
computer.pushSignal("init") -- so libs know components are initialized.
|
||||
|
||||
while true do
|
||||
local result, reason = os.execute(os.getenv("SHELL"))
|
||||
require("term").clear()
|
||||
io.write(_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)\n")
|
||||
local result, reason = os.execute(os.getenv("SHELL") .. " -")
|
||||
if not result then
|
||||
print(reason)
|
||||
io.stderr:write((reason or "unknown error") .. "\n")
|
||||
print("Press any key to continue.")
|
||||
event.pull("key")
|
||||
end
|
||||
end
|
@ -10,7 +10,8 @@ function buffer.new(mode, stream)
|
||||
bufferRead = "",
|
||||
bufferWrite = "",
|
||||
bufferSize = math.max(512, math.min(8 * 1024, computer.freeMemory() / 8)),
|
||||
bufferMode = "full"
|
||||
bufferMode = "full",
|
||||
readTimeout = math.huge
|
||||
}
|
||||
mode = mode or "r"
|
||||
for i = 1, unicode.len(mode) do
|
||||
@ -58,7 +59,12 @@ function buffer:lines(...)
|
||||
end
|
||||
|
||||
function buffer:read(...)
|
||||
local timeout = computer.uptime() + self.readTimeout
|
||||
|
||||
local function readChunk()
|
||||
if computer.uptime() > timeout then
|
||||
error("timeout")
|
||||
end
|
||||
local result, reason = self.stream:read(self.bufferSize)
|
||||
if result then
|
||||
self.bufferRead = self.bufferRead .. result
|
||||
@ -213,6 +219,14 @@ function buffer:setvbuf(mode, size)
|
||||
return self.bufferMode, self.bufferSize
|
||||
end
|
||||
|
||||
function buffer:getTimeout()
|
||||
return self.readTimeout
|
||||
end
|
||||
|
||||
function buffer:setTimeout(value)
|
||||
self.readTimeout = tonumber(value)
|
||||
end
|
||||
|
||||
function buffer:write(...)
|
||||
if self.closed then
|
||||
return nil, "bad file descriptor"
|
||||
|
@ -1,7 +1,8 @@
|
||||
local event = require("event")
|
||||
local fs = require("filesystem")
|
||||
local unicode = require("unicode")
|
||||
local process = require("process")
|
||||
local text = require("text")
|
||||
local unicode = require("unicode")
|
||||
|
||||
local shell = {}
|
||||
local aliases = {}
|
||||
@ -130,39 +131,11 @@ function shell.resolve(path, ext)
|
||||
end
|
||||
|
||||
function shell.execute(command, env, ...)
|
||||
checkArg(1, command, "string")
|
||||
local parts, reason = text.tokenize(command)
|
||||
if not parts then
|
||||
local sh, reason = loadfile(shell.resolve(os.getenv("SHELL"), "lua"), "t", env)
|
||||
if not sh then
|
||||
return false, reason
|
||||
end
|
||||
if #parts == 0 then
|
||||
return true
|
||||
end
|
||||
local program, args = shell.resolveAlias(parts[1], table.pack(select(2, table.unpack(parts))))
|
||||
table.insert(args, 1, true)
|
||||
for _, arg in ipairs(table.pack(...)) do
|
||||
table.insert(args, arg)
|
||||
end
|
||||
args.n = #args
|
||||
local thread, reason = shell.load(program, env, nil, command)
|
||||
if not thread then
|
||||
return false, reason
|
||||
end
|
||||
local result = nil
|
||||
-- Emulate CC behavior by making yields a filtered event.pull()
|
||||
while args[1] and coroutine.status(thread) ~= "dead" do
|
||||
result = table.pack(coroutine.resume(thread, table.unpack(args, 2, args.n)))
|
||||
if coroutine.status(thread) ~= "dead" then
|
||||
if type(result[2]) == "string" then
|
||||
args = table.pack(pcall(event.pull, table.unpack(result, 2, result.n)))
|
||||
else
|
||||
args = {true, n=1}
|
||||
end
|
||||
end
|
||||
end
|
||||
if not args[1] then
|
||||
return false, args[2]
|
||||
end
|
||||
local result = table.pack(pcall(sh, command, ...))
|
||||
if not result[1] and type(result[2]) == "table" and result[2].reason == "terminated" then
|
||||
if result[2].code then
|
||||
return true
|
||||
@ -173,21 +146,15 @@ function shell.execute(command, env, ...)
|
||||
return table.unpack(result, 1, result.n)
|
||||
end
|
||||
|
||||
function shell.load(path, env, init, name)
|
||||
local path, reason = shell.resolve(path, "lua")
|
||||
if not path then
|
||||
return nil, reason
|
||||
end
|
||||
return require("process").load(path, env, init, name)
|
||||
end
|
||||
|
||||
function shell.parse(...)
|
||||
local params = table.pack(...)
|
||||
local args = {}
|
||||
local options = {}
|
||||
for i = 1, params.n do
|
||||
local param = params[i]
|
||||
if unicode.sub(param, 1, 1) == "-" then
|
||||
if type(param) == "string" and unicode.sub(param, 1, 2) == "--" then
|
||||
options[unicode.sub(param, 3)] = true
|
||||
elseif type(param) == "string" and unicode.sub(param, 1, 1) == "-" then
|
||||
for j = 2, unicode.len(param) do
|
||||
options[unicode.sub(param, j, j)] = true
|
||||
end
|
||||
|
@ -340,12 +340,14 @@ function term.write(value, wrap)
|
||||
term.setCursorBlink(false)
|
||||
local line, nl = value
|
||||
repeat
|
||||
local wrapAfter, margin = math.huge, math.huge
|
||||
if wrap then
|
||||
line, value, nl = text.wrap(value, w - (cursorX - 1), w)
|
||||
wrapAfter, margin = w - (cursorX - 1), w
|
||||
end
|
||||
line, value, nl = text.wrap(value, wrapAfter, margin)
|
||||
component.gpu.set(cursorX, cursorY, line)
|
||||
cursorX = cursorX + unicode.len(line)
|
||||
if nl or cursorX > w then
|
||||
if nl or (cursorX > w and wrap) then
|
||||
cursorX = 1
|
||||
cursorY = cursorY + 1
|
||||
end
|
||||
|
@ -10,7 +10,8 @@ function text.detab(value, tabWidth)
|
||||
local spaces = tabWidth - match:len() % tabWidth
|
||||
return match .. string.rep(" ", spaces)
|
||||
end
|
||||
return value:gsub("([^\n]-)\t", rep)
|
||||
local result = value:gsub("([^\n]-)\t", rep) -- truncate results
|
||||
return result
|
||||
end
|
||||
|
||||
function text.padRight(value, length)
|
||||
@ -43,6 +44,7 @@ end
|
||||
function text.wrap(value, width, maxWidth)
|
||||
checkArg(1, value, "string")
|
||||
checkArg(2, width, "number")
|
||||
checkArg(3, maxWidth, "number")
|
||||
local line, nl = value:match("([^\r\n]*)([\r\n]?)") -- read until newline
|
||||
if unicode.len(line) > width then -- do we even need to wrap?
|
||||
local partial = unicode.sub(line, 1, width)
|
||||
|
Loading…
x
Reference in New Issue
Block a user