mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-15 12:37:13 +00:00
Cherry pick several changes back from 1.19.3
The main purpose of this is to backport the improved parse/runtime errors to older versions. I think they're sufficiently useful that we should try to make it as widely available as possible. We've been running them for a week now on SC3 and the released version and not seen any issues, so I think it's probably stable enough. This is a pretty lazy commit: I ended up copying the whole ROM over and then picking up a few other related changes along the way. - Trim spaces from file paths (b8fce1eecc) - Correctly format 12AM/PM with %I (9f48395596) - Fix http.request and htpt.websocketAsync not handling a few failure edge-cases correctly (3b42f22a4f). - Move the internal modules into the main package path, hidden under cc.internal (34a31abd9c). - Gather code coverage in Java instead of Lua (28a55349a9). - Make error messages in edit more obvious (8cfbfe7ceb). - Make mcfly's test methods global. This means we don't need to pass stub everywhere (7335a892b5). - Improve runtime and parse errors. This comes from numerous commits, but chieflya12b405acf, and5502412181. - Hide the internal redirect methods in multishell (33b6f38339). Note this does /not/ include the shebang changes (sorry Emma!). I've tried to avoid adding any user-controllable features, mostly because I don't know how to handle the versioning otherwise :).
This commit is contained in:
@@ -3,16 +3,15 @@
|
||||
-- Ideally we'd use require, but that is part of the shell, and so is not
|
||||
-- available to the BIOS or any APIs. All APIs load this using dofile, but that
|
||||
-- has not been defined at this point.
|
||||
local expect, field
|
||||
local expect
|
||||
|
||||
do
|
||||
local h = fs.open("rom/modules/main/cc/expect.lua", "r")
|
||||
local f, err = loadstring(h.readAll(), "@expect.lua")
|
||||
local f, err = loadstring(h.readAll(), "@/rom/modules/main/cc/expect.lua")
|
||||
h.close()
|
||||
|
||||
if not f then error(err) end
|
||||
local res = f()
|
||||
expect, field = res.expect, res.field
|
||||
expect = f().expect
|
||||
end
|
||||
|
||||
if _VERSION == "Lua 5.1" then
|
||||
@@ -468,7 +467,7 @@ function loadfile(filename, mode, env)
|
||||
local file = fs.open(filename, "r")
|
||||
if not file then return nil, "File not found" end
|
||||
|
||||
local func, err = load(file.readAll(), "@" .. fs.getName(filename), mode, env)
|
||||
local func, err = load(file.readAll(), "@/" .. fs.combine(filename), mode, env)
|
||||
file.close()
|
||||
return func, err
|
||||
end
|
||||
@@ -584,257 +583,28 @@ function os.reboot()
|
||||
end
|
||||
end
|
||||
|
||||
-- Install the lua part of the HTTP api (if enabled)
|
||||
if http then
|
||||
local nativeHTTPRequest = http.request
|
||||
local bAPIError = false
|
||||
|
||||
local methods = {
|
||||
GET = true, POST = true, HEAD = true,
|
||||
OPTIONS = true, PUT = true, DELETE = true,
|
||||
PATCH = true, TRACE = true,
|
||||
}
|
||||
local function load_apis(dir)
|
||||
if not fs.isDir(dir) then return end
|
||||
|
||||
local function checkKey(options, key, ty, opt)
|
||||
local value = options[key]
|
||||
local valueTy = type(value)
|
||||
|
||||
if (value ~= nil or not opt) and valueTy ~= ty then
|
||||
error(("bad field '%s' (expected %s, got %s"):format(key, ty, valueTy), 4)
|
||||
end
|
||||
end
|
||||
|
||||
local function checkOptions(options, body)
|
||||
checkKey(options, "url", "string")
|
||||
if body == false then
|
||||
checkKey(options, "body", "nil")
|
||||
else
|
||||
checkKey(options, "body", "string", not body)
|
||||
end
|
||||
checkKey(options, "headers", "table", true)
|
||||
checkKey(options, "method", "string", true)
|
||||
checkKey(options, "redirect", "boolean", true)
|
||||
|
||||
if options.method and not methods[options.method] then
|
||||
error("Unsupported HTTP method", 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function wrapRequest(_url, ...)
|
||||
local ok, err = nativeHTTPRequest(...)
|
||||
if ok then
|
||||
while true do
|
||||
local event, param1, param2, param3 = os.pullEvent()
|
||||
if event == "http_success" and param1 == _url then
|
||||
return param2
|
||||
elseif event == "http_failure" and param1 == _url then
|
||||
return nil, param2, param3
|
||||
for _, file in ipairs(fs.list(dir)) do
|
||||
if file:sub(1, 1) ~= "." then
|
||||
local path = fs.combine(dir, file)
|
||||
if not fs.isDir(path) then
|
||||
if not os.loadAPI(path) then
|
||||
bAPIError = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil, err
|
||||
end
|
||||
|
||||
http.get = function(_url, _headers, _binary)
|
||||
if type(_url) == "table" then
|
||||
checkOptions(_url, false)
|
||||
return wrapRequest(_url.url, _url)
|
||||
end
|
||||
|
||||
expect(1, _url, "string")
|
||||
expect(2, _headers, "table", "nil")
|
||||
expect(3, _binary, "boolean", "nil")
|
||||
return wrapRequest(_url, _url, nil, _headers, _binary)
|
||||
end
|
||||
|
||||
http.post = function(_url, _post, _headers, _binary)
|
||||
if type(_url) == "table" then
|
||||
checkOptions(_url, true)
|
||||
return wrapRequest(_url.url, _url)
|
||||
end
|
||||
|
||||
expect(1, _url, "string")
|
||||
expect(2, _post, "string")
|
||||
expect(3, _headers, "table", "nil")
|
||||
expect(4, _binary, "boolean", "nil")
|
||||
return wrapRequest(_url, _url, _post, _headers, _binary)
|
||||
end
|
||||
|
||||
http.request = function(_url, _post, _headers, _binary)
|
||||
local url
|
||||
if type(_url) == "table" then
|
||||
checkOptions(_url)
|
||||
url = _url.url
|
||||
else
|
||||
expect(1, _url, "string")
|
||||
expect(2, _post, "string", "nil")
|
||||
expect(3, _headers, "table", "nil")
|
||||
expect(4, _binary, "boolean", "nil")
|
||||
url = _url.url
|
||||
end
|
||||
|
||||
local ok, err = nativeHTTPRequest(_url, _post, _headers, _binary)
|
||||
if not ok then
|
||||
os.queueEvent("http_failure", url, err)
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
|
||||
local nativeCheckURL = http.checkURL
|
||||
http.checkURLAsync = nativeCheckURL
|
||||
http.checkURL = function(_url)
|
||||
expect(1, _url, "string")
|
||||
local ok, err = nativeCheckURL(_url)
|
||||
if not ok then return ok, err end
|
||||
|
||||
while true do
|
||||
local _, url, ok, err = os.pullEvent("http_check")
|
||||
if url == _url then return ok, err end
|
||||
end
|
||||
end
|
||||
|
||||
local nativeWebsocket = http.websocket
|
||||
http.websocketAsync = nativeWebsocket
|
||||
http.websocket = function(_url, _headers)
|
||||
expect(1, _url, "string")
|
||||
expect(2, _headers, "table", "nil")
|
||||
|
||||
local ok, err = nativeWebsocket(_url, _headers)
|
||||
if not ok then return ok, err end
|
||||
|
||||
while true do
|
||||
local event, url, param = os.pullEvent( )
|
||||
if event == "websocket_success" and url == _url then
|
||||
return param
|
||||
elseif event == "websocket_failure" and url == _url then
|
||||
return false, param
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Install the lua part of the FS api
|
||||
local tEmpty = {}
|
||||
function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs)
|
||||
expect(1, sPath, "string")
|
||||
expect(2, sLocation, "string")
|
||||
local bIncludeHidden = nil
|
||||
if type(bIncludeFiles) == "table" then
|
||||
bIncludeDirs = field(bIncludeFiles, "include_dirs", "boolean", "nil")
|
||||
bIncludeHidden = field(bIncludeFiles, "include_hidden", "boolean", "nil")
|
||||
bIncludeFiles = field(bIncludeFiles, "include_files", "boolean", "nil")
|
||||
else
|
||||
expect(3, bIncludeFiles, "boolean", "nil")
|
||||
expect(4, bIncludeDirs, "boolean", "nil")
|
||||
end
|
||||
|
||||
bIncludeHidden = bIncludeHidden ~= false
|
||||
bIncludeFiles = bIncludeFiles ~= false
|
||||
bIncludeDirs = bIncludeDirs ~= false
|
||||
local sDir = sLocation
|
||||
local nStart = 1
|
||||
local nSlash = string.find(sPath, "[/\\]", nStart)
|
||||
if nSlash == 1 then
|
||||
sDir = ""
|
||||
nStart = 2
|
||||
end
|
||||
local sName
|
||||
while not sName do
|
||||
local nSlash = string.find(sPath, "[/\\]", nStart)
|
||||
if nSlash then
|
||||
local sPart = string.sub(sPath, nStart, nSlash - 1)
|
||||
sDir = fs.combine(sDir, sPart)
|
||||
nStart = nSlash + 1
|
||||
else
|
||||
sName = string.sub(sPath, nStart)
|
||||
end
|
||||
end
|
||||
|
||||
if fs.isDir(sDir) then
|
||||
local tResults = {}
|
||||
if bIncludeDirs and sPath == "" then
|
||||
table.insert(tResults, ".")
|
||||
end
|
||||
if sDir ~= "" then
|
||||
if sPath == "" then
|
||||
table.insert(tResults, bIncludeDirs and ".." or "../")
|
||||
elseif sPath == "." then
|
||||
table.insert(tResults, bIncludeDirs and "." or "./")
|
||||
end
|
||||
end
|
||||
local tFiles = fs.list(sDir)
|
||||
for n = 1, #tFiles do
|
||||
local sFile = tFiles[n]
|
||||
if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName and (
|
||||
bIncludeHidden or sFile:sub(1, 1) ~= "." or sName:sub(1, 1) == "."
|
||||
) then
|
||||
local bIsDir = fs.isDir(fs.combine(sDir, sFile))
|
||||
local sResult = string.sub(sFile, #sName + 1)
|
||||
if bIsDir then
|
||||
table.insert(tResults, sResult .. "/")
|
||||
if bIncludeDirs and #sResult > 0 then
|
||||
table.insert(tResults, sResult)
|
||||
end
|
||||
else
|
||||
if bIncludeFiles and #sResult > 0 then
|
||||
table.insert(tResults, sResult)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return tResults
|
||||
end
|
||||
return tEmpty
|
||||
end
|
||||
|
||||
function fs.isDriveRoot(sPath)
|
||||
expect(1, sPath, "string")
|
||||
-- Force the root directory to be a mount.
|
||||
return fs.getDir(sPath) == ".." or fs.getDrive(sPath) ~= fs.getDrive(fs.getDir(sPath))
|
||||
end
|
||||
|
||||
-- Load APIs
|
||||
local bAPIError = false
|
||||
local tApis = fs.list("rom/apis")
|
||||
for _, sFile in ipairs(tApis) do
|
||||
if string.sub(sFile, 1, 1) ~= "." then
|
||||
local sPath = fs.combine("rom/apis", sFile)
|
||||
if not fs.isDir(sPath) then
|
||||
if not os.loadAPI(sPath) then
|
||||
bAPIError = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if turtle and fs.isDir("rom/apis/turtle") then
|
||||
-- Load turtle APIs
|
||||
local tApis = fs.list("rom/apis/turtle")
|
||||
for _, sFile in ipairs(tApis) do
|
||||
if string.sub(sFile, 1, 1) ~= "." then
|
||||
local sPath = fs.combine("rom/apis/turtle", sFile)
|
||||
if not fs.isDir(sPath) then
|
||||
if not os.loadAPI(sPath) then
|
||||
bAPIError = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if pocket and fs.isDir("rom/apis/pocket") then
|
||||
-- Load pocket APIs
|
||||
local tApis = fs.list("rom/apis/pocket")
|
||||
for _, sFile in ipairs(tApis) do
|
||||
if string.sub(sFile, 1, 1) ~= "." then
|
||||
local sPath = fs.combine("rom/apis/pocket", sFile)
|
||||
if not fs.isDir(sPath) then
|
||||
if not os.loadAPI(sPath) then
|
||||
bAPIError = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
load_apis("rom/apis")
|
||||
if http then load_apis("rom/apis/http") end
|
||||
if turtle then load_apis("rom/apis/turtle") end
|
||||
if pocket then load_apis("rom/apis/pocket") end
|
||||
|
||||
if commands and fs.isDir("rom/apis/command") then
|
||||
-- Load command APIs
|
||||
@@ -930,7 +700,7 @@ settings.define("motd.path", {
|
||||
|
||||
settings.define("lua.warn_against_use_of_local", {
|
||||
default = true,
|
||||
description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessable on the next input.]],
|
||||
description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessible on the next input.]],
|
||||
type = "boolean",
|
||||
})
|
||||
settings.define("lua.function_args", {
|
||||
|
||||
Reference in New Issue
Block a user