mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 02:39:48 -04:00
Merge branch master-MC1.11 into master-MC1.12
This commit is contained in:
commit
18592726c4
@ -86,6 +86,8 @@ to create an IntelliJ IDEA project.
|
||||
|
||||
Open the project and you will be asked to *import the Gradle project* (check your Event Log if you missed the pop-up). **Do so**. This will configure additionally referenced libraries.
|
||||
|
||||
For more specific instructions, read [Steps to run master MC1.7.10 from IDEA][idea_1.7.10]
|
||||
|
||||
In the case you wish to use Eclipse rather than IntelliJ IDEA, the process is mostly the same, except you must run `gradlew eclipse` rather than `gradlew idea`.
|
||||
|
||||
|
||||
@ -108,3 +110,4 @@ In the case you wish to use Eclipse rather than IntelliJ IDEA, the process is mo
|
||||
[wiki]: http://ocdoc.cil.li/
|
||||
[integration]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/scala/li/cil/oc/integration
|
||||
[ingame manual]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/doc
|
||||
[idea_1.7.10]: http://ocdoc.cil.li/tutorial:debug_1.7.10
|
@ -1,15 +1,34 @@
|
||||
local fs = require("filesystem")
|
||||
local shell = require("shell")
|
||||
|
||||
local args, ops = shell.parse(...)
|
||||
local argc = #args
|
||||
local function usage()
|
||||
io.stderr:write([==[
|
||||
Usage: mount [OPTIONS] [device path]")
|
||||
If no args are given, all current mount points are printed.
|
||||
<Options> Note that multiple options can be used together
|
||||
-r, --ro Mount the filesystem read only
|
||||
--bind Create a mount bind point, folder to folder
|
||||
<Args>
|
||||
device Specify filesystem device by one of:
|
||||
a. label
|
||||
b. address (can be abbreviated)
|
||||
c. folder path (requires --bind)
|
||||
path Target folder path to mount to
|
||||
|
||||
if ops and (ops.h or ops.help) then
|
||||
print("see `man mount` for help");
|
||||
See `man mount` for more details
|
||||
]==])
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
if argc == 0 then
|
||||
-- smart parse, follow arg after -o
|
||||
local args, opts = shell.parse(...)
|
||||
opts.readonly = opts.r or opts.readonly
|
||||
|
||||
if opts.h or opts.help then
|
||||
usage()
|
||||
end
|
||||
|
||||
local function print_mounts()
|
||||
-- for each mount
|
||||
local mounts = {}
|
||||
|
||||
@ -38,29 +57,40 @@ if argc == 0 then
|
||||
local rw_ro = "(" .. device.rw_ro .. ")"
|
||||
local fs_label = "\"" .. device.fs_label .. "\""
|
||||
|
||||
io.write(string.format("%s on %-10s %s %s\n",
|
||||
io.write(string.format("%-8s on %-10s %s %s\n",
|
||||
dev_path:sub(1,8),
|
||||
device.mount_path,
|
||||
rw_ro,
|
||||
fs_label))
|
||||
end
|
||||
end
|
||||
elseif argc ~= 2 then
|
||||
print("Usage: mount [<label|address> <path>]")
|
||||
print("Note that the address may be abbreviated.")
|
||||
return 1 -- error code
|
||||
else
|
||||
local proxy, reason = fs.proxy(args[1])
|
||||
end
|
||||
|
||||
local function do_mount()
|
||||
-- bind converts a path to a proxy
|
||||
local proxy, reason = fs.proxy(args[1], opts)
|
||||
if not proxy then
|
||||
io.stderr:write(reason,"\n")
|
||||
return 1
|
||||
elseif ops.r then
|
||||
proxy = dofile("/lib/core/ro_wrapper.lua").wrap(proxy)
|
||||
io.stderr:write("Failed to mount: ", tostring(reason), "\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local result, mount_failure = fs.mount(proxy, shell.resolve(args[2]))
|
||||
if not result then
|
||||
io.stderr:write(mount_failure, "\n")
|
||||
return 2 -- error code
|
||||
os.exit(2) -- error code
|
||||
end
|
||||
end
|
||||
|
||||
if #args == 0 then
|
||||
if next(opts) then
|
||||
io.stderr:write("Missing argument\n")
|
||||
usage()
|
||||
else
|
||||
print_mounts()
|
||||
end
|
||||
elseif #args == 2 then
|
||||
do_mount()
|
||||
else
|
||||
io.stderr:write("wrong number of arguments: ", #args, "\n")
|
||||
usage()
|
||||
end
|
||||
|
@ -17,13 +17,20 @@ if not file then
|
||||
return 1
|
||||
end
|
||||
|
||||
local current_data = process.info().data
|
||||
local lines = file:lines()
|
||||
|
||||
local source_proc = process.load((assert(os.getenv("SHELL"), "no $SHELL set")))
|
||||
local source_data = process.list[source_proc].data
|
||||
source_data.aliases = current_data.aliases -- hacks to propogate sub shell env changes
|
||||
source_data.vars = current_data.vars
|
||||
source_data.io[0] = file -- set stdin to the file
|
||||
process.internal.continue(source_proc, "-c")
|
||||
while true do
|
||||
local line = lines()
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
local current_data = process.info().data
|
||||
|
||||
file:close() -- should have closed when the process closed, but just to be sure
|
||||
local source_proc = process.load((assert(os.getenv("SHELL"), "no $SHELL set")))
|
||||
local source_data = process.list[source_proc].data
|
||||
source_data.aliases = current_data.aliases -- hacks to propogate sub shell env changes
|
||||
source_data.vars = current_data.vars
|
||||
process.internal.continue(source_proc, _ENV, line)
|
||||
end
|
||||
|
||||
file:close()
|
||||
|
@ -62,5 +62,5 @@ os.setenv("TMP", "/tmp") -- Deprecated
|
||||
os.setenv("TMPDIR", "/tmp")
|
||||
|
||||
if computer.tmpAddress() then
|
||||
fs.mount(computer.tmpAddress(), os.getenv("TMPDIR") or "/tmp")
|
||||
fs.mount(computer.tmpAddress(), "/tmp")
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ local core_stderr = buffer.new("w", setmetatable(
|
||||
write = function(_, str)
|
||||
return tty_stream:write("\27[31m"..str.."\27[37m")
|
||||
end
|
||||
}, {__index=tty_stream}))
|
||||
}, {__index=tty_stream}))
|
||||
|
||||
core_stdout:setvbuf("no")
|
||||
core_stderr:setvbuf("no")
|
||||
|
@ -1,29 +1,13 @@
|
||||
local component = require("component")
|
||||
local event = require("event")
|
||||
local fs = require("filesystem")
|
||||
local shell = require("shell")
|
||||
local tmp = require("computer").tmpAddress()
|
||||
|
||||
local isInitialized, pendingAutoruns = false, {}
|
||||
|
||||
local function onInit()
|
||||
isInitialized = true
|
||||
for _, run in ipairs(pendingAutoruns) do
|
||||
local result, reason = pcall(run)
|
||||
if not result then
|
||||
local path = fs.concat(os.getenv("TMPDIR") or "/tmp", "event.log")
|
||||
local log = io.open(path, "a")
|
||||
if log then
|
||||
log:write(tostring(result) .. ":" .. tostring(reason) .. "\n")
|
||||
log:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
pendingAutoruns = nil
|
||||
end
|
||||
local pendingAutoruns = {}
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "filesystem" and require("computer").tmpAddress() ~= address then
|
||||
local proxy = component.proxy(address)
|
||||
if componentType == "filesystem" and tmp ~= address then
|
||||
local proxy = fs.proxy(address)
|
||||
if proxy then
|
||||
local name = address:sub(1, 3)
|
||||
while fs.exists(fs.concat("/mnt", name)) and
|
||||
@ -37,13 +21,11 @@ local function onComponentAdded(_, address, componentType)
|
||||
local file = shell.resolve(fs.concat(name, "autorun"), "lua") or
|
||||
shell.resolve(fs.concat(name, ".autorun"), "lua")
|
||||
if file then
|
||||
local run = function()
|
||||
assert(shell.execute(file, _ENV, proxy))
|
||||
end
|
||||
if isInitialized then
|
||||
run()
|
||||
else
|
||||
local run = {file, _ENV, proxy}
|
||||
if pendingAutoruns then
|
||||
table.insert(pendingAutoruns, run)
|
||||
else
|
||||
xpcall(shell.execute, event.onError, table.unpack(run))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -60,7 +42,14 @@ local function onComponentRemoved(_, address, componentType)
|
||||
end
|
||||
end
|
||||
|
||||
event.listen("init", onInit)
|
||||
event.listen("init", function()
|
||||
for _, run in ipairs(pendingAutoruns) do
|
||||
xpcall(shell.execute, event.onError, table.unpack(run))
|
||||
end
|
||||
pendingAutoruns = nil
|
||||
return false
|
||||
end)
|
||||
|
||||
event.listen("component_added", onComponentAdded)
|
||||
event.listen("component_removed", onComponentRemoved)
|
||||
|
||||
|
@ -1,35 +1,38 @@
|
||||
local component = require("component")
|
||||
local computer = require("computer")
|
||||
local text = require("text")
|
||||
local unicode = require("unicode")
|
||||
local tty = require("tty")
|
||||
|
||||
if not component.isAvailable("gpu") then
|
||||
return
|
||||
end
|
||||
local lines = {_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)"}
|
||||
local maxWidth = unicode.len(lines[1])
|
||||
|
||||
local f = io.open("/usr/misc/greetings.txt")
|
||||
local lines = {_OSVERSION .. " (" .. math.floor(computer.totalMemory() / 1024) .. "k RAM)"}
|
||||
local greeting = ""
|
||||
if f then
|
||||
local greetings = {}
|
||||
pcall(function()
|
||||
for line in f:lines() do table.insert(greetings, line) end
|
||||
end)
|
||||
f:close()
|
||||
local greeting = greetings[math.random(1, #greetings)]
|
||||
if greeting then
|
||||
local width = math.max(10, tty.getViewport())
|
||||
for line in text.wrappedLines(greeting, width - 4, width - 4) do
|
||||
table.insert(lines, line)
|
||||
maxWidth = math.max(maxWidth, unicode.len(line))
|
||||
end
|
||||
end
|
||||
greeting = greetings[math.random(1, math.max(#greetings, 1))] or ""
|
||||
end
|
||||
local width = math.min(#greeting, tty.getViewport() - 5)
|
||||
local maxLine = #lines[1]
|
||||
while #greeting > 0 do
|
||||
local si, ei = greeting:sub(1, width):find("%s%S*$")
|
||||
local line = #greeting <= width and greeting or greeting:sub(1, si or width)
|
||||
lines[#lines + 1] = line
|
||||
maxLine = math.max(maxLine, #line)
|
||||
greeting = greeting:sub(#line + 1)
|
||||
end
|
||||
|
||||
local borders = {{unicode.char(0x2552), unicode.char(0x2550), unicode.char(0x2555)},
|
||||
{unicode.char(0x2502), nil, unicode.char(0x2502)},
|
||||
{unicode.char(0x2514), unicode.char(0x2500), unicode.char(0x2518)}}
|
||||
io.write(borders[1][1] .. string.rep(borders[1][2], maxWidth + 2) .. borders[1][3] .. "\n")
|
||||
for _, line in ipairs(lines) do
|
||||
io.write(borders[2][1] .. " " .. text.padRight(line, maxWidth) .. " " .. borders[2][3] .. "\n")
|
||||
io.write(borders[1][1], string.rep(borders[1][2], maxLine + 2), borders[1][3], "\n")
|
||||
for _,line in ipairs(lines) do
|
||||
io.write(borders[2][1], " ", line, (" "):rep(maxLine - #line + 1), borders[2][3], " \n")
|
||||
end
|
||||
io.write(borders[3][1] .. string.rep(borders[3][2], maxWidth + 2) .. borders[3][3] .. "\n")
|
||||
io.write(borders[3][1] .. string.rep(borders[3][2], maxLine + 2) .. borders[3][3] .. "\n")
|
||||
|
@ -39,14 +39,8 @@ function buffer:flush()
|
||||
local tmp = self.bufferWrite
|
||||
self.bufferWrite = ""
|
||||
local result, reason = self.stream:write(tmp)
|
||||
if result then
|
||||
self.bufferWrite = ""
|
||||
else
|
||||
if reason then
|
||||
return nil, reason
|
||||
else
|
||||
return nil, "bad file descriptor"
|
||||
end
|
||||
if not result then
|
||||
return nil, reason or "bad file descriptor"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
-- called from /init.lua
|
||||
local raw_loadfile = ...
|
||||
|
||||
_G._OSVERSION = "OpenOS 1.6.8"
|
||||
_G._OSVERSION = "OpenOS 1.7.1"
|
||||
|
||||
local component = component
|
||||
local computer = computer
|
||||
|
@ -0,0 +1,61 @@
|
||||
local event = require("event")
|
||||
|
||||
local function createMultipleFilter(...)
|
||||
local filter = table.pack(...)
|
||||
if filter.n == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return function(...)
|
||||
local signal = table.pack(...)
|
||||
if type(signal[1]) ~= "string" then
|
||||
return false
|
||||
end
|
||||
for i = 1, filter.n do
|
||||
if filter[i] ~= nil and signal[1]:match(filter[i]) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function event.pullMultiple(...)
|
||||
local seconds
|
||||
local args
|
||||
if type(...) == "number" then
|
||||
seconds = ...
|
||||
args = table.pack(select(2,...))
|
||||
for i=1,args.n do
|
||||
checkArg(i+1, args[i], "string", "nil")
|
||||
end
|
||||
else
|
||||
args = table.pack(...)
|
||||
for i=1,args.n do
|
||||
checkArg(i, args[i], "string", "nil")
|
||||
end
|
||||
end
|
||||
return event.pullFiltered(seconds, createMultipleFilter(table.unpack(args, 1, args.n)))
|
||||
end
|
||||
|
||||
function event.cancel(timerId)
|
||||
checkArg(1, timerId, "number")
|
||||
if handlers[timerId] then
|
||||
handlers[timerId] = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function event.ignore(name, callback)
|
||||
checkArg(1, name, "string")
|
||||
checkArg(2, callback, "function")
|
||||
for id, handler in pairs(handlers) do
|
||||
if handler.key == name and handler.callback == callback then
|
||||
handlers[id] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
local filesystem = require("filesystem")
|
||||
local component = require("component")
|
||||
|
||||
function filesystem.makeDirectory(path)
|
||||
if filesystem.exists(path) then
|
||||
@ -136,3 +137,102 @@ function filesystem.copy(fromPath, toPath)
|
||||
return data == nil, reason
|
||||
end
|
||||
|
||||
local function readonly_wrap(proxy)
|
||||
checkArg(1, proxy, "table")
|
||||
if proxy.isReadOnly() then
|
||||
return proxy
|
||||
end
|
||||
|
||||
local function roerr() return nil, "filesystem is readonly" end
|
||||
return setmetatable({
|
||||
rename = roerr,
|
||||
open = function(path, mode)
|
||||
checkArg(1, path, "string")
|
||||
checkArg(2, mode, "string")
|
||||
if mode:match("[wa]") then
|
||||
return roerr()
|
||||
end
|
||||
return proxy.open(path, mode)
|
||||
end,
|
||||
isReadOnly = function()
|
||||
return true
|
||||
end,
|
||||
write = roerr,
|
||||
setLabel = roerr,
|
||||
makeDirectory = roerr,
|
||||
remove = roerr,
|
||||
}, {__index=proxy})
|
||||
end
|
||||
|
||||
local function bind_proxy(path)
|
||||
local real, reason = filesystem.realPath(path)
|
||||
if not real then
|
||||
return nil, reason
|
||||
end
|
||||
if not filesystem.isDirectory(real) then
|
||||
return nil, "must bind to a directory"
|
||||
end
|
||||
local real_fs, real_fs_path = filesystem.get(real)
|
||||
if real == real_fs_path then
|
||||
return real_fs
|
||||
end
|
||||
-- turn /tmp/foo into foo
|
||||
local rest = real:sub(#real_fs_path + 1)
|
||||
local function wrap_relative(fp)
|
||||
return function(path, ...)
|
||||
return fp(filesystem.concat(rest, path), ...)
|
||||
end
|
||||
end
|
||||
local bind = {
|
||||
type = "filesystem_bind",
|
||||
address = real,
|
||||
isReadOnly = real_fs.isReadOnly,
|
||||
list = wrap_relative(real_fs.list),
|
||||
isDirectory = wrap_relative(real_fs.isDirectory),
|
||||
size = wrap_relative(real_fs.size),
|
||||
lastModified = wrap_relative(real_fs.lastModified),
|
||||
exists = wrap_relative(real_fs.exists),
|
||||
open = wrap_relative(real_fs.open),
|
||||
remove = wrap_relative(real_fs.remove),
|
||||
read = real_fs.read,
|
||||
write = real_fs.write,
|
||||
close = real_fs.close,
|
||||
getLabel = function() return "" end,
|
||||
setLabel = function() return nil, "cannot set the label of a bind point" end,
|
||||
}
|
||||
return bind
|
||||
end
|
||||
|
||||
filesystem.internal = {}
|
||||
function filesystem.internal.proxy(filter, options)
|
||||
checkArg(1, filter, "string")
|
||||
checkArg(2, options, "table", "nil")
|
||||
options = options or {}
|
||||
local address, proxy, reason
|
||||
if options.bind then
|
||||
proxy, reason = bind_proxy(filter)
|
||||
else
|
||||
-- no options: filter should be a label or partial address
|
||||
for c in component.list("filesystem", true) do
|
||||
if component.invoke(c, "getLabel") == filter then
|
||||
address = c
|
||||
break
|
||||
end
|
||||
if c:sub(1, filter:len()) == filter then
|
||||
address = c
|
||||
break
|
||||
end
|
||||
end
|
||||
if not address then
|
||||
return nil, "no such file system"
|
||||
end
|
||||
proxy, reason = component.proxy(address)
|
||||
end
|
||||
if not proxy then
|
||||
return proxy, reason
|
||||
end
|
||||
if options.readonly then
|
||||
proxy = readonly_wrap(proxy)
|
||||
end
|
||||
return proxy
|
||||
end
|
||||
|
@ -244,3 +244,43 @@ function text.padLeft(value, length)
|
||||
return string.rep(" ", length - unicode.wlen(value)) .. value
|
||||
end
|
||||
end
|
||||
|
||||
function text.padRight(value, length)
|
||||
checkArg(1, value, "string", "nil")
|
||||
checkArg(2, length, "number")
|
||||
if not value or unicode.wlen(value) == 0 then
|
||||
return string.rep(" ", length)
|
||||
else
|
||||
return value .. string.rep(" ", length - unicode.wlen(value))
|
||||
end
|
||||
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.wlen(line) > width then -- do we even need to wrap?
|
||||
local partial = unicode.wtrunc(line, width)
|
||||
local wrapped = partial:match("(.*[^a-zA-Z0-9._()'`=])")
|
||||
if wrapped or unicode.wlen(line) > maxWidth then
|
||||
partial = wrapped or partial
|
||||
return partial, unicode.sub(value, unicode.len(partial) + 1), true
|
||||
else
|
||||
return "", value, true -- write in new line.
|
||||
end
|
||||
end
|
||||
local start = unicode.len(line) + unicode.len(nl) + 1
|
||||
return line, start <= unicode.len(value) and unicode.sub(value, start) or nil, unicode.len(nl) > 0
|
||||
end
|
||||
|
||||
function text.wrappedLines(value, width, maxWidth)
|
||||
local line
|
||||
return function()
|
||||
if value then
|
||||
line, value = text.wrap(value, width, maxWidth)
|
||||
return line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -0,0 +1,93 @@
|
||||
local vt100 = require("vt100")
|
||||
|
||||
local rules = vt100.rules
|
||||
|
||||
-- [?7[hl] wrap mode
|
||||
rules[{"%[", "%?", "7", "[hl]"}] = function(window, _, _, _, nowrap)
|
||||
window.nowrap = nowrap == "l"
|
||||
end
|
||||
|
||||
-- helper scroll function
|
||||
local function set_cursor(window, x, y)
|
||||
window.x = math.min(math.max(x, 1), window.width)
|
||||
window.y = math.min(math.max(y, 1), window.height)
|
||||
end
|
||||
|
||||
-- -- These DO NOT SCROLL
|
||||
-- [(%d+)A move cursor up n lines
|
||||
-- [(%d+)B move cursor down n lines
|
||||
-- [(%d+)C move cursor right n lines
|
||||
-- [(%d+)D move cursor left n lines
|
||||
rules[{"%[", "%d+", "[ABCD]"}] = function(window, _, n, dir)
|
||||
local dx, dy = 0, 0
|
||||
n = tonumber(n)
|
||||
if dir == "A" then
|
||||
dy = -n
|
||||
elseif dir == "B" then
|
||||
dy = n
|
||||
elseif dir == "C" then
|
||||
dx = n
|
||||
else -- D
|
||||
dx = -n
|
||||
end
|
||||
set_cursor(window, window.x + dx, window.y + dy)
|
||||
end
|
||||
|
||||
-- [Line;ColumnH Move cursor to screen location v,h
|
||||
-- [Line;Columnf ^ same
|
||||
rules[{"%[", "%d+", ";", "%d+", "[Hf]"}] = function(window, _, y, _, x)
|
||||
set_cursor(window, tonumber(x), tonumber(y))
|
||||
end
|
||||
|
||||
-- [K clear line from cursor right
|
||||
-- [0K ^ same
|
||||
-- [1K clear line from cursor left
|
||||
-- [2K clear entire line
|
||||
local function clear_line(window, _, n)
|
||||
n = tonumber(n) or 0
|
||||
local x = n == 0 and window.x or 1
|
||||
local rep = n == 1 and window.x or window.width
|
||||
window.gpu.set(x, window.y, (" "):rep(rep))
|
||||
end
|
||||
rules[{"%[", "[012]?", "K"}] = clear_line
|
||||
|
||||
-- [J clear screen from cursor down
|
||||
-- [0J ^ same
|
||||
-- [1J clear screen from cursor up
|
||||
-- [2J clear entire screen
|
||||
rules[{"%[", "[012]?", "J"}] = function(window, _, n)
|
||||
clear_line(window, _, n)
|
||||
n = tonumber(n) or 0
|
||||
local y = n == 0 and (window.y + 1) or 1
|
||||
local rep = n == 1 and (window.y - 1) or window.height
|
||||
window.gpu.fill(1, y, window.width, rep, " ")
|
||||
end
|
||||
|
||||
-- [H move cursor to upper left corner
|
||||
-- [;H ^ same
|
||||
-- [f ^ same
|
||||
-- [;f ^ same
|
||||
rules[{"%[;?", "[Hf]"}] = function(window)
|
||||
set_cursor(window, 1, 1)
|
||||
end
|
||||
|
||||
-- [6n get the cursor position [ EscLine;ColumnR Response: cursor is at v,h ]
|
||||
rules[{"%[", "6", "n"}] = function(window)
|
||||
-- this solution puts the response on stdin, but it isn't echo'd
|
||||
-- I'm personally fine with the lack of echo
|
||||
io.stdin.bufferRead = string.format("%s%s%d;%dR", io.stdin.bufferRead, string.char(0x1b), window.y, window.x)
|
||||
end
|
||||
|
||||
-- D scroll up one line -- moves cursor down
|
||||
-- E move to next line (acts the same ^, but x=1)
|
||||
-- M scroll down one line -- moves cursor up
|
||||
rules[{"[DEM]"}] = function(window, dir)
|
||||
if dir == "D" then
|
||||
window.y = window.y + 1
|
||||
elseif dir == "E" then
|
||||
window.y = window.y + 1
|
||||
window.x = 1
|
||||
else -- M
|
||||
window.y = window.y - 1
|
||||
end
|
||||
end
|
@ -61,13 +61,19 @@ local targets = {}
|
||||
|
||||
-- tmpfs is not a candidate unless it is specified
|
||||
|
||||
local comps = require("component").list("filesystem")
|
||||
local devices = {}
|
||||
|
||||
-- not all mounts are components, only use components
|
||||
for dev, path in fs.mounts() do
|
||||
devices[dev] = devices[dev] and #devices[dev] < #path and devices[dev] or path
|
||||
if comps[dev.address] then
|
||||
local known = devices[dev]
|
||||
devices[dev] = known and #known < #path and known or path
|
||||
end
|
||||
end
|
||||
|
||||
devices[fs.get("/dev/") or false] = nil
|
||||
local dev_dev = fs.get("/dev")
|
||||
devices[dev_dev == rootfs or dev_dev] = nil
|
||||
local tmpAddress = computer.tmpAddress()
|
||||
|
||||
for dev, path in pairs(devices) do
|
||||
|
@ -101,7 +101,10 @@ while tty.isAvailable() do
|
||||
if string.sub(command, 1, 1) == "=" then
|
||||
code, reason = load("return " .. string.sub(command, 2), "=stdin", "t", env)
|
||||
else
|
||||
code, reason = load(command, "=stdin", "t", env)
|
||||
code, reason = load("return " .. command, "=stdin", "t", env)
|
||||
if not code then
|
||||
code, reason = load(command, "=stdin", "t", env)
|
||||
end
|
||||
end
|
||||
if code then
|
||||
local result = table.pack(xpcall(code, debug.traceback))
|
||||
|
@ -1,30 +0,0 @@
|
||||
local lib = {}
|
||||
|
||||
function lib.wrap(proxy)
|
||||
checkArg(1, proxy, "table")
|
||||
if proxy.isReadOnly() then
|
||||
return proxy
|
||||
end
|
||||
|
||||
local function roerr() return nil, "filesystem is readonly" end
|
||||
return setmetatable({
|
||||
rename = roerr,
|
||||
open = function(path, mode)
|
||||
checkArg(1, path, "string")
|
||||
checkArg(2, mode, "string")
|
||||
if mode:match("[wa]") then
|
||||
return roerr()
|
||||
end
|
||||
return proxy.open(path, mode)
|
||||
end,
|
||||
isReadOnly = function()
|
||||
return true
|
||||
end,
|
||||
write = roerr,
|
||||
setLabel = roerr,
|
||||
makeDirectory = roerr,
|
||||
remove = roerr,
|
||||
}, {__index=proxy})
|
||||
end
|
||||
|
||||
return lib
|
@ -89,48 +89,8 @@ local function createPlainFilter(name, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function createMultipleFilter(...)
|
||||
local filter = table.pack(...)
|
||||
if filter.n == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return function(...)
|
||||
local signal = table.pack(...)
|
||||
if type(signal[1]) ~= "string" then
|
||||
return false
|
||||
end
|
||||
for i = 1, filter.n do
|
||||
if filter[i] ~= nil and signal[1]:match(filter[i]) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function event.cancel(timerId)
|
||||
checkArg(1, timerId, "number")
|
||||
if handlers[timerId] then
|
||||
handlers[timerId] = nil
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function event.ignore(name, callback)
|
||||
checkArg(1, name, "string")
|
||||
checkArg(2, callback, "function")
|
||||
for id, handler in pairs(handlers) do
|
||||
if handler.key == name and handler.callback == callback then
|
||||
handlers[id] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function event.listen(name, callback)
|
||||
checkArg(1, name, "string")
|
||||
checkArg(2, callback, "function")
|
||||
@ -145,7 +105,7 @@ end
|
||||
function event.onError(message)
|
||||
local log = io.open("/tmp/event.log", "a")
|
||||
if log then
|
||||
pcall(log.write, log, message, "\n")
|
||||
pcall(log.write, log, tostring(message), "\n")
|
||||
log:close()
|
||||
end
|
||||
end
|
||||
@ -161,24 +121,6 @@ function event.pull(...)
|
||||
end
|
||||
end
|
||||
|
||||
function event.pullMultiple(...)
|
||||
local seconds
|
||||
local args
|
||||
if type(...) == "number" then
|
||||
seconds = ...
|
||||
args = table.pack(select(2,...))
|
||||
for i=1,args.n do
|
||||
checkArg(i+1, args[i], "string", "nil")
|
||||
end
|
||||
else
|
||||
args = table.pack(...)
|
||||
for i=1,args.n do
|
||||
checkArg(i, args[i], "string", "nil")
|
||||
end
|
||||
end
|
||||
return event.pullFiltered(seconds, createMultipleFilter(table.unpack(args, 1, args.n)))
|
||||
end
|
||||
|
||||
function event.pullFiltered(...)
|
||||
local args = table.pack(...)
|
||||
local seconds, filter
|
||||
@ -217,6 +159,8 @@ end
|
||||
-- users may expect to find event.push to exist
|
||||
event.push = computer.pushSignal
|
||||
|
||||
require("package").delay(event, "/lib/core/full_event.lua")
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
return event
|
||||
|
@ -184,8 +184,8 @@ function filesystem.mount(fs, path)
|
||||
return nil, why
|
||||
end
|
||||
|
||||
if filesystem.exists(real) then
|
||||
return nil, "file already exists"
|
||||
if filesystem.exists(real) and not filesystem.isDirectory(real) then
|
||||
return nil, "mount point is not a directory"
|
||||
end
|
||||
end
|
||||
|
||||
@ -234,23 +234,13 @@ function filesystem.name(path)
|
||||
return parts[#parts]
|
||||
end
|
||||
|
||||
function filesystem.proxy(filter)
|
||||
function filesystem.proxy(filter, options)
|
||||
checkArg(1, filter, "string")
|
||||
local address
|
||||
for c in component.list("filesystem", true) do
|
||||
if component.invoke(c, "getLabel") == filter then
|
||||
address = c
|
||||
break
|
||||
end
|
||||
if c:sub(1, filter:len()) == filter then
|
||||
address = c
|
||||
break
|
||||
end
|
||||
if not component.list("filesystem")[filter] or next(options or {}) then
|
||||
-- if not, load fs full library, it has a smarter proxy that also supports options
|
||||
return filesystem.internal.proxy(filter, options)
|
||||
end
|
||||
if not address then
|
||||
return nil, "no such file system"
|
||||
end
|
||||
return component.proxy(address)
|
||||
return component.proxy(filter) -- it might be a perfect match
|
||||
end
|
||||
|
||||
function filesystem.exists(path)
|
||||
|
@ -72,9 +72,9 @@ end
|
||||
function package.delay(lib, file)
|
||||
local mt = {
|
||||
__index = function(tbl, key)
|
||||
dofile(file)
|
||||
setmetatable(lib, nil)
|
||||
setmetatable(lib.internal or {}, nil)
|
||||
dofile(file)
|
||||
return tbl[key]
|
||||
end
|
||||
}
|
||||
|
@ -65,11 +65,7 @@ function process.load(path, env, init, name)
|
||||
return code(init(...))
|
||||
end,
|
||||
function(msg)
|
||||
-- msg can be a custom error object
|
||||
if type(msg) == "table" then
|
||||
if msg.reason ~= "terminated" then
|
||||
io.stderr:write(tostring(msg.reason), "\n")
|
||||
end
|
||||
if type(msg) == "table" and msg.reason == "terminated" then
|
||||
return msg.code or 0
|
||||
end
|
||||
local stack = debug.traceback():gsub("^([^\n]*\n)[^\n]*\n[^\n]*\n","%1")
|
||||
|
@ -4,53 +4,13 @@ local tx = require("transforms")
|
||||
local text = {}
|
||||
text.internal = {}
|
||||
|
||||
text.syntax = {"^%d?>>?&%d+$","^%d?>>?",">>?","<%&%d+","<",";","&&","||?"}
|
||||
text.syntax = {"^%d?>>?&%d+","^%d?>>?",">>?","<%&%d+","<",";","&&","||?"}
|
||||
|
||||
function text.trim(value) -- from http://lua-users.org/wiki/StringTrim
|
||||
local from = string.match(value, "^%s*()")
|
||||
return from > #value and "" or string.match(value, ".*%S", from)
|
||||
end
|
||||
|
||||
-- used in motd
|
||||
function text.padRight(value, length)
|
||||
checkArg(1, value, "string", "nil")
|
||||
checkArg(2, length, "number")
|
||||
if not value or unicode.wlen(value) == 0 then
|
||||
return string.rep(" ", length)
|
||||
else
|
||||
return value .. string.rep(" ", length - unicode.wlen(value))
|
||||
end
|
||||
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.wlen(line) > width then -- do we even need to wrap?
|
||||
local partial = unicode.wtrunc(line, width)
|
||||
local wrapped = partial:match("(.*[^a-zA-Z0-9._()'`=])")
|
||||
if wrapped or unicode.wlen(line) > maxWidth then
|
||||
partial = wrapped or partial
|
||||
return partial, unicode.sub(value, unicode.len(partial) + 1), true
|
||||
else
|
||||
return "", value, true -- write in new line.
|
||||
end
|
||||
end
|
||||
local start = unicode.len(line) + unicode.len(nl) + 1
|
||||
return line, start <= unicode.len(value) and unicode.sub(value, start) or nil, unicode.len(nl) > 0
|
||||
end
|
||||
|
||||
function text.wrappedLines(value, width, maxWidth)
|
||||
local line
|
||||
return function()
|
||||
if value then
|
||||
line, value = text.wrap(value, width, maxWidth)
|
||||
return line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- used by lib/sh
|
||||
function text.escapeMagic(txt)
|
||||
return txt:gsub('[%(%)%.%%%+%-%*%?%[%^%$]', '%%%1')
|
||||
|
@ -32,11 +32,11 @@ function tty.key_down_handler(handler, cursor, char, code)
|
||||
elseif code == keys.enter or code == keys.numpadenter then
|
||||
cursor:move(math.huge)
|
||||
cursor:draw("\n")
|
||||
if #data > 0 then
|
||||
if data:find("%S") and data ~= handler[1] then
|
||||
table.insert(handler, 1, data)
|
||||
handler[(tonumber(os.getenv("HISTSIZE")) or 10)+1]=nil
|
||||
handler[0]=nil
|
||||
end
|
||||
handler[0]=nil
|
||||
return nil, data .. "\n"
|
||||
elseif code == keys.up or code == keys.down then
|
||||
local ni = handler.index + (code == keys.up and 1 or -1)
|
||||
@ -101,49 +101,23 @@ function tty.isAvailable()
|
||||
return not not (gpu and gpu.getScreen())
|
||||
end
|
||||
|
||||
function tty.stream:blink(done)
|
||||
local width, height, dx, dy, x, y = tty.getViewport()
|
||||
local gpu = tty.gpu()
|
||||
if not gpu or x < 1 or x > width or y < 1 or y > height then
|
||||
return true
|
||||
end
|
||||
x, y = x + dx, y + dy
|
||||
local blinked, bgColor, bgIsPalette, fgColor, fgIsPalette, char_at_cursor = table.unpack(self.blink_cache or {})
|
||||
if done == nil then -- reset
|
||||
blinked = false
|
||||
bgColor, bgIsPalette = gpu.getBackground()
|
||||
-- it can happen during a type of race condition when a screen is removed
|
||||
if not bgColor then
|
||||
return
|
||||
end
|
||||
|
||||
fgColor, fgIsPalette = gpu.getForeground()
|
||||
char_at_cursor = gpu.get(x, y)
|
||||
end
|
||||
|
||||
if not blinked and not done then
|
||||
gpu.setForeground(bgColor, bgIsPalette)
|
||||
gpu.setBackground(fgColor, fgIsPalette)
|
||||
gpu.set(x, y, char_at_cursor)
|
||||
gpu.setForeground(fgColor, fgIsPalette)
|
||||
gpu.setBackground(bgColor, bgIsPalette)
|
||||
blinked = true
|
||||
elseif blinked and (done or tty.window.blink) then
|
||||
gpu.set(x, y, char_at_cursor)
|
||||
blinked = false
|
||||
end
|
||||
|
||||
self.blink_cache = table.pack(blinked, bgColor, bgIsPalette, fgColor, fgIsPalette, char_at_cursor)
|
||||
return true
|
||||
end
|
||||
|
||||
function tty.stream:pull(timeout, ...)
|
||||
timeout = timeout or math.huge
|
||||
local blink_timeout = tty.window.blink and .5 or math.huge
|
||||
|
||||
-- it can happen during a type of race condition when a screen is removed
|
||||
if not self:blink() then
|
||||
return nil, "interrupted"
|
||||
local width, height, dx, dy, x, y = tty.getViewport()
|
||||
local gpu = tty.gpu()
|
||||
if x < 1 or x > width or y < 1 or y > height then
|
||||
gpu = nil
|
||||
end
|
||||
local char_at_cursor
|
||||
local blinked
|
||||
if gpu then
|
||||
blinked, char_at_cursor = pcall(gpu.get, x + dx, y + dy)
|
||||
if not blinked then
|
||||
return nil, "interrupted"
|
||||
end
|
||||
io.write("\0277\27[7m", char_at_cursor, "\0278")
|
||||
end
|
||||
|
||||
-- get the next event
|
||||
@ -152,7 +126,15 @@ function tty.stream:pull(timeout, ...)
|
||||
|
||||
timeout = timeout - blink_timeout
|
||||
local done = signal.n > 1 or timeout < blink_timeout
|
||||
self:blink(done)
|
||||
if gpu then
|
||||
if not blinked and not done then
|
||||
io.write("\0277\27[7m", char_at_cursor, "\0278")
|
||||
blinked = true
|
||||
elseif blinked and (done or tty.window.blink) then
|
||||
io.write("\0277", char_at_cursor, "\0278")
|
||||
blinked = false
|
||||
end
|
||||
end
|
||||
|
||||
if done then
|
||||
return table.unpack(signal, 1, signal.n)
|
||||
@ -336,27 +318,7 @@ function tty.stream:write(value)
|
||||
-- parse the instruction in segment
|
||||
-- [ (%d+;)+ %d+m
|
||||
window.ansi_escape = window.ansi_escape .. value
|
||||
local color_attributes = {tonumber(window.ansi_escape:match("^%[(%d%d)m"))}
|
||||
if not color_attributes[1] then
|
||||
color_attributes, ansi_print, value = require("vt100").parse(window)
|
||||
else
|
||||
value = window.ansi_escape:sub(5)
|
||||
end
|
||||
for _,catt in ipairs(color_attributes) do
|
||||
-- B6 is closer to cyan in 4 bit color
|
||||
local colors = {0x0,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00B6ff,0xffffff}
|
||||
catt = catt - 29
|
||||
local method = "setForeground"
|
||||
if catt > 10 then
|
||||
method = "setBackground"
|
||||
catt = catt - 10
|
||||
end
|
||||
local c = colors[catt]
|
||||
if c then
|
||||
gpu[method](c)
|
||||
end
|
||||
window.ansi_escape = nil -- might happen multiple times, that's fine
|
||||
end
|
||||
value, ansi_print = require("vt100").parse(window)
|
||||
end
|
||||
|
||||
-- scroll before parsing next line
|
||||
|
@ -1,190 +1,129 @@
|
||||
local text = require("text")
|
||||
local vt100 = {}
|
||||
|
||||
-- runs patterns on ansi until failure
|
||||
-- returns valid:boolean, completed_index:nil|number
|
||||
function vt100.validate(ansi, patterns)
|
||||
local last_index = 0
|
||||
local captures = {}
|
||||
for _,pattern in ipairs(patterns) do
|
||||
if last_index >= #ansi then
|
||||
return true
|
||||
end
|
||||
local si, ei, capture = ansi:find("^(" .. pattern .. ")", last_index + 1)
|
||||
if not si then -- failed to match
|
||||
return
|
||||
end
|
||||
captures[#captures + 1] = capture
|
||||
last_index = ei
|
||||
end
|
||||
return true, last_index, captures
|
||||
end
|
||||
|
||||
local rules = {}
|
||||
local vt100 = {rules=rules}
|
||||
local full
|
||||
|
||||
-- colors
|
||||
-- colors, blinking, and reverse
|
||||
-- [%d+;%d+;..%d+m
|
||||
rules[{"%[", "[%d;]*", "m"}] = function(_, _, number_text)
|
||||
local numbers = {}
|
||||
-- cost: 2,250
|
||||
rules[{"%[", "[%d;]*", "m"}] = function(window, _, number_text)
|
||||
-- prefix and suffix ; act as reset
|
||||
-- e.g. \27[41;m is actually 41 followed by a reset
|
||||
number_text = ";" .. number_text:gsub("^;$","") .. ";"
|
||||
local parts = text.split(number_text, {";"})
|
||||
local colors = {0x0,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00B6ff,0xffffff}
|
||||
local fg, bg = window.gpu.setForeground, window.gpu.setBackground
|
||||
if window.flip then
|
||||
fg, bg = bg, fg
|
||||
end
|
||||
number_text = " _ " .. number_text:gsub("^;$", ""):gsub(";", " _ ") .. " _ "
|
||||
local parts = text.internal.tokenize(number_text)
|
||||
local last_was_break
|
||||
for _,part in ipairs(parts) do
|
||||
local num = tonumber(part)
|
||||
if not num then
|
||||
num = last_was_break and 0
|
||||
last_was_break = true
|
||||
else
|
||||
last_was_break = false
|
||||
end
|
||||
if num == 0 then
|
||||
numbers[#numbers + 1] = 40
|
||||
numbers[#numbers + 1] = 37
|
||||
local num = tonumber(part[1].txt)
|
||||
last_was_break, num = not num, num or last_was_break and 0
|
||||
|
||||
if num == 7 then
|
||||
if not window.flip then
|
||||
fg(bg(window.gpu.getForeground()))
|
||||
fg, bg = bg, fg
|
||||
end
|
||||
window.flip = true
|
||||
elseif num == 5 then
|
||||
window.blink = true
|
||||
elseif num == 0 then
|
||||
bg(colors[1])
|
||||
fg(colors[8])
|
||||
elseif num then
|
||||
numbers[#numbers + 1] = num
|
||||
num = num - 29
|
||||
local set = fg
|
||||
if num > 10 then
|
||||
num = num - 10
|
||||
set = bg
|
||||
end
|
||||
local color = colors[num]
|
||||
if color then
|
||||
set(color)
|
||||
end
|
||||
end
|
||||
end
|
||||
return numbers
|
||||
end
|
||||
|
||||
-- [?7[hl] wrap mode
|
||||
rules[{"%[", "%?", "7", "[hl]"}] = function(window, _, _, _, nowrap)
|
||||
window.nowrap = nowrap == "l"
|
||||
end
|
||||
|
||||
-- helper scroll function
|
||||
local function set_cursor(window, x, y)
|
||||
window.x = math.min(math.max(x, 1), window.width)
|
||||
window.y = math.min(math.max(y, 1), window.height)
|
||||
end
|
||||
|
||||
-- -- These DO NOT SCROLL
|
||||
-- [(%d+)A move cursor up n lines
|
||||
-- [(%d+)B move cursor down n lines
|
||||
-- [(%d+)C move cursor right n lines
|
||||
-- [(%d+)D move cursor left n lines
|
||||
rules[{"%[", "%d+", "[ABCD]"}] = function(window, _, n, dir)
|
||||
local dx, dy = 0, 0
|
||||
n = tonumber(n)
|
||||
if dir == "A" then
|
||||
dy = -n
|
||||
elseif dir == "B" then
|
||||
dy = n
|
||||
elseif dir == "C" then
|
||||
dx = n
|
||||
else -- D
|
||||
dx = -n
|
||||
end
|
||||
set_cursor(window, window.x + dx, window.y + dy)
|
||||
end
|
||||
|
||||
-- [Line;ColumnH Move cursor to screen location v,h
|
||||
-- [Line;Columnf ^ same
|
||||
rules[{"%[", "%d+", ";", "%d+", "[Hf]"}] = function(window, _, y, _, x)
|
||||
set_cursor(window, tonumber(x), tonumber(y))
|
||||
end
|
||||
|
||||
-- [K clear line from cursor right
|
||||
-- [0K ^ same
|
||||
-- [1K clear line from cursor left
|
||||
-- [2K clear entire line
|
||||
local function clear_line(window, _, n)
|
||||
n = tonumber(n) or 0
|
||||
local x = n == 0 and window.x or 1
|
||||
local rep = n == 1 and window.x or window.width
|
||||
window.gpu.set(x, window.y, (" "):rep(rep))
|
||||
end
|
||||
rules[{"%[", "[012]?", "K"}] = clear_line
|
||||
|
||||
-- [J clear screen from cursor down
|
||||
-- [0J ^ same
|
||||
-- [1J clear screen from cursor up
|
||||
-- [2J clear entire screen
|
||||
rules[{"%[", "[012]?", "J"}] = function(window, _, n)
|
||||
clear_line(window, _, n)
|
||||
n = tonumber(n) or 0
|
||||
local y = n == 0 and (window.y + 1) or 1
|
||||
local rep = n == 1 and (window.y - 1) or window.height
|
||||
window.gpu.fill(1, y, window.width, rep, " ")
|
||||
end
|
||||
|
||||
-- [H move cursor to upper left corner
|
||||
-- [;H ^ same
|
||||
-- [f ^ same
|
||||
-- [;f ^ same
|
||||
rules[{"%[;?", "[Hf]"}] = function(window)
|
||||
set_cursor(window, 1, 1)
|
||||
end
|
||||
|
||||
-- [6n get the cursor position [ EscLine;ColumnR Response: cursor is at v,h ]
|
||||
rules[{"%[", "6", "n"}] = function(window)
|
||||
-- this solution puts the response on stdin, but it isn't echo'd
|
||||
-- I'm personally fine with the lack of echo
|
||||
io.stdin.bufferRead = string.format("%s%s%d;%dR", io.stdin.bufferRead, string.char(0x1b), window.y, window.x)
|
||||
end
|
||||
|
||||
-- D scroll up one line -- moves cursor down
|
||||
-- E move to next line (acts the same ^, but x=1)
|
||||
-- M scroll down one line -- moves cursor up
|
||||
rules[{"[DEM]"}] = function(window, dir)
|
||||
if dir == "D" then
|
||||
window.y = window.y + 1
|
||||
elseif dir == "E" then
|
||||
window.y = window.y + 1
|
||||
window.x = 1
|
||||
else -- M
|
||||
window.y = window.y - 1
|
||||
end
|
||||
end
|
||||
|
||||
local function save_attributes(window, save)
|
||||
if save then
|
||||
local data = window.saved or {1, 1, {0x0}, {0xffffff}}
|
||||
local function save_attributes(window, seven, s)
|
||||
if seven == "7" or s == "s" then
|
||||
window.saved =
|
||||
{
|
||||
window.x,
|
||||
window.y,
|
||||
{window.gpu.getBackground()},
|
||||
{window.gpu.getForeground()},
|
||||
window.flip,
|
||||
window.blink
|
||||
}
|
||||
else
|
||||
local data = window.saved or {1, 1, {0x0}, {0xffffff}, window.flip, window.blink}
|
||||
window.x = data[1]
|
||||
window.y = data[2]
|
||||
window.gpu.setBackground(table.unpack(data[3]))
|
||||
window.gpu.setForeground(table.unpack(data[4]))
|
||||
else
|
||||
window.saved = {window.x, window.y, {window.gpu.getBackground()}, {window.gpu.getForeground()}}
|
||||
window.flip = data[5]
|
||||
window.blink = data[6]
|
||||
end
|
||||
end
|
||||
|
||||
-- 7 save cursor position and attributes
|
||||
-- 8 restore cursor position and attributes
|
||||
rules[{"[78]"}] = function(window, restore)
|
||||
save_attributes(window, restore == "8")
|
||||
end
|
||||
rules[{"[78]"}] = save_attributes
|
||||
|
||||
-- s save cursor position
|
||||
-- u restore cursor position
|
||||
rules[{"%[", "[su]"}] = function(window, _, restore)
|
||||
save_attributes(window, restore == "u")
|
||||
end
|
||||
rules[{"%[", "[su]"}] = save_attributes
|
||||
|
||||
-- returns 2 values
|
||||
-- value: parsed text
|
||||
-- ansi_print: failed to parse
|
||||
function vt100.parse(window)
|
||||
local ansi = window.ansi_escape
|
||||
window.ansi_escape = nil
|
||||
local any_valid
|
||||
|
||||
for rule,action in pairs(rules) do
|
||||
local ok, completed, captures = vt100.validate(ansi, rule)
|
||||
if completed then
|
||||
return action(window, table.unpack(captures)) or {}, "", ansi:sub(completed + 1)
|
||||
elseif ok then
|
||||
any_valid = true
|
||||
local last_index = 0
|
||||
local captures = {}
|
||||
for _,pattern in ipairs(rule) do
|
||||
if last_index >= #ansi then
|
||||
any_valid = true
|
||||
break
|
||||
end
|
||||
local si, ei, capture = ansi:find("^(" .. pattern .. ")", last_index + 1)
|
||||
if not si then
|
||||
break
|
||||
end
|
||||
captures[#captures + 1] = capture
|
||||
last_index = ei
|
||||
end
|
||||
|
||||
if #captures == #rule then
|
||||
action(window, table.unpack(captures))
|
||||
return ansi:sub(last_index + 1), ""
|
||||
end
|
||||
end
|
||||
|
||||
if not full then
|
||||
-- maybe it did satisfy a rule, load more rules
|
||||
full = true
|
||||
dofile("/lib/core/full_vt.lua")
|
||||
window.ansi_escape = ansi
|
||||
return vt100.parse(window)
|
||||
end
|
||||
|
||||
if not any_valid then
|
||||
-- malformed
|
||||
return {}, string.char(0x1b), ansi
|
||||
return ansi, "\27"
|
||||
end
|
||||
|
||||
-- else, still consuming
|
||||
window.ansi_escape = ansi
|
||||
return {}, "", ""
|
||||
return "", ""
|
||||
end
|
||||
|
||||
return vt100
|
||||
|
@ -5,9 +5,12 @@ SYNOPSIS
|
||||
mount
|
||||
mount LABEL PATH
|
||||
mount ADDRESS PATH
|
||||
mount --bind PATH PATH
|
||||
|
||||
OPTIONS
|
||||
-r mount filesystem readonly
|
||||
-r, --readonly mount filesystem readonly
|
||||
--bind mount a bind point (folder to folder)
|
||||
-h, --help print help message
|
||||
|
||||
DESCRIPTION
|
||||
All files accessible in OpenOS are arranged in one big tree, starting with the root node, '/'. The files are the leaves of the tree, directories are inner nodes of the tree. Files can be distributed across several devices (file system components, such as hard drives and floppies). The `mount` command is used to attach a file system to this tree. The `umount` command can be used to remove a mounted file system from the tree (note that `rm` works for this, too).
|
||||
@ -22,5 +25,8 @@ EXAMPLES
|
||||
mount 56f /var
|
||||
Mounts the file system of which the address starts with `56f` at `/var`.
|
||||
|
||||
mount -r tmpfs /tmp_ro
|
||||
mount --readonly tmpfs /tmp_ro
|
||||
Mounts a readonly access path of tmpfs to /tmp_ro
|
||||
|
||||
mount --bind /mnt/fa4/home /home
|
||||
Mounts /mnt/fa5/home to /home
|
||||
|
Loading…
x
Reference in New Issue
Block a user