mirror of
https://github.com/Ale32bit/Capy64.git
synced 2025-01-18 10:36:44 +00:00
Bring back CapyOS to the main repo
This commit is contained in:
parent
e926bd6d6b
commit
e07f79c31a
35 changed files with 3573 additions and 93 deletions
17
Capy64/Assets/Lua/CapyOS/bin/cd.lua
Normal file
17
Capy64/Assets/Lua/CapyOS/bin/cd.lua
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
local args = {...}
|
||||||
|
local fs = require("fs")
|
||||||
|
|
||||||
|
local dir = args[1]
|
||||||
|
|
||||||
|
if not dir then
|
||||||
|
dir = shell.homePath
|
||||||
|
end
|
||||||
|
|
||||||
|
dir = shell.resolve(dir)
|
||||||
|
|
||||||
|
if not fs.isDir(dir) then
|
||||||
|
error("No such directory: " .. dir, 0)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
shell.setDir(dir)
|
5
Capy64/Assets/Lua/CapyOS/bin/clear.lua
Normal file
5
Capy64/Assets/Lua/CapyOS/bin/clear.lua
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
local term = require("term")
|
||||||
|
local colors = require("colors")
|
||||||
|
term.setBackground(colors.black)
|
||||||
|
term.clear()
|
||||||
|
term.setPos(1, 1)
|
1
Capy64/Assets/Lua/CapyOS/bin/exit.lua
Normal file
1
Capy64/Assets/Lua/CapyOS/bin/exit.lua
Normal file
|
@ -0,0 +1 @@
|
||||||
|
shell.exit()
|
94
Capy64/Assets/Lua/CapyOS/bin/fun/mandelbrot.lua
Normal file
94
Capy64/Assets/Lua/CapyOS/bin/fun/mandelbrot.lua
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
-- Mandelbrot in Capy64
|
||||||
|
|
||||||
|
local gpu = require("gpu")
|
||||||
|
local timer = require("timer")
|
||||||
|
local event = require("event")
|
||||||
|
local term = require("term")
|
||||||
|
|
||||||
|
-- lower = closer = slower
|
||||||
|
local scale = 4
|
||||||
|
|
||||||
|
-- higher = more detailed = slower
|
||||||
|
local iterations = 100
|
||||||
|
|
||||||
|
local pscale = scale
|
||||||
|
local w, h = gpu.getSize()
|
||||||
|
local px = pscale / w
|
||||||
|
local colorUnit = math.floor(0xffffff / iterations)
|
||||||
|
-- todo: make it interactive
|
||||||
|
local dx, dy = 0, 0
|
||||||
|
local cx, cy = math.floor(w / 2), math.floor(h / 2)
|
||||||
|
|
||||||
|
-- z = z^2 + c
|
||||||
|
local function mandelbrot(zr, zi, cr, ci)
|
||||||
|
return zr ^ 2 - zi ^ 2 + cr,
|
||||||
|
2 * zr * zi + ci
|
||||||
|
end
|
||||||
|
|
||||||
|
local function iter(cr, ci)
|
||||||
|
local zr, zi = 0, 0
|
||||||
|
for i = 1, iterations do
|
||||||
|
zr, zi = mandelbrot(zr, zi, cr, ci)
|
||||||
|
if math.abs(zr) >= (pscale >= 2 and pscale or 2) or math.abs(zi) >= (pscale >= 2 and pscale or 2) then
|
||||||
|
return false, colorUnit, i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, 0, iterations
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw()
|
||||||
|
local buffer <close> = gpu.newBuffer()
|
||||||
|
|
||||||
|
for y = 0, h - 1 do
|
||||||
|
for x = 0, w - 1 do
|
||||||
|
local _, _, i = iter((x - cx + dx * pscale) * px, (y - cy + dy * pscale) * px)
|
||||||
|
buffer[y * w + x] = colorUnit * (iterations - i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gpu.setBuffer(buffer)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- no idea why it's needed
|
||||||
|
timer.sleep(1)
|
||||||
|
|
||||||
|
draw()
|
||||||
|
|
||||||
|
local tw, th = term.getSize()
|
||||||
|
|
||||||
|
while true do
|
||||||
|
term.setPos(1, th)
|
||||||
|
term.setBackground(0)
|
||||||
|
term.setForeground(0xffffff)
|
||||||
|
term.write("X: " .. dx .. "; Y: " .. dy .. "; S: " .. pscale .. "; " .. px .. "!")
|
||||||
|
local ev = { event.pull("key_down") }
|
||||||
|
if ev[1] == "key_down" then
|
||||||
|
local key = ev[3]
|
||||||
|
if key == "up" then
|
||||||
|
dy = dy - 10 / pscale
|
||||||
|
elseif key == "down" then
|
||||||
|
dy = dy + 10 / pscale
|
||||||
|
elseif key == "right" then
|
||||||
|
dx = dx + 10 / pscale
|
||||||
|
elseif key == "left" then
|
||||||
|
dx = dx - 10 / pscale
|
||||||
|
elseif key == "enter" then
|
||||||
|
draw()
|
||||||
|
elseif key == "page_down" then
|
||||||
|
pscale = pscale * 1.25
|
||||||
|
dx = dx * pscale
|
||||||
|
dy = dy * pscale
|
||||||
|
elseif key == "page_up" then
|
||||||
|
pscale = pscale / 1.25
|
||||||
|
dx = dx / pscale
|
||||||
|
dy = dy / pscale
|
||||||
|
elseif key == "r" then
|
||||||
|
pscale = scale
|
||||||
|
dx = 0
|
||||||
|
dy = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
px = pscale / w
|
||||||
|
end
|
73
Capy64/Assets/Lua/CapyOS/bin/fun/melt.lua
Normal file
73
Capy64/Assets/Lua/CapyOS/bin/fun/melt.lua
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
local gpu = require("gpu")
|
||||||
|
local timer = require("timer")
|
||||||
|
local event = require("event")
|
||||||
|
local colors = require("colors")
|
||||||
|
local parallel = require("parallel")
|
||||||
|
|
||||||
|
local melts = 2 ^ 12
|
||||||
|
|
||||||
|
local function contains(arr, val)
|
||||||
|
for k, v in ipairs(arr) do
|
||||||
|
if v == val then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function melt()
|
||||||
|
local w, h = gpu.getSize()
|
||||||
|
local x, y = 0, 0
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local buffer <close> = gpu.getBuffer()
|
||||||
|
for i = 1, melts do
|
||||||
|
local nx = math.random(x, w)
|
||||||
|
local ny = math.random(y, h)
|
||||||
|
|
||||||
|
local c = buffer[ny * w + nx]
|
||||||
|
buffer[(ny + 1) * w + nx] = c
|
||||||
|
end
|
||||||
|
gpu.setBuffer(buffer)
|
||||||
|
|
||||||
|
timer.delay(10):await()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw()
|
||||||
|
local ox, oy
|
||||||
|
while true do
|
||||||
|
local ev, b, x, y = event.pull("mouse_move", "mouse_down")
|
||||||
|
|
||||||
|
if ev == "mouse_down" then
|
||||||
|
if b == 1 then
|
||||||
|
ox = x
|
||||||
|
oy = y
|
||||||
|
end
|
||||||
|
elseif ev == "mouse_move" then
|
||||||
|
if contains(b, 1) then
|
||||||
|
gpu.plot(x, y, colors.red)
|
||||||
|
gpu.drawLine(x, y, ox, oy, colors.red)
|
||||||
|
ox, oy = x, y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function random()
|
||||||
|
local w, h = gpu.getSize()
|
||||||
|
while true do
|
||||||
|
for i = 1, 24 do
|
||||||
|
gpu.drawString(
|
||||||
|
math.random(-7, w),
|
||||||
|
math.random(-13, h),
|
||||||
|
math.random(0, 0xffffff),
|
||||||
|
string.char(math.random(32, 127))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.delay(100):await()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parallel.waitForAny(draw, melt, random)
|
17
Capy64/Assets/Lua/CapyOS/bin/hello.lua
Normal file
17
Capy64/Assets/Lua/CapyOS/bin/hello.lua
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
local timer = require("timer")
|
||||||
|
local colors = require("colors")
|
||||||
|
local term = require("term")
|
||||||
|
|
||||||
|
local function slowPrint(text, delay)
|
||||||
|
for i = 1, #text do
|
||||||
|
local ch = text:sub(i, i)
|
||||||
|
io.write(ch)
|
||||||
|
timer.sleep(delay)
|
||||||
|
end
|
||||||
|
print()
|
||||||
|
end
|
||||||
|
|
||||||
|
local color = colors[math.random(1, #colors)]
|
||||||
|
|
||||||
|
term.setForeground(color)
|
||||||
|
slowPrint("Hello, World!", 50)
|
25
Capy64/Assets/Lua/CapyOS/bin/ls.lua
Normal file
25
Capy64/Assets/Lua/CapyOS/bin/ls.lua
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
local args = { ... }
|
||||||
|
local fs = require("fs")
|
||||||
|
local term = require("term")
|
||||||
|
local colors = require("colors")
|
||||||
|
local dir = shell.getDir()
|
||||||
|
|
||||||
|
if args[1] then
|
||||||
|
dir = shell.resolve(args[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fs.isDir(dir) then
|
||||||
|
error("No such directory: " .. dir, 0)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local files = fs.list(dir)
|
||||||
|
for k, v in ipairs(files) do
|
||||||
|
if fs.isDir(fs.combine(dir, v)) then
|
||||||
|
term.setForeground(colors.lightBlue)
|
||||||
|
print(v .. "/")
|
||||||
|
else
|
||||||
|
term.setForeground(colors.white)
|
||||||
|
print(v)
|
||||||
|
end
|
||||||
|
end
|
75
Capy64/Assets/Lua/CapyOS/bin/lua.lua
Normal file
75
Capy64/Assets/Lua/CapyOS/bin/lua.lua
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
local term = require("term")
|
||||||
|
local io = require("io")
|
||||||
|
local colors = require("colors")
|
||||||
|
local colours = colors
|
||||||
|
|
||||||
|
local tArgs = { ... }
|
||||||
|
if #tArgs > 0 then
|
||||||
|
print("This is an interactive Lua prompt.")
|
||||||
|
print("To run a lua program, just type its name.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--local pretty = require "cc.pretty"
|
||||||
|
|
||||||
|
local bRunning = true
|
||||||
|
local tCommandHistory = {}
|
||||||
|
local tEnv = {
|
||||||
|
["exit"] = setmetatable({}, {
|
||||||
|
__tostring = function() return "Call exit() to exit." end,
|
||||||
|
__call = function() bRunning = false end,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
setmetatable(tEnv, { __index = _ENV })
|
||||||
|
|
||||||
|
for k, v in pairs(package.loaded) do
|
||||||
|
tEnv[k] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setForeground(colours.yellow)
|
||||||
|
print(_VERSION .. " interactive prompt")
|
||||||
|
print("Call exit() to exit.")
|
||||||
|
term.setForeground(colours.white)
|
||||||
|
|
||||||
|
while bRunning do
|
||||||
|
term.setForeground(colours.yellow)
|
||||||
|
io.write("> ")
|
||||||
|
term.setForeground(colours.white)
|
||||||
|
|
||||||
|
local s = io.read(nil, tCommandHistory)
|
||||||
|
if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then
|
||||||
|
table.insert(tCommandHistory, s)
|
||||||
|
end
|
||||||
|
|
||||||
|
local nForcePrint = 0
|
||||||
|
local func, e = load(s, "=lua", "t", tEnv)
|
||||||
|
local func2 = load("return " .. s, "=lua", "t", tEnv)
|
||||||
|
if not func then
|
||||||
|
if func2 then
|
||||||
|
func = func2
|
||||||
|
e = nil
|
||||||
|
nForcePrint = 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if func2 then
|
||||||
|
func = func2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if func then
|
||||||
|
local tResults = table.pack(pcall(func))
|
||||||
|
if tResults[1] then
|
||||||
|
local n = 1
|
||||||
|
while n < tResults.n or n <= nForcePrint do
|
||||||
|
local value = tResults[n + 1]
|
||||||
|
print(tostring(value))
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
io.stderr.print(tResults[2])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
io.stderr.print(e)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
14
Capy64/Assets/Lua/CapyOS/bin/mkdir.lua
Normal file
14
Capy64/Assets/Lua/CapyOS/bin/mkdir.lua
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
local fs = require("fs")
|
||||||
|
local args = { ... }
|
||||||
|
|
||||||
|
if #args == 0 then
|
||||||
|
print("Usage: mkdir <directory>")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local dir = shell.resolve(args[1])
|
||||||
|
if fs.exists(dir) then
|
||||||
|
error("Path already exists", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
fs.makeDir(dir)
|
1
Capy64/Assets/Lua/CapyOS/bin/pwd.lua
Normal file
1
Capy64/Assets/Lua/CapyOS/bin/pwd.lua
Normal file
|
@ -0,0 +1 @@
|
||||||
|
print(shell.getDir())
|
8
Capy64/Assets/Lua/CapyOS/bin/reboot.lua
Normal file
8
Capy64/Assets/Lua/CapyOS/bin/reboot.lua
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
local timer = require("timer")
|
||||||
|
local machine = require("machine")
|
||||||
|
|
||||||
|
print("Goodbye!")
|
||||||
|
|
||||||
|
timer.sleep(1000)
|
||||||
|
|
||||||
|
machine.reboot()
|
10
Capy64/Assets/Lua/CapyOS/bin/rm.lua
Normal file
10
Capy64/Assets/Lua/CapyOS/bin/rm.lua
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
local fs = require("fs")
|
||||||
|
|
||||||
|
local args = { ... }
|
||||||
|
if #args == 0 then
|
||||||
|
print("Usage: rm <file>")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local file = shell.resolve(args[1])
|
||||||
|
fs.delete(file, true)
|
143
Capy64/Assets/Lua/CapyOS/bin/shell.lua
Normal file
143
Capy64/Assets/Lua/CapyOS/bin/shell.lua
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
local term = require("term")
|
||||||
|
local colors = require("colors")
|
||||||
|
local fs = require("fs")
|
||||||
|
local machine = require("machine")
|
||||||
|
|
||||||
|
local exit = false
|
||||||
|
local shell = {}
|
||||||
|
|
||||||
|
shell.path = "./?;./?.lua;/bin/?.lua"
|
||||||
|
shell.homePath = "/home"
|
||||||
|
|
||||||
|
local currentDir = shell.homePath
|
||||||
|
|
||||||
|
local function buildEnvironment(path, args)
|
||||||
|
local arg = { table.unpack(args, 2) }
|
||||||
|
arg[0] = path
|
||||||
|
|
||||||
|
return setmetatable({
|
||||||
|
shell = shell,
|
||||||
|
arg = arg
|
||||||
|
}, { __index = _G })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tokenise(...)
|
||||||
|
local sLine = table.concat({ ... }, " ")
|
||||||
|
local tWords = {}
|
||||||
|
local bQuoted = false
|
||||||
|
for match in string.gmatch(sLine .. "\"", "(.-)\"") do
|
||||||
|
if bQuoted then
|
||||||
|
table.insert(tWords, match)
|
||||||
|
else
|
||||||
|
for m in string.gmatch(match, "[^ \t]+") do
|
||||||
|
table.insert(tWords, m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
bQuoted = not bQuoted
|
||||||
|
end
|
||||||
|
return tWords
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.getDir()
|
||||||
|
return currentDir
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.setDir(path)
|
||||||
|
currentDir = path
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.resolve(path)
|
||||||
|
if path:sub(1, 1) == "/" then
|
||||||
|
return fs.combine("", path)
|
||||||
|
end
|
||||||
|
|
||||||
|
if path:sub(1, 1) == "~" then
|
||||||
|
return fs.combine(shell.homePath, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
return fs.combine(currentDir, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.resolveProgram(path)
|
||||||
|
if path:sub(1, 1) == "/" then
|
||||||
|
return shell.resolve(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
for seg in shell.path:gmatch("[^;]+") do
|
||||||
|
local resolved = shell.resolve(seg:gsub("%?", path))
|
||||||
|
if fs.exists(resolved) and not fs.isDir(resolved) then
|
||||||
|
return resolved
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.run(...)
|
||||||
|
local args = tokenise(...)
|
||||||
|
local command = args[1]
|
||||||
|
local path = shell.resolveProgram(command)
|
||||||
|
|
||||||
|
if not path then
|
||||||
|
io.stderr.print("Command not found: " .. command)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local env = buildEnvironment(command, args)
|
||||||
|
|
||||||
|
local func, err = loadfile(path, "t", env)
|
||||||
|
|
||||||
|
if not func then
|
||||||
|
io.stderr.print(err)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = pcall(func, table.unpack(args, 2))
|
||||||
|
if not ok then
|
||||||
|
io.stderr.print(err)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function shell.exit()
|
||||||
|
exit = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fs.exists(shell.homePath) then
|
||||||
|
fs.makeDir(shell.homePath)
|
||||||
|
end
|
||||||
|
|
||||||
|
local history = {}
|
||||||
|
local lastExecSuccess = true
|
||||||
|
while not exit do
|
||||||
|
machine.setRPC(os.version(), "On shell")
|
||||||
|
|
||||||
|
term.setBackground(colors.black)
|
||||||
|
term.setForeground(colors.white)
|
||||||
|
io.write(":")
|
||||||
|
term.setForeground(colors.lightBlue)
|
||||||
|
if currentDir == shell.homePath then
|
||||||
|
io.write("~")
|
||||||
|
else
|
||||||
|
io.write(currentDir)
|
||||||
|
end
|
||||||
|
|
||||||
|
if lastExecSuccess then
|
||||||
|
term.setForeground(colors.yellow)
|
||||||
|
else
|
||||||
|
term.setForeground(colors.red)
|
||||||
|
end
|
||||||
|
io.write("$ ")
|
||||||
|
|
||||||
|
term.setForeground(colors.white)
|
||||||
|
local line = io.read(nil, history)
|
||||||
|
|
||||||
|
if line:match("%S") and history[#history] ~= line then
|
||||||
|
table.insert(history, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
if line:match("%S") then
|
||||||
|
machine.setRPC(os.version(), "Running: " .. line)
|
||||||
|
lastExecSuccess = shell.run(line)
|
||||||
|
end
|
||||||
|
end
|
8
Capy64/Assets/Lua/CapyOS/bin/shutdown.lua
Normal file
8
Capy64/Assets/Lua/CapyOS/bin/shutdown.lua
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
local timer = require("timer")
|
||||||
|
local machine = require("machine")
|
||||||
|
|
||||||
|
print("Goodbye!")
|
||||||
|
|
||||||
|
timer.sleep(1000)
|
||||||
|
|
||||||
|
machine.shutdown()
|
2
Capy64/Assets/Lua/CapyOS/bin/version.lua
Normal file
2
Capy64/Assets/Lua/CapyOS/bin/version.lua
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
local machine = require("machine")
|
||||||
|
print(string.format("%s @ %s - %s", os.version(), machine.version(), _VERSION))
|
34
Capy64/Assets/Lua/CapyOS/bin/wget.lua
Normal file
34
Capy64/Assets/Lua/CapyOS/bin/wget.lua
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
local http = require("http")
|
||||||
|
local fs = require("fs")
|
||||||
|
|
||||||
|
local args = { ... }
|
||||||
|
|
||||||
|
if not http then
|
||||||
|
error("HTTP is not enabled", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
if #args == 0 then
|
||||||
|
print("Usage: wget <url> [outputPath]")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local outputName = args[2] or fs.getName(args[1])
|
||||||
|
local outputPath = shell.resolve(outputName)
|
||||||
|
|
||||||
|
if not http.checkURL(args[1]) then
|
||||||
|
error("Invalid URL", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local response, err = http.get(args[1], nil, {
|
||||||
|
binary = true,
|
||||||
|
})
|
||||||
|
if not response then
|
||||||
|
error(err, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local file <close> = fs.open(outputPath, "wb")
|
||||||
|
file:write(response:readAll())
|
||||||
|
file:close()
|
||||||
|
response:close()
|
||||||
|
|
||||||
|
print("File written to " .. outputPath)
|
3
Capy64/Assets/Lua/CapyOS/boot/autorun/00_package.lua
Normal file
3
Capy64/Assets/Lua/CapyOS/boot/autorun/00_package.lua
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package.path = "/lib/?.lua;/lib/?/init.lua;" .. package.path
|
||||||
|
|
||||||
|
_G.io = require("io")
|
15
Capy64/Assets/Lua/CapyOS/boot/autorun/01_stdio.lua
Normal file
15
Capy64/Assets/Lua/CapyOS/boot/autorun/01_stdio.lua
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
function _G.print(...)
|
||||||
|
local args = { ... }
|
||||||
|
local size = #args
|
||||||
|
local lines = 0
|
||||||
|
for n, v in ipairs(args) do
|
||||||
|
local s = tostring(v)
|
||||||
|
if n < size then
|
||||||
|
s = s .. "\t"
|
||||||
|
end
|
||||||
|
lines = lines + io.write(s)
|
||||||
|
end
|
||||||
|
lines = lines + io.write("\n")
|
||||||
|
|
||||||
|
return lines
|
||||||
|
end
|
20
Capy64/Assets/Lua/CapyOS/boot/autorun/01_task.lua
Normal file
20
Capy64/Assets/Lua/CapyOS/boot/autorun/01_task.lua
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
local event = require("event")
|
||||||
|
|
||||||
|
local function awaiter(task)
|
||||||
|
local status = task:getStatus()
|
||||||
|
local uuid = task:getID()
|
||||||
|
if status == "running" then
|
||||||
|
local _, taskId, result, err
|
||||||
|
repeat
|
||||||
|
_, taskId, result, err = event.pull("task_finish")
|
||||||
|
until taskId == uuid
|
||||||
|
return result, err
|
||||||
|
elseif status == "succeeded" then
|
||||||
|
return task:getResult(), nil
|
||||||
|
elseif status == "failed" then
|
||||||
|
return nil, task:getError()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Second argument freezes the awaiter function, so it cannot be modified
|
||||||
|
event.setAwaiter(awaiter, true)
|
77
Capy64/Assets/Lua/CapyOS/boot/autorun/02_http.lua
Normal file
77
Capy64/Assets/Lua/CapyOS/boot/autorun/02_http.lua
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
local http = require("http")
|
||||||
|
local event = require("event")
|
||||||
|
local expect = require("expect").expect
|
||||||
|
|
||||||
|
|
||||||
|
function http.request(url, body, headers, options)
|
||||||
|
expect(1, url, "string")
|
||||||
|
expect(2, body, "string", "nil")
|
||||||
|
expect(3, headers, "table", "nil")
|
||||||
|
expect(4, options, "table", "nil")
|
||||||
|
|
||||||
|
if not http.checkURL(url) then
|
||||||
|
return nil, "Invalid URL"
|
||||||
|
end
|
||||||
|
|
||||||
|
local task<close> = http.requestAsync(url, body, headers, options)
|
||||||
|
return task:await()
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.get(url, headers, options)
|
||||||
|
expect(1, url, "string")
|
||||||
|
expect(2, headers, "table", "nil")
|
||||||
|
expect(3, options, "table", "nil")
|
||||||
|
|
||||||
|
return http.request(url, nil, headers, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.post(url, body, headers, options)
|
||||||
|
expect(1, url, "string")
|
||||||
|
expect(2, body, "string", "nil")
|
||||||
|
expect(3, headers, "table", "nil")
|
||||||
|
expect(4, options, "table", "nil")
|
||||||
|
|
||||||
|
return http.request(url, body, headers, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
local WebSocketHandle
|
||||||
|
local function buildWebsocketHandle(handle)
|
||||||
|
if not handle then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if not WebSocketHandle then
|
||||||
|
WebSocketHandle = getmetatable(handle) or { __index = {} }
|
||||||
|
function WebSocketHandle.__index:close()
|
||||||
|
self:closeAsync()
|
||||||
|
local _, id
|
||||||
|
repeat
|
||||||
|
_, id = event.pull("websocket_close")
|
||||||
|
until id == self:getRequestID()
|
||||||
|
end
|
||||||
|
|
||||||
|
function WebSocketHandle.__index:receive()
|
||||||
|
local _, id, par
|
||||||
|
repeat
|
||||||
|
_, id, par = event.pull("websocket_message")
|
||||||
|
until id == self:getRequestID()
|
||||||
|
|
||||||
|
return par
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return handle
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.websocket(url, headers)
|
||||||
|
expect(1, url, "string")
|
||||||
|
expect(2, headers, "table", "nil")
|
||||||
|
|
||||||
|
if not http.checkURL(url) then
|
||||||
|
return nil, "Invalid URL"
|
||||||
|
end
|
||||||
|
|
||||||
|
local task<close> = http.websocketAsync(url, headers)
|
||||||
|
local client, err = task:await()
|
||||||
|
|
||||||
|
return buildWebsocketHandle(client), err
|
||||||
|
end
|
14
Capy64/Assets/Lua/CapyOS/boot/autorun/02_timer.lua
Normal file
14
Capy64/Assets/Lua/CapyOS/boot/autorun/02_timer.lua
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
local timer = require("timer")
|
||||||
|
local event = require("event")
|
||||||
|
local expect = require("expect").expect
|
||||||
|
local range = require("expect").range
|
||||||
|
|
||||||
|
function timer.sleep(n)
|
||||||
|
expect(1, n, "number")
|
||||||
|
range(1, 1)
|
||||||
|
|
||||||
|
local timerId = timer.start(n)
|
||||||
|
repeat
|
||||||
|
local _, par = event.pull("timer")
|
||||||
|
until par == timerId
|
||||||
|
end
|
15
Capy64/Assets/Lua/CapyOS/boot/autorun/99_shell.lua
Normal file
15
Capy64/Assets/Lua/CapyOS/boot/autorun/99_shell.lua
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
local term = require("term")
|
||||||
|
local colors = require("colors")
|
||||||
|
local machine = require("machine")
|
||||||
|
|
||||||
|
term.setForeground(0x59c9ff)
|
||||||
|
term.setBackground(colors.black)
|
||||||
|
term.clear()
|
||||||
|
term.setPos(1, 1)
|
||||||
|
|
||||||
|
term.write(os.version())
|
||||||
|
term.setPos(1, 2)
|
||||||
|
|
||||||
|
dofile("/bin/shell.lua")
|
||||||
|
|
||||||
|
machine.shutdown()
|
BIN
Capy64/Assets/Lua/CapyOS/boot/vendor.bmp
Normal file
BIN
Capy64/Assets/Lua/CapyOS/boot/vendor.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
44
Capy64/Assets/Lua/CapyOS/init.lua
Normal file
44
Capy64/Assets/Lua/CapyOS/init.lua
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
local version = "0.0.2"
|
||||||
|
|
||||||
|
print("Starting CapyOS")
|
||||||
|
|
||||||
|
local term = require("term")
|
||||||
|
local fs = require("fs")
|
||||||
|
local gpu = require("gpu")
|
||||||
|
|
||||||
|
local nPrint = print
|
||||||
|
local function showError(err)
|
||||||
|
nPrint(err)
|
||||||
|
local x, y = term.getPos()
|
||||||
|
term.setForeground(0xff0000)
|
||||||
|
term.setPos(1, y)
|
||||||
|
term.write(err)
|
||||||
|
|
||||||
|
term.setPos(1, y + 1)
|
||||||
|
term.setForeground(0xffffff)
|
||||||
|
term.write("Press any key to continue")
|
||||||
|
|
||||||
|
coroutine.yield("key_down")
|
||||||
|
end
|
||||||
|
|
||||||
|
function os.version()
|
||||||
|
return "CapyOS " .. version
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setPos(1, 1)
|
||||||
|
term.write(_HOST)
|
||||||
|
|
||||||
|
local files = fs.list("/boot/autorun")
|
||||||
|
for i = 1, #files do
|
||||||
|
local func, err = loadfile("/boot/autorun/" .. files[i])
|
||||||
|
if not func then
|
||||||
|
showError(err)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = pcall(func)
|
||||||
|
if not ok then
|
||||||
|
showError(debug.traceback(err))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
94
Capy64/Assets/Lua/CapyOS/lib/colors.lua
Normal file
94
Capy64/Assets/Lua/CapyOS/lib/colors.lua
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
local expect = require("expect")
|
||||||
|
|
||||||
|
local palette = {
|
||||||
|
{
|
||||||
|
"white",
|
||||||
|
0xf0f0f0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"orange",
|
||||||
|
0xf2b233
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"magenta",
|
||||||
|
0xe57fd8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lightBlue",
|
||||||
|
0x99b2f2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"yellow",
|
||||||
|
0xdede6c
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lime",
|
||||||
|
0x7fcc19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pink",
|
||||||
|
0xf2b2cc
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gray",
|
||||||
|
0x4c4c4c
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lightGray",
|
||||||
|
0x999999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cyan",
|
||||||
|
0x4c99b2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"purple",
|
||||||
|
0xb266e5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blue",
|
||||||
|
0x3366cc
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brown",
|
||||||
|
0x7f664c
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"green",
|
||||||
|
0x57a64e
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"red",
|
||||||
|
0xcc4c4c
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"black",
|
||||||
|
0x111111
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local colors = {}
|
||||||
|
for k, v in ipairs(palette) do
|
||||||
|
colors[v[1]] = v[2]
|
||||||
|
colors[k] = v[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
function colors.packRGB(r, g, b)
|
||||||
|
expect(1, r, "number")
|
||||||
|
expect(2, g, "number")
|
||||||
|
expect(3, b, "number")
|
||||||
|
|
||||||
|
return (r << 16) +
|
||||||
|
(g << 8) +
|
||||||
|
b
|
||||||
|
end
|
||||||
|
|
||||||
|
function colors.unpackRGB(rgb)
|
||||||
|
expect(1, rgb, "number")
|
||||||
|
|
||||||
|
return (rgb >> 16) & 0xff,
|
||||||
|
(rgb >> 8) & 0xff,
|
||||||
|
rgb & 0xff
|
||||||
|
end
|
||||||
|
|
||||||
|
return colors;
|
52
Capy64/Assets/Lua/CapyOS/lib/expect.lua
Normal file
52
Capy64/Assets/Lua/CapyOS/lib/expect.lua
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
-- Credits: https://github.com/Ocawesome101/recrafted
|
||||||
|
|
||||||
|
-- cc.expect
|
||||||
|
|
||||||
|
local _expect = {}
|
||||||
|
|
||||||
|
local function checkType(index, valueType, value, ...)
|
||||||
|
local expected = table.pack(...)
|
||||||
|
local isType = false
|
||||||
|
|
||||||
|
for i = 1, expected.n, 1 do
|
||||||
|
if type(value) == expected[i] then
|
||||||
|
isType = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not isType then
|
||||||
|
error(string.format("bad %s %s (%s expected, got %s)", valueType,
|
||||||
|
index, table.concat(expected, " or "), type(value)), 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
function _expect.expect(index, value, ...)
|
||||||
|
return checkType(("#%d"):format(index), "argument", value, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _expect.field(tbl, index, ...)
|
||||||
|
_expect.expect(1, tbl, "table")
|
||||||
|
_expect.expect(2, index, "string")
|
||||||
|
return checkType(("%q"):format(index), "field", tbl[index], ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function _expect.range(num, min, max)
|
||||||
|
_expect.expect(1, num, "number")
|
||||||
|
_expect.expect(2, min, "number", "nil")
|
||||||
|
_expect.expect(3, max, "number", "nil")
|
||||||
|
min = min or -math.huge
|
||||||
|
max = max or math.huge
|
||||||
|
if num < min or num > max then
|
||||||
|
error(("number outside of range (expected %d to be within %d and %d")
|
||||||
|
:format(num, min, max), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(_expect, { __call = function(_, ...)
|
||||||
|
return _expect.expect(...)
|
||||||
|
end })
|
||||||
|
|
||||||
|
return _expect
|
275
Capy64/Assets/Lua/CapyOS/lib/io.lua
Normal file
275
Capy64/Assets/Lua/CapyOS/lib/io.lua
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
local expect = require("expect").expect
|
||||||
|
local event = require("event")
|
||||||
|
local term = require("term")
|
||||||
|
local keys = require("keys")
|
||||||
|
local machine = require("machine")
|
||||||
|
|
||||||
|
local io = {}
|
||||||
|
|
||||||
|
function io.write(text)
|
||||||
|
text = tostring(text)
|
||||||
|
|
||||||
|
local lines = 0
|
||||||
|
local w, h = term.getSize()
|
||||||
|
|
||||||
|
local function inc_cy(cy)
|
||||||
|
lines = lines + 1
|
||||||
|
|
||||||
|
if cy > h - 1 then
|
||||||
|
term.scroll(1)
|
||||||
|
return cy
|
||||||
|
else
|
||||||
|
return cy + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while #text > 0 do
|
||||||
|
local nl = text:find("\n") or #text
|
||||||
|
local chunk = text:sub(1, nl)
|
||||||
|
text = text:sub(#chunk + 1)
|
||||||
|
|
||||||
|
local has_nl = chunk:sub( -1) == "\n"
|
||||||
|
if has_nl then chunk = chunk:sub(1, -2) end
|
||||||
|
|
||||||
|
local cx, cy = term.getPos()
|
||||||
|
while #chunk > 0 do
|
||||||
|
if cx > w then
|
||||||
|
term.setPos(1, inc_cy(cy))
|
||||||
|
cx, cy = term.getPos()
|
||||||
|
end
|
||||||
|
|
||||||
|
local to_write = chunk:sub(1, w - cx + 1)
|
||||||
|
term.write(to_write)
|
||||||
|
|
||||||
|
chunk = chunk:sub(#to_write + 1)
|
||||||
|
cx, cy = term.getPos()
|
||||||
|
end
|
||||||
|
|
||||||
|
if has_nl then
|
||||||
|
term.setPos(1, inc_cy(cy))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return lines
|
||||||
|
end
|
||||||
|
|
||||||
|
local empty = {}
|
||||||
|
function io.read(replace, history, complete, default)
|
||||||
|
expect(1, replace, "string", "nil")
|
||||||
|
expect(2, history, "table", "nil")
|
||||||
|
expect(3, complete, "function", "nil")
|
||||||
|
expect(4, default, "string", "nil")
|
||||||
|
|
||||||
|
if replace then replace = replace:sub(1, 1) end
|
||||||
|
local hist = history or {}
|
||||||
|
history = {}
|
||||||
|
for i = 1, #hist, 1 do
|
||||||
|
history[i] = hist[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
local buffer = default or ""
|
||||||
|
local prev_buf = buffer
|
||||||
|
history[#history + 1] = buffer
|
||||||
|
|
||||||
|
local hist_pos = #history
|
||||||
|
local cursor_pos = 0
|
||||||
|
|
||||||
|
local stx, sty = term.getPos()
|
||||||
|
local w, h = term.getSize()
|
||||||
|
|
||||||
|
local dirty = false
|
||||||
|
local completions = {}
|
||||||
|
local comp_id = 0
|
||||||
|
|
||||||
|
local function clearCompletion()
|
||||||
|
if completions[comp_id] then
|
||||||
|
write((" "):rep(#completions[comp_id]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function full_redraw(force)
|
||||||
|
if force or dirty then
|
||||||
|
if complete and buffer ~= prev_buf then
|
||||||
|
completions = complete(buffer) or empty
|
||||||
|
comp_id = math.min(1, #completions)
|
||||||
|
end
|
||||||
|
prev_buf = buffer
|
||||||
|
|
||||||
|
term.setPos(stx, sty)
|
||||||
|
local text = buffer
|
||||||
|
if replace then text = replace:rep(#text) end
|
||||||
|
local ln = io.write(text)
|
||||||
|
|
||||||
|
if completions[comp_id] then
|
||||||
|
local oldfg = term.getForeground()
|
||||||
|
local oldbg = term.getBackground()
|
||||||
|
term.setForeground(colors.white)
|
||||||
|
term.setBackground(colors.gray)
|
||||||
|
ln = ln + write(completions[comp_id])
|
||||||
|
term.setForeground(oldfg)
|
||||||
|
term.setBackground(oldbg)
|
||||||
|
else
|
||||||
|
ln = ln + io.write(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
if sty + ln > h then
|
||||||
|
sty = sty - (sty + ln - h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set cursor to the appropriate spot
|
||||||
|
local cx, cy = stx, sty
|
||||||
|
cx = cx + #buffer - cursor_pos -- + #(completions[comp_id] or "")
|
||||||
|
while cx > w do
|
||||||
|
cx = cx - w
|
||||||
|
cy = cy + 1
|
||||||
|
end
|
||||||
|
term.setPos(cx, cy)
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setBlink(true)
|
||||||
|
|
||||||
|
while true do
|
||||||
|
full_redraw()
|
||||||
|
-- get input
|
||||||
|
local evt, par1, par2, mods = event.pull()
|
||||||
|
|
||||||
|
if evt == "char" then
|
||||||
|
dirty = true
|
||||||
|
clearCompletion()
|
||||||
|
if cursor_pos == 0 then
|
||||||
|
buffer = buffer .. par1
|
||||||
|
elseif cursor_pos == #buffer then
|
||||||
|
buffer = par1 .. buffer
|
||||||
|
else
|
||||||
|
buffer = buffer:sub(0, -cursor_pos - 1) .. par1 .. buffer:sub( -cursor_pos)
|
||||||
|
end
|
||||||
|
elseif evt == "key_down" then
|
||||||
|
if par1 == keys.back and #buffer > 0 then
|
||||||
|
dirty = true
|
||||||
|
if cursor_pos == 0 then
|
||||||
|
buffer = buffer:sub(1, -2)
|
||||||
|
clearCompletion()
|
||||||
|
elseif cursor_pos < #buffer then
|
||||||
|
buffer = buffer:sub(0, -cursor_pos - 2) .. buffer:sub( -cursor_pos)
|
||||||
|
end
|
||||||
|
elseif par1 == keys.delete and cursor_pos > 0 then
|
||||||
|
dirty = true
|
||||||
|
|
||||||
|
if cursor_pos == #buffer then
|
||||||
|
buffer = buffer:sub(2)
|
||||||
|
elseif cursor_pos == 1 then
|
||||||
|
buffer = buffer:sub(1, -2)
|
||||||
|
else
|
||||||
|
buffer = buffer:sub(0, -cursor_pos - 1) .. buffer:sub( -cursor_pos + 1)
|
||||||
|
end
|
||||||
|
cursor_pos = cursor_pos - 1
|
||||||
|
elseif par1 == keys.up then
|
||||||
|
if #completions > 1 then
|
||||||
|
dirty = true
|
||||||
|
clearCompletion()
|
||||||
|
if comp_id > 1 then
|
||||||
|
comp_id = comp_id - 1
|
||||||
|
else
|
||||||
|
comp_id = #completions
|
||||||
|
end
|
||||||
|
elseif hist_pos > 1 then
|
||||||
|
cursor_pos = 0
|
||||||
|
|
||||||
|
history[hist_pos] = buffer
|
||||||
|
hist_pos = hist_pos - 1
|
||||||
|
|
||||||
|
buffer = (" "):rep(#buffer)
|
||||||
|
full_redraw(true)
|
||||||
|
|
||||||
|
buffer = history[hist_pos]
|
||||||
|
dirty = true
|
||||||
|
end
|
||||||
|
elseif par1 == keys.down then
|
||||||
|
if #completions > 1 then
|
||||||
|
dirty = true
|
||||||
|
clearCompletion()
|
||||||
|
if comp_id < #completions then
|
||||||
|
comp_id = comp_id + 1
|
||||||
|
else
|
||||||
|
comp_id = 1
|
||||||
|
end
|
||||||
|
elseif hist_pos < #history then
|
||||||
|
cursor_pos = 0
|
||||||
|
|
||||||
|
history[hist_pos] = buffer
|
||||||
|
hist_pos = hist_pos + 1
|
||||||
|
|
||||||
|
buffer = (" "):rep(#buffer)
|
||||||
|
full_redraw(true)
|
||||||
|
|
||||||
|
buffer = history[hist_pos]
|
||||||
|
dirty = true
|
||||||
|
end
|
||||||
|
elseif par1 == keys.left then
|
||||||
|
if cursor_pos < #buffer then
|
||||||
|
clearCompletion()
|
||||||
|
cursor_pos = cursor_pos + 1
|
||||||
|
end
|
||||||
|
elseif par1 == keys.right then
|
||||||
|
if cursor_pos > 0 then
|
||||||
|
cursor_pos = cursor_pos - 1
|
||||||
|
elseif comp_id > 0 then
|
||||||
|
dirty = true
|
||||||
|
buffer = buffer .. completions[comp_id]
|
||||||
|
end
|
||||||
|
elseif par1 == keys.tab then
|
||||||
|
if comp_id > 0 then
|
||||||
|
dirty = true
|
||||||
|
buffer = buffer .. completions[comp_id]
|
||||||
|
end
|
||||||
|
elseif par1 == keys.home then
|
||||||
|
cursor_pos = #buffer
|
||||||
|
elseif par1 == keys["end"] then
|
||||||
|
cursor_pos = 0
|
||||||
|
elseif par1 == keys.enter then
|
||||||
|
clearCompletion()
|
||||||
|
print()
|
||||||
|
break
|
||||||
|
elseif mods & keys.mods.ctrl ~= 0 then
|
||||||
|
if par1 == keys.v then
|
||||||
|
dirty = true
|
||||||
|
clearCompletion()
|
||||||
|
local text = machine.getClipboard()
|
||||||
|
if text then
|
||||||
|
if cursor_pos == 0 then
|
||||||
|
buffer = buffer .. text
|
||||||
|
elseif cursor_pos == #buffer then
|
||||||
|
buffer = text .. buffer
|
||||||
|
else
|
||||||
|
buffer = buffer:sub(0, -cursor_pos - 1) .. text ..
|
||||||
|
buffer:sub( -cursor_pos + (#text - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setBlink(false)
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
io.stderr = {}
|
||||||
|
|
||||||
|
function io.stderr.write(text)
|
||||||
|
local fg = term.getForeground()
|
||||||
|
term.setForeground(0xff0000)
|
||||||
|
io.write(text)
|
||||||
|
term.setForeground(fg)
|
||||||
|
end
|
||||||
|
|
||||||
|
function io.stderr.print(...)
|
||||||
|
local fg = term.getForeground()
|
||||||
|
term.setForeground(0xff0000)
|
||||||
|
print(...)
|
||||||
|
term.setForeground(fg)
|
||||||
|
end
|
||||||
|
|
||||||
|
return io
|
388
Capy64/Assets/Lua/CapyOS/lib/json.lua
Normal file
388
Capy64/Assets/Lua/CapyOS/lib/json.lua
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
--
|
||||||
|
-- json.lua
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2020 rxi
|
||||||
|
--
|
||||||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
-- this software and associated documentation files (the "Software"), to deal in
|
||||||
|
-- the Software without restriction, including without limitation the rights to
|
||||||
|
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
-- of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
-- so, subject to the following conditions:
|
||||||
|
--
|
||||||
|
-- The above copyright notice and this permission notice shall be included in all
|
||||||
|
-- copies or substantial portions of the Software.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
-- SOFTWARE.
|
||||||
|
--
|
||||||
|
|
||||||
|
local json = { _version = "0.1.2" }
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Encode
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local encode
|
||||||
|
|
||||||
|
local escape_char_map = {
|
||||||
|
[ "\\" ] = "\\",
|
||||||
|
[ "\"" ] = "\"",
|
||||||
|
[ "\b" ] = "b",
|
||||||
|
[ "\f" ] = "f",
|
||||||
|
[ "\n" ] = "n",
|
||||||
|
[ "\r" ] = "r",
|
||||||
|
[ "\t" ] = "t",
|
||||||
|
}
|
||||||
|
|
||||||
|
local escape_char_map_inv = { [ "/" ] = "/" }
|
||||||
|
for k, v in pairs(escape_char_map) do
|
||||||
|
escape_char_map_inv[v] = k
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function escape_char(c)
|
||||||
|
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_nil(val)
|
||||||
|
return "null"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_table(val, stack)
|
||||||
|
local res = {}
|
||||||
|
stack = stack or {}
|
||||||
|
|
||||||
|
-- Circular reference?
|
||||||
|
if stack[val] then error("circular reference") end
|
||||||
|
|
||||||
|
stack[val] = true
|
||||||
|
|
||||||
|
if rawget(val, 1) ~= nil or next(val) == nil then
|
||||||
|
-- Treat as array -- check keys are valid and it is not sparse
|
||||||
|
local n = 0
|
||||||
|
for k in pairs(val) do
|
||||||
|
if type(k) ~= "number" then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
if n ~= #val then
|
||||||
|
error("invalid table: sparse array")
|
||||||
|
end
|
||||||
|
-- Encode
|
||||||
|
for i, v in ipairs(val) do
|
||||||
|
table.insert(res, encode(v, stack))
|
||||||
|
end
|
||||||
|
stack[val] = nil
|
||||||
|
return "[" .. table.concat(res, ",") .. "]"
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Treat as an object
|
||||||
|
for k, v in pairs(val) do
|
||||||
|
if type(k) ~= "string" then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
|
||||||
|
end
|
||||||
|
stack[val] = nil
|
||||||
|
return "{" .. table.concat(res, ",") .. "}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_string(val)
|
||||||
|
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_number(val)
|
||||||
|
-- Check for NaN, -inf and inf
|
||||||
|
if val ~= val or val <= -math.huge or val >= math.huge then
|
||||||
|
error("unexpected number value '" .. tostring(val) .. "'")
|
||||||
|
end
|
||||||
|
return string.format("%.14g", val)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local type_func_map = {
|
||||||
|
[ "nil" ] = encode_nil,
|
||||||
|
[ "table" ] = encode_table,
|
||||||
|
[ "string" ] = encode_string,
|
||||||
|
[ "number" ] = encode_number,
|
||||||
|
[ "boolean" ] = tostring,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
encode = function(val, stack)
|
||||||
|
local t = type(val)
|
||||||
|
local f = type_func_map[t]
|
||||||
|
if f then
|
||||||
|
return f(val, stack)
|
||||||
|
end
|
||||||
|
error("unexpected type '" .. t .. "'")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function json.encode(val)
|
||||||
|
return ( encode(val) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Decode
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local parse
|
||||||
|
|
||||||
|
local function create_set(...)
|
||||||
|
local res = {}
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
res[ select(i, ...) ] = true
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
local space_chars = create_set(" ", "\t", "\r", "\n")
|
||||||
|
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
||||||
|
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
||||||
|
local literals = create_set("true", "false", "null")
|
||||||
|
|
||||||
|
local literal_map = {
|
||||||
|
[ "true" ] = true,
|
||||||
|
[ "false" ] = false,
|
||||||
|
[ "null" ] = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local function next_char(str, idx, set, negate)
|
||||||
|
for i = idx, #str do
|
||||||
|
if set[str:sub(i, i)] ~= negate then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return #str + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function decode_error(str, idx, msg)
|
||||||
|
local line_count = 1
|
||||||
|
local col_count = 1
|
||||||
|
for i = 1, idx - 1 do
|
||||||
|
col_count = col_count + 1
|
||||||
|
if str:sub(i, i) == "\n" then
|
||||||
|
line_count = line_count + 1
|
||||||
|
col_count = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function codepoint_to_utf8(n)
|
||||||
|
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
|
||||||
|
local f = math.floor
|
||||||
|
if n <= 0x7f then
|
||||||
|
return string.char(n)
|
||||||
|
elseif n <= 0x7ff then
|
||||||
|
return string.char(f(n / 64) + 192, n % 64 + 128)
|
||||||
|
elseif n <= 0xffff then
|
||||||
|
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||||
|
elseif n <= 0x10ffff then
|
||||||
|
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
|
||||||
|
f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||||
|
end
|
||||||
|
error( string.format("invalid unicode codepoint '%x'", n) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_unicode_escape(s)
|
||||||
|
local n1 = tonumber( s:sub(1, 4), 16 )
|
||||||
|
local n2 = tonumber( s:sub(7, 10), 16 )
|
||||||
|
-- Surrogate pair?
|
||||||
|
if n2 then
|
||||||
|
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
|
||||||
|
else
|
||||||
|
return codepoint_to_utf8(n1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_string(str, i)
|
||||||
|
local res = ""
|
||||||
|
local j = i + 1
|
||||||
|
local k = j
|
||||||
|
|
||||||
|
while j <= #str do
|
||||||
|
local x = str:byte(j)
|
||||||
|
|
||||||
|
if x < 32 then
|
||||||
|
decode_error(str, j, "control character in string")
|
||||||
|
|
||||||
|
elseif x == 92 then -- `\`: Escape
|
||||||
|
res = res .. str:sub(k, j - 1)
|
||||||
|
j = j + 1
|
||||||
|
local c = str:sub(j, j)
|
||||||
|
if c == "u" then
|
||||||
|
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
|
||||||
|
or str:match("^%x%x%x%x", j + 1)
|
||||||
|
or decode_error(str, j - 1, "invalid unicode escape in string")
|
||||||
|
res = res .. parse_unicode_escape(hex)
|
||||||
|
j = j + #hex
|
||||||
|
else
|
||||||
|
if not escape_chars[c] then
|
||||||
|
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
|
||||||
|
end
|
||||||
|
res = res .. escape_char_map_inv[c]
|
||||||
|
end
|
||||||
|
k = j + 1
|
||||||
|
|
||||||
|
elseif x == 34 then -- `"`: End of string
|
||||||
|
res = res .. str:sub(k, j - 1)
|
||||||
|
return res, j + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
decode_error(str, i, "expected closing quote for string")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_number(str, i)
|
||||||
|
local x = next_char(str, i, delim_chars)
|
||||||
|
local s = str:sub(i, x - 1)
|
||||||
|
local n = tonumber(s)
|
||||||
|
if not n then
|
||||||
|
decode_error(str, i, "invalid number '" .. s .. "'")
|
||||||
|
end
|
||||||
|
return n, x
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_literal(str, i)
|
||||||
|
local x = next_char(str, i, delim_chars)
|
||||||
|
local word = str:sub(i, x - 1)
|
||||||
|
if not literals[word] then
|
||||||
|
decode_error(str, i, "invalid literal '" .. word .. "'")
|
||||||
|
end
|
||||||
|
return literal_map[word], x
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_array(str, i)
|
||||||
|
local res = {}
|
||||||
|
local n = 1
|
||||||
|
i = i + 1
|
||||||
|
while 1 do
|
||||||
|
local x
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
-- Empty / end of array?
|
||||||
|
if str:sub(i, i) == "]" then
|
||||||
|
i = i + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- Read token
|
||||||
|
x, i = parse(str, i)
|
||||||
|
res[n] = x
|
||||||
|
n = n + 1
|
||||||
|
-- Next token
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
local chr = str:sub(i, i)
|
||||||
|
i = i + 1
|
||||||
|
if chr == "]" then break end
|
||||||
|
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
|
||||||
|
end
|
||||||
|
return res, i
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_object(str, i)
|
||||||
|
local res = {}
|
||||||
|
i = i + 1
|
||||||
|
while 1 do
|
||||||
|
local key, val
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
-- Empty / end of object?
|
||||||
|
if str:sub(i, i) == "}" then
|
||||||
|
i = i + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- Read key
|
||||||
|
if str:sub(i, i) ~= '"' then
|
||||||
|
decode_error(str, i, "expected string for key")
|
||||||
|
end
|
||||||
|
key, i = parse(str, i)
|
||||||
|
-- Read ':' delimiter
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
if str:sub(i, i) ~= ":" then
|
||||||
|
decode_error(str, i, "expected ':' after key")
|
||||||
|
end
|
||||||
|
i = next_char(str, i + 1, space_chars, true)
|
||||||
|
-- Read value
|
||||||
|
val, i = parse(str, i)
|
||||||
|
-- Set
|
||||||
|
res[key] = val
|
||||||
|
-- Next token
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
local chr = str:sub(i, i)
|
||||||
|
i = i + 1
|
||||||
|
if chr == "}" then break end
|
||||||
|
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
|
||||||
|
end
|
||||||
|
return res, i
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local char_func_map = {
|
||||||
|
[ '"' ] = parse_string,
|
||||||
|
[ "0" ] = parse_number,
|
||||||
|
[ "1" ] = parse_number,
|
||||||
|
[ "2" ] = parse_number,
|
||||||
|
[ "3" ] = parse_number,
|
||||||
|
[ "4" ] = parse_number,
|
||||||
|
[ "5" ] = parse_number,
|
||||||
|
[ "6" ] = parse_number,
|
||||||
|
[ "7" ] = parse_number,
|
||||||
|
[ "8" ] = parse_number,
|
||||||
|
[ "9" ] = parse_number,
|
||||||
|
[ "-" ] = parse_number,
|
||||||
|
[ "t" ] = parse_literal,
|
||||||
|
[ "f" ] = parse_literal,
|
||||||
|
[ "n" ] = parse_literal,
|
||||||
|
[ "[" ] = parse_array,
|
||||||
|
[ "{" ] = parse_object,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse = function(str, idx)
|
||||||
|
local chr = str:sub(idx, idx)
|
||||||
|
local f = char_func_map[chr]
|
||||||
|
if f then
|
||||||
|
return f(str, idx)
|
||||||
|
end
|
||||||
|
decode_error(str, idx, "unexpected character '" .. chr .. "'")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function json.decode(str)
|
||||||
|
if type(str) ~= "string" then
|
||||||
|
error("expected argument of type string, got " .. type(str))
|
||||||
|
end
|
||||||
|
local res, idx = parse(str, next_char(str, 1, space_chars, true))
|
||||||
|
idx = next_char(str, idx, space_chars, true)
|
||||||
|
if idx <= #str then
|
||||||
|
decode_error(str, idx, "trailing garbage")
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return json
|
179
Capy64/Assets/Lua/CapyOS/lib/keys.lua
Normal file
179
Capy64/Assets/Lua/CapyOS/lib/keys.lua
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
local keys = {
|
||||||
|
none = 0,
|
||||||
|
back = 8,
|
||||||
|
tab = 9,
|
||||||
|
enter = 13,
|
||||||
|
pause = 19,
|
||||||
|
caps_lock = 20,
|
||||||
|
kana = 21,
|
||||||
|
kanji = 25,
|
||||||
|
escape = 27,
|
||||||
|
ime_convert = 28,
|
||||||
|
ime_no_convert = 29,
|
||||||
|
space = 32,
|
||||||
|
page_up = 33,
|
||||||
|
page_down = 34,
|
||||||
|
["end"] = 35,
|
||||||
|
home = 36,
|
||||||
|
left = 37,
|
||||||
|
up = 38,
|
||||||
|
right = 39,
|
||||||
|
down = 40,
|
||||||
|
select = 41,
|
||||||
|
print = 42,
|
||||||
|
execute = 43,
|
||||||
|
print_screen = 44,
|
||||||
|
insert = 45,
|
||||||
|
delete = 46,
|
||||||
|
help = 47,
|
||||||
|
zero = 48,
|
||||||
|
one = 49,
|
||||||
|
two = 50,
|
||||||
|
three = 51,
|
||||||
|
four = 52,
|
||||||
|
five = 53,
|
||||||
|
six = 54,
|
||||||
|
seven = 55,
|
||||||
|
eight = 56,
|
||||||
|
nine = 57,
|
||||||
|
a = 65,
|
||||||
|
b = 66,
|
||||||
|
c = 67,
|
||||||
|
d = 68,
|
||||||
|
e = 69,
|
||||||
|
f = 70,
|
||||||
|
g = 71,
|
||||||
|
h = 72,
|
||||||
|
i = 73,
|
||||||
|
j = 74,
|
||||||
|
k = 75,
|
||||||
|
l = 76,
|
||||||
|
m = 77,
|
||||||
|
n = 78,
|
||||||
|
o = 79,
|
||||||
|
p = 80,
|
||||||
|
q = 81,
|
||||||
|
r = 82,
|
||||||
|
s = 83,
|
||||||
|
t = 84,
|
||||||
|
u = 85,
|
||||||
|
v = 86,
|
||||||
|
w = 87,
|
||||||
|
x = 88,
|
||||||
|
y = 89,
|
||||||
|
z = 90,
|
||||||
|
left_windows = 91,
|
||||||
|
right_windows = 92,
|
||||||
|
apps = 93,
|
||||||
|
sleep = 95,
|
||||||
|
num_pad0 = 96,
|
||||||
|
num_pad1 = 97,
|
||||||
|
num_pad2 = 98,
|
||||||
|
num_pad3 = 99,
|
||||||
|
num_pad4 = 100,
|
||||||
|
num_pad5 = 101,
|
||||||
|
num_pad6 = 102,
|
||||||
|
num_pad7 = 103,
|
||||||
|
num_pad8 = 104,
|
||||||
|
num_pad9 = 105,
|
||||||
|
multiply = 106,
|
||||||
|
add = 107,
|
||||||
|
separator = 108,
|
||||||
|
subtract = 109,
|
||||||
|
decimal = 110,
|
||||||
|
divide = 111,
|
||||||
|
f1 = 112,
|
||||||
|
f2 = 113,
|
||||||
|
f3 = 114,
|
||||||
|
f4 = 115,
|
||||||
|
f5 = 116,
|
||||||
|
f6 = 117,
|
||||||
|
f7 = 118,
|
||||||
|
f8 = 119,
|
||||||
|
f9 = 120,
|
||||||
|
f10 = 121,
|
||||||
|
f11 = 122,
|
||||||
|
f12 = 123,
|
||||||
|
f13 = 124,
|
||||||
|
f14 = 125,
|
||||||
|
f15 = 126,
|
||||||
|
f16 = 127,
|
||||||
|
f17 = 128,
|
||||||
|
f18 = 129,
|
||||||
|
f19 = 130,
|
||||||
|
f20 = 131,
|
||||||
|
f21 = 132,
|
||||||
|
f22 = 133,
|
||||||
|
f23 = 134,
|
||||||
|
f24 = 135,
|
||||||
|
num_lock = 144,
|
||||||
|
scroll = 145,
|
||||||
|
left_shift = 160,
|
||||||
|
right_shift = 161,
|
||||||
|
left_control = 162,
|
||||||
|
right_control = 163,
|
||||||
|
left_alt = 164,
|
||||||
|
right_alt = 165,
|
||||||
|
browser_back = 166,
|
||||||
|
browser_forward = 167,
|
||||||
|
browser_refresh = 168,
|
||||||
|
browser_stop = 169,
|
||||||
|
browser_search = 170,
|
||||||
|
browser_favorites = 171,
|
||||||
|
browser_home = 172,
|
||||||
|
volume_mute = 173,
|
||||||
|
volume_down = 174,
|
||||||
|
volume_up = 175,
|
||||||
|
media_next_track = 176,
|
||||||
|
media_previous_track = 177,
|
||||||
|
media_stop = 178,
|
||||||
|
media_play_pause = 179,
|
||||||
|
launch_mail = 180,
|
||||||
|
select_media = 181,
|
||||||
|
launch_application1 = 182,
|
||||||
|
launch_application2 = 183,
|
||||||
|
semicolon = 186,
|
||||||
|
plus = 187,
|
||||||
|
comma = 188,
|
||||||
|
minus = 189,
|
||||||
|
period = 190,
|
||||||
|
question = 191,
|
||||||
|
tilde = 192,
|
||||||
|
chat_pad_green = 202,
|
||||||
|
chat_pad_orange = 203,
|
||||||
|
open_brackets = 219,
|
||||||
|
pipe = 220,
|
||||||
|
close_brackets = 221,
|
||||||
|
quotes = 222,
|
||||||
|
oem8 = 223,
|
||||||
|
backslash = 226,
|
||||||
|
process_key = 229,
|
||||||
|
copy = 242,
|
||||||
|
auto = 243,
|
||||||
|
enl_w = 244,
|
||||||
|
attn = 246,
|
||||||
|
crsel = 247,
|
||||||
|
exsel = 248,
|
||||||
|
erase_eof = 249,
|
||||||
|
play = 250,
|
||||||
|
zoom = 251,
|
||||||
|
pa1 = 253,
|
||||||
|
clear = 254,
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.mods = {
|
||||||
|
none = 0,
|
||||||
|
left_shift = 1,
|
||||||
|
right_shift = 2,
|
||||||
|
left_alt = 4,
|
||||||
|
right_alt = 8,
|
||||||
|
left_control = 16,
|
||||||
|
right_control = 32,
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.mods.shift = keys.mods.left_shift | keys.mods.right_shift
|
||||||
|
keys.mods.alt = keys.mods.left_alt | keys.mods.right_alt
|
||||||
|
keys.mods.control = keys.mods.left_control | keys.mods.right_control
|
||||||
|
keys.mods.ctrl = keys.mods.control
|
||||||
|
|
||||||
|
return keys
|
61
Capy64/Assets/Lua/CapyOS/lib/parallel.lua
Normal file
61
Capy64/Assets/Lua/CapyOS/lib/parallel.lua
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
local expect = require("expect")
|
||||||
|
|
||||||
|
local parallel = {}
|
||||||
|
|
||||||
|
local function contains(array, value)
|
||||||
|
for k, v in pairs(array) do
|
||||||
|
if v == value then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run(threads, exitOnAny)
|
||||||
|
local alive = #threads
|
||||||
|
local filters = {}
|
||||||
|
local ev = {}
|
||||||
|
while true do
|
||||||
|
for i, thread in pairs(threads) do
|
||||||
|
if not filters[i] or #filters[i] == 0 or contains(filters[i], ev[1]) or ev[1] == "interrupt" then
|
||||||
|
local pars = table.pack(coroutine.resume(thread, table.unpack(ev)))
|
||||||
|
if pars[1] then
|
||||||
|
filters[i] = table.pack(table.unpack(pars, 2))
|
||||||
|
else
|
||||||
|
error(pars[2], 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if coroutine.status(thread) == "dead" then
|
||||||
|
alive = alive - 1
|
||||||
|
if exitOnAny or alive <= 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ev = table.pack(coroutine.yield())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function parallel.waitForAll(...)
|
||||||
|
local threads = {}
|
||||||
|
for k, v in ipairs({ ... }) do
|
||||||
|
expect(k, v, "function")
|
||||||
|
table.insert(threads, coroutine.create(v))
|
||||||
|
end
|
||||||
|
|
||||||
|
return run(threads, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function parallel.waitForAny(...)
|
||||||
|
local threads = {}
|
||||||
|
for k, v in ipairs({ ... }) do
|
||||||
|
expect(k, v, "function")
|
||||||
|
table.insert(threads, coroutine.create(v))
|
||||||
|
end
|
||||||
|
|
||||||
|
return run(threads, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
return parallel
|
1776
Capy64/Assets/Lua/CapyOS/lib/utfstring.lua
Normal file
1776
Capy64/Assets/Lua/CapyOS/lib/utfstring.lua
Normal file
File diff suppressed because it is too large
Load diff
5
Capy64/Assets/Lua/README.txt
Normal file
5
Capy64/Assets/Lua/README.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
If you are looking for your data directory look in:
|
||||||
|
|
||||||
|
Windows: %APPDATA%\Capy64\data
|
||||||
|
Mac: $HOME/.local/share/Capy64/data
|
||||||
|
Linux: $HOME/.local/share/Capy64/data
|
|
@ -19,13 +19,8 @@ local gpu = require("gpu")
|
||||||
local fs = require("fs")
|
local fs = require("fs")
|
||||||
local machine = require("machine")
|
local machine = require("machine")
|
||||||
local audio = require("audio")
|
local audio = require("audio")
|
||||||
local http = require("http")
|
|
||||||
local event = require("event")
|
local event = require("event")
|
||||||
|
|
||||||
|
|
||||||
local INDEX_URL = "https://raw.github.com/Ale32bit/CapyOS/deploy/index.json"
|
|
||||||
local JSON_URL = "https://raw.github.com/Ale32bit/CapyOS/main/lib/json.lua"
|
|
||||||
|
|
||||||
local bootSleep = 2000
|
local bootSleep = 2000
|
||||||
local bg = 0x0
|
local bg = 0x0
|
||||||
local fg = 0xffffff
|
local fg = 0xffffff
|
||||||
|
@ -95,64 +90,11 @@ local function printError( text )
|
||||||
term.setForeground(0xffffff)
|
term.setForeground(0xffffff)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function hget(url, headers)
|
|
||||||
local response, err = http.requestAsync(url, nul, headers, {binary = true}):await()
|
|
||||||
|
|
||||||
if not response then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
|
|
||||||
local content = response.content:read("a")
|
|
||||||
response.content:close()
|
|
||||||
return content, response
|
|
||||||
end
|
|
||||||
|
|
||||||
local function promptKey()
|
local function promptKey()
|
||||||
print("Press any key to continue")
|
print("Press any key to continue")
|
||||||
event.pull("key_down")
|
event.pull("key_down")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function installOS()
|
|
||||||
term.clear()
|
|
||||||
term.setPos(1, 1)
|
|
||||||
|
|
||||||
print("Installing CapyOS...")
|
|
||||||
|
|
||||||
local jsonLib, par = hget(JSON_URL)
|
|
||||||
if not jsonLib then
|
|
||||||
printError(par)
|
|
||||||
promptKey()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local json = load(jsonLib)()
|
|
||||||
local indexData, par = hget(INDEX_URL)
|
|
||||||
if not indexData then
|
|
||||||
printError(par)
|
|
||||||
promptKey()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local index = json.decode(indexData)
|
|
||||||
|
|
||||||
for i, v in ipairs(index) do
|
|
||||||
local dirname = fs.getDir(v.path)
|
|
||||||
if not fs.exists(dirname) then
|
|
||||||
fs.makeDir(dirname)
|
|
||||||
end
|
|
||||||
print("Downloading " .. v.path)
|
|
||||||
local fileContent = hget(v.raw_url)
|
|
||||||
local f = fs.open(v.path, "w")
|
|
||||||
f:write(fileContent)
|
|
||||||
f:close()
|
|
||||||
print("Written to " .. v.path)
|
|
||||||
end
|
|
||||||
|
|
||||||
flagInstalled()
|
|
||||||
|
|
||||||
print("CapyOS installed!")
|
|
||||||
promptKey()
|
|
||||||
end
|
|
||||||
|
|
||||||
term.setBlink(false)
|
term.setBlink(false)
|
||||||
|
|
||||||
local function setupScreen()
|
local function setupScreen()
|
||||||
|
@ -245,10 +187,6 @@ end
|
||||||
|
|
||||||
audio.beep(1000, 0.2, 0.2, "square")
|
audio.beep(1000, 0.2, 0.2, "square")
|
||||||
|
|
||||||
if shouldInstallOS() then
|
|
||||||
installOS()
|
|
||||||
end
|
|
||||||
|
|
||||||
bootScreen()
|
bootScreen()
|
||||||
|
|
||||||
term.clear()
|
term.clear()
|
|
@ -26,9 +26,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Assets\Lua/**">
|
<Content Include="Assets\Lua\**">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE">
|
<None Include="..\LICENSE">
|
||||||
|
@ -46,17 +46,15 @@
|
||||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
||||||
<PackageReference Include="System.ComponentModel.Composition" Version="7.0.0" />
|
<PackageReference Include="System.ComponentModel.Composition" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Update="Assets\bios.lua">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
|
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
|
||||||
<Message Text="Restoring dotnet tools" Importance="High" />
|
<Message Text="Restoring dotnet tools" Importance="High" />
|
||||||
<Exec Command="dotnet tool restore" />
|
<Exec Command="dotnet tool restore" />
|
||||||
</Target>
|
</Target>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EditorConfigFiles Remove="C:\Users\Alex\source\repos\Capy64\Capy64\Capy64\.editorconfig" />
|
<EditorConfigFiles Remove="C:\Users\Alex\source\repos\Capy64\Capy64\Capy64\.editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Assets\Lua\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
|
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
|
||||||
|
|
|
@ -97,6 +97,8 @@ internal class RuntimeManager : IComponent
|
||||||
{
|
{
|
||||||
_game.Discord.SetPresence("Booting up...");
|
_game.Discord.SetPresence("Booting up...");
|
||||||
|
|
||||||
|
InstallOS(false);
|
||||||
|
|
||||||
luaState = new LuaState();
|
luaState = new LuaState();
|
||||||
_game.LuaRuntime = luaState;
|
_game.LuaRuntime = luaState;
|
||||||
luaState.Init();
|
luaState.Init();
|
||||||
|
@ -114,16 +116,13 @@ internal class RuntimeManager : IComponent
|
||||||
luaState.Thread.PushCFunction(L_OpenDataFolder);
|
luaState.Thread.PushCFunction(L_OpenDataFolder);
|
||||||
luaState.Thread.SetGlobal("openDataFolder");
|
luaState.Thread.SetGlobal("openDataFolder");
|
||||||
|
|
||||||
luaState.Thread.PushCFunction(L_ShouldInstallOS);
|
luaState.Thread.PushCFunction(L_InstallOS);
|
||||||
luaState.Thread.SetGlobal("shouldInstallOS");
|
luaState.Thread.SetGlobal("installOS");
|
||||||
|
|
||||||
luaState.Thread.PushCFunction(L_FlagInstalled);
|
|
||||||
luaState.Thread.SetGlobal("flagInstalled");
|
|
||||||
|
|
||||||
luaState.Thread.PushCFunction(L_Exit);
|
luaState.Thread.PushCFunction(L_Exit);
|
||||||
luaState.Thread.SetGlobal("exit");
|
luaState.Thread.SetGlobal("exit");
|
||||||
|
|
||||||
var status = luaState.Thread.LoadFile("Assets/bios.lua");
|
var status = luaState.Thread.LoadFile("Assets/Lua/bios.lua");
|
||||||
if (status != LuaStatus.OK)
|
if (status != LuaStatus.OK)
|
||||||
{
|
{
|
||||||
throw new LuaException(luaState.Thread.ToString(-1));
|
throw new LuaException(luaState.Thread.ToString(-1));
|
||||||
|
@ -132,8 +131,6 @@ internal class RuntimeManager : IComponent
|
||||||
|
|
||||||
private void InitOS()
|
private void InitOS()
|
||||||
{
|
{
|
||||||
_game.Discord.SetPresence("On CapyOS");
|
|
||||||
|
|
||||||
luaState = new LuaState();
|
luaState = new LuaState();
|
||||||
_game.LuaRuntime = luaState;
|
_game.LuaRuntime = luaState;
|
||||||
luaState.Init();
|
luaState.Init();
|
||||||
|
@ -148,6 +145,11 @@ internal class RuntimeManager : IComponent
|
||||||
|
|
||||||
emitter.Register();
|
emitter.Register();
|
||||||
|
|
||||||
|
if (!File.Exists(Path.Combine(FileSystem.DataPath, "init.lua")))
|
||||||
|
{
|
||||||
|
throw new LuaException("Operating System not found\nMissing init.lua");
|
||||||
|
}
|
||||||
|
|
||||||
var initContent = File.ReadAllText(Path.Combine(FileSystem.DataPath, "init.lua"));
|
var initContent = File.ReadAllText(Path.Combine(FileSystem.DataPath, "init.lua"));
|
||||||
var status = luaState.Thread.LoadString(initContent, "=init.lua");
|
var status = luaState.Thread.LoadString(initContent, "=init.lua");
|
||||||
if (status != LuaStatus.OK)
|
if (status != LuaStatus.OK)
|
||||||
|
@ -173,6 +175,16 @@ internal class RuntimeManager : IComponent
|
||||||
_game.Exit();
|
_game.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void InstallOS(bool force = false)
|
||||||
|
{
|
||||||
|
var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed");
|
||||||
|
if (!File.Exists(installedFilePath) || force)
|
||||||
|
{
|
||||||
|
FileSystem.CopyDirectory("Assets/Lua/CapyOS", FileSystem.DataPath, true, true);
|
||||||
|
File.Create(installedFilePath).Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static int L_OpenDataFolder(IntPtr state)
|
private static int L_OpenDataFolder(IntPtr state)
|
||||||
{
|
{
|
||||||
var path = FileSystem.DataPath;
|
var path = FileSystem.DataPath;
|
||||||
|
@ -189,22 +201,9 @@ internal class RuntimeManager : IComponent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int L_ShouldInstallOS(IntPtr state)
|
private static int L_InstallOS(IntPtr state)
|
||||||
{
|
{
|
||||||
var L = Lua.FromIntPtr(state);
|
InstallOS(true);
|
||||||
var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed");
|
|
||||||
|
|
||||||
L.PushBoolean(!File.Exists(installedFilePath));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int L_FlagInstalled(IntPtr state)
|
|
||||||
{
|
|
||||||
var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed");
|
|
||||||
if (!File.Exists(installedFilePath))
|
|
||||||
File.Create(installedFilePath).Dispose();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue