1
0
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 chiefly a12b405acf, and
   5502412181.

 - 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:
Jonathan Coates
2023-02-14 09:45:02 +00:00
parent 68f6fa9343
commit 9b3cadf57c
95 changed files with 5447 additions and 942 deletions

View File

@@ -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", {